vcr 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -23,6 +23,8 @@ pkg
23
23
  ## PROJECT::SPECIFIC
24
24
  features/fixtures/vcr_cassettes/**/temp/
25
25
  *.rbc
26
+ .rbc
27
+ .rbx
26
28
  .bundle
27
29
  tmp
28
30
  rerun.txt
data/.travis.yml CHANGED
@@ -11,17 +11,13 @@ rvm:
11
11
  - jruby-19mode
12
12
  - rbx-18mode
13
13
  - rbx-19mode
14
- - ruby-head
15
14
  branches:
16
15
  only:
17
16
  - master
18
17
  - 1-x-stable
19
18
  - travis-testing
20
- - 2-0-stable
21
19
  matrix:
22
20
  allow_failures:
23
21
  - rvm: jruby-19mode
24
- - rvm: rbx-18mode
25
22
  - rvm: rbx-19mode
26
- - rvm: ruby-head
27
23
 
data/CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
1
  ## In git
2
2
 
3
- [Full Changelog](http://github.com/myronmarston/vcr/compare/v2.0.0...2-0-stable)
3
+ [Full Changelog](http://github.com/myronmarston/vcr/compare/v2.0.1...master)
4
+
5
+ * Add new `:use_scenario_name` option to the cucumber tags API. This
6
+ allows you to use a generic tag (such as `@vcr`) and have the
7
+ cassettes named based on the feature and scenario rather than based on
8
+ the tag. Thanks to [Omer Rauchwerger](https://github.com/rauchy) for
9
+ the implementation and [Chad Jolly](https://github.com/cjolly) for the
10
+ initial idea and feedback.
11
+ * Add new `:decode_compressed_response` cassette option. When set to
12
+ true, VCR will decompress a gzipped or deflated response before
13
+ recording the cassette, in order to make it more human readable.
14
+ Thanks to [Mislav Marohnić](https://github.com/mislav) for the
15
+ idea and implementation.
16
+
17
+ ## 2.0.1 (March 30, 2012)
18
+
19
+ [Full Changelog](http://github.com/myronmarston/vcr/compare/v2.0.0...v2.0.1)
4
20
 
5
21
  * Fix encoding logic to not attempt to encode the request or response
6
22
  body on deserialization if there is no encoding specified. This should
data/README.md CHANGED
@@ -112,6 +112,7 @@ Note that as of VCR 2, 1.8.6 and 1.9.1 are not supported.
112
112
  and create a topic branch for every separate change you make.
113
113
  * See the [Contributing](https://github.com/myronmarston/vcr/blob/master/CONTRIBUTING.md)
114
114
  guide for instructions on running the specs and features.
115
+ * Code quality metrics are checked by [Code Climate](https://codeclimate.com/github/myronmarston/vcr).
115
116
  * Documentation is generated with [YARD](http://yardoc.org/) ([cheat sheet](http://cheat.errtheblog.com/s/yard/)).
116
117
  To generate while developing:
117
118
 
@@ -119,8 +120,6 @@ Note that as of VCR 2, 1.8.6 and 1.9.1 are not supported.
119
120
  yard server --reload
120
121
  ```
121
122
 
122
- If you find VCR useful, please recommend me on [working with rails](http://workingwithrails.com/person/16590-myron-marston).
123
-
124
123
  ## Thanks
125
124
 
126
125
  * [Aslak Hellesøy](http://github.com/aslakhellesoy) for [Cucumber](http://github.com/aslakhellesoy/cucumber).
@@ -142,14 +141,18 @@ Thanks also to the following people who have contributed patches or helpful sugg
142
141
  * [Ben Hutton](http://github.com/benhutton)
143
142
  * [Bradley Isotope](https://github.com/bradleyisotope)
144
143
  * [Carlos Kirkconnell](https://github.com/kirkconnell)
144
+ * [Chad Jolly](https://github.com/cjolly)
145
145
  * [Eric Allam](http://github.com/rubymaverick)
146
+ * [Ezekiel Templin](https://github.com/ezkl)
146
147
  * [Flaviu Simihaian](https://github.com/closedbracket)
147
148
  * [Jeff Pollard](https://github.com/Fluxx)
148
149
  * [Justin Smestad](https://github.com/jsmestad)
149
150
  * [Karl Baum](https://github.com/kbaum)
150
151
  * [Michael Lavrisha](https://github.com/vrish88)
152
+ * [Mislav Marohnić](https://github.com/mislav)
151
153
  * [Nathaniel Bibler](https://github.com/nbibler)
152
154
  * [Oliver Searle-Barnes](https://github.com/opsb)
155
+ * [Omer Rauchwerger](https://github.com/rauchy)
153
156
  * [Paco Guzmán](https://github.com/pacoguzman)
154
157
  * [Ryan Bates](https://github.com/ryanb)
155
158
  * [Sathya Sekaran](https://github.com/sfsekaran)
data/features/.nav CHANGED
@@ -12,6 +12,7 @@
12
12
  - automatic_re_recording.feature
13
13
  - exclusive.feature
14
14
  - update_content_length_header.feature
15
+ - decompress.feature
15
16
  - record_modes:
16
17
  - once.feature
17
18
  - new_episodes.feature
@@ -0,0 +1,70 @@
1
+ Feature: Decode compressed response
2
+
3
+ When the `:decode_compressed_response` option is set to a truthy value, VCR
4
+ will decompress "gzip" and "deflate" response bodies before recording. This
5
+ ensures that these interactions become readable and editable after being
6
+ serialized.
7
+
8
+ This option should be avoided if the actual decompression of response bodies
9
+ is part of the functionality of the library or app being tested.
10
+
11
+ Background:
12
+ Given a file named "decompress.rb" with:
13
+ """ruby
14
+ require 'zlib'
15
+ require 'stringio'
16
+
17
+ start_sinatra_app(:port => 7777) do
18
+ get('/') {
19
+ content = 'The quick brown fox jumps over the lazy dog'
20
+ io = StringIO.new
21
+
22
+ writer = Zlib::GzipWriter.new(io)
23
+ writer << content
24
+ writer.close
25
+
26
+ headers['Content-Encoding'] = 'gzip'
27
+ io.string
28
+ }
29
+ end
30
+
31
+ require 'vcr'
32
+
33
+ VCR.configure do |c|
34
+ c.cassette_library_dir = 'cassettes'
35
+ c.hook_into :fakeweb
36
+ c.default_cassette_options = { :serialize_with => :syck }
37
+ end
38
+ """
39
+
40
+ Scenario: The option is not set by default
41
+ When I append to file "decompress.rb":
42
+ """ruby
43
+ VCR.use_cassette(:decompress) do
44
+ Net::HTTP.get_response('localhost', '/', 7777)
45
+ end
46
+ """
47
+ And I run `ruby decompress.rb`
48
+ Then the file "cassettes/decompress.yml" should contain a YAML fragment like:
49
+ """
50
+ content-encoding:
51
+ - gzip
52
+ """
53
+
54
+ Scenario: The option is enabled
55
+ When I append to file "decompress.rb":
56
+ """ruby
57
+ VCR.use_cassette(:decompress, :decode_compressed_response => true) do
58
+ Net::HTTP.get_response('localhost', '/', 7777)
59
+ end
60
+ """
61
+ And I run `ruby decompress.rb`
62
+ Then the file "cassettes/decompress.yml" should contain a YAML fragment like:
63
+ """
64
+ content-length:
65
+ - '43'
66
+ """
67
+ And the file "cassettes/decompress.yml" should contain:
68
+ """
69
+ string: The quick brown fox jumps over the lazy dog
70
+ """
@@ -96,6 +96,10 @@ When /^I modify the file "([^"]*)" to replace "([^"]*)" with "([^"]*)"$/ do |fil
96
96
  modify_file(file_name, orig_text, new_text)
97
97
  end
98
98
 
99
+ When /^I append to file "([^"]*)":$/ do |file_name, content|
100
+ append_to_file(file_name, "\n" + content)
101
+ end
102
+
99
103
  When /^I set the "([^"]*)" environment variable to "([^"]*)"$/ do |var, value|
100
104
  set_env(var, value)
101
105
  end
@@ -149,7 +153,8 @@ Then /^the file "([^"]*)" should contain a YAML fragment like:$/ do |file_name,
149
153
 
150
154
  # Normalize by removing leading and trailing whitespace...
151
155
  file_content = file_content.split("\n").map do |line|
152
- line.strip
156
+ # Different versions of psych use single vs. double quotes
157
+ line.strip.gsub('"', "'")
153
158
  end.join("\n")
154
159
 
155
160
  file_content.should include(fragment)
@@ -1,8 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
3
  Bundler.setup
4
- require 'limited_red/plugins/cucumber'
5
4
 
5
+ require 'limited_red/plugins/cucumber'
6
6
  require 'ruby-debug' if !defined?(RUBY_ENGINE) && RUBY_VERSION != '1.9.3' && !ENV['CI']
7
7
 
8
8
  require 'aruba/cucumber'
@@ -15,13 +15,18 @@ Feature: Usage with Cucumber
15
15
 
16
16
  t.tag '@tag3', :cassette => :options
17
17
  t.tags '@tag4, '@tag5', :cassette => :options
18
+ t.tag '@vcr', :use_scenario_name => true
18
19
  end
19
20
  ```
20
21
 
21
22
  VCR will use a cassette named "cucumber_tags/<tag_name>" for scenarios
22
- with each of these tags. The configured `default_cassette_options` will
23
- be used, or you can override specific options by passing a hash as the
24
- last argument to `#tag` or `#tags`.
23
+ with each of these tags (Unless the :use_scenario_name option is provided. See below).
24
+ The configured `default_cassette_options` will be used, or you can override specific
25
+ options by passing a hash as the last argument to `#tag` or `#tags`.
26
+
27
+ You can also have VCR name your cassettes automatically according to the feature
28
+ and scenario name by providing :use_scenario_name => true to '#tag' or '#tags'.
29
+ In this case, the cassette will be named "<feature_name>/<scenario_name>".
25
30
 
26
31
  @exclude-jruby
27
32
  Scenario: Record HTTP interactions in a scenario by tagging it
@@ -47,6 +52,7 @@ Feature: Usage with Cucumber
47
52
  VCR.cucumber_tags do |t|
48
53
  t.tag '@localhost_request' # uses default record mode since no options are given
49
54
  t.tags '@disallowed_1', '@disallowed_2', :record => :none
55
+ t.tag '@vcr', :use_scenario_name => true
50
56
  end
51
57
  """
52
58
  And a file named "features/step_definitions/steps.rb" with:
@@ -78,6 +84,11 @@ Feature: Usage with Cucumber
78
84
  When a request is made to "http://localhost:7777/localhost_request_2"
79
85
  Then the response should be "Hello localhost_request_2"
80
86
 
87
+ @vcr
88
+ Scenario: tagged scenario
89
+ When a request is made to "http://localhost:7777/localhost_request_1"
90
+ Then the response should be "Hello localhost_request_1"
91
+
81
92
  @disallowed_1
82
93
  Scenario: tagged scenario
83
94
  When a request is made to "http://localhost:7777/allowed" within a cassette named "allowed"
@@ -90,7 +101,7 @@ Feature: Usage with Cucumber
90
101
  """
91
102
  And the directory "features/cassettes" does not exist
92
103
  When I run `cucumber WITH_SERVER=true features/vcr_example.feature`
93
- Then it should fail with "3 scenarios (2 failed, 1 passed)"
104
+ Then it should fail with "4 scenarios (2 failed, 2 passed)"
94
105
  And the output should contain each of the following:
95
106
  | An HTTP request has been made that VCR does not know how to handle: |
96
107
  | GET http://localhost:7777/disallowed_1 |
@@ -100,11 +111,12 @@ Feature: Usage with Cucumber
100
111
  And the file "features/cassettes/cucumber_tags/localhost_request.yml" should contain "Hello localhost_request_2"
101
112
  And the file "features/cassettes/nested_cassette.yml" should contain "Hello nested_cassette"
102
113
  And the file "features/cassettes/allowed.yml" should contain "Hello allowed"
114
+ And the file "features/cassettes/VCR_example/tagged_scenario.yml" should contain "Hello localhost_request_1"
103
115
 
104
116
  # Run again without the server; we'll get the same responses because VCR
105
117
  # will replay the recorded responses.
106
118
  When I run `cucumber features/vcr_example.feature`
107
- Then it should fail with "3 scenarios (2 failed, 1 passed)"
119
+ Then it should fail with "4 scenarios (2 failed, 2 passed)"
108
120
  And the output should contain each of the following:
109
121
  | An HTTP request has been made that VCR does not know how to handle: |
110
122
  | GET http://localhost:7777/disallowed_1 |
@@ -114,4 +126,4 @@ Feature: Usage with Cucumber
114
126
  And the file "features/cassettes/cucumber_tags/localhost_request.yml" should contain "Hello localhost_request_2"
115
127
  And the file "features/cassettes/nested_cassette.yml" should contain "Hello nested_cassette"
116
128
  And the file "features/cassettes/allowed.yml" should contain "Hello allowed"
117
-
129
+ And the file "features/cassettes/VCR_example/tagged_scenario.yml" should contain "Hello localhost_request_1"
data/lib/vcr.rb CHANGED
@@ -74,6 +74,9 @@ module VCR
74
74
  # @option options :update_content_length_header [Boolean] Whether or
75
75
  # not to overwrite the Content-Length header of the responses to
76
76
  # match the length of the response body. Defaults to false.
77
+ # @option options :decode_compressed_response [Boolean] Whether or
78
+ # not to decode compressed responses before recording the cassette.
79
+ # This makes the cassette more human readable. Defaults to false.
77
80
  # @option options :allow_playback_repeats [Boolean] Whether or not to
78
81
  # allow a single HTTP interaction to be played back multiple times.
79
82
  # Defaults to false.
@@ -144,6 +147,12 @@ module VCR
144
147
  # @see #insert_cassette
145
148
  # @see #eject_cassette
146
149
  def use_cassette(name, options = {}, &block)
150
+ unless block
151
+ raise ArgumentError, "`VCR.use_cassette` requires a block. " +
152
+ "If you cannot wrap your code in a block, use " +
153
+ "`VCR.insert_cassette` / `VCR.eject_cassette` instead."
154
+ end
155
+
147
156
  cassette = insert_cassette(name, options)
148
157
 
149
158
  begin
data/lib/vcr/cassette.rb CHANGED
@@ -50,7 +50,7 @@ module VCR
50
50
  invalid_options = options.keys - [
51
51
  :record, :erb, :match_requests_on, :re_record_interval, :tag, :tags,
52
52
  :update_content_length_header, :allow_playback_repeats, :exclusive,
53
- :serialize_with, :preserve_exact_body_bytes
53
+ :serialize_with, :preserve_exact_body_bytes, :decode_compressed_response
54
54
  ]
55
55
 
56
56
  if invalid_options.size > 0
@@ -65,6 +65,7 @@ module VCR
65
65
  @tags = Array(options.fetch(:tags) { options[:tag] })
66
66
  @tags << :update_content_length_header if options[:update_content_length_header]
67
67
  @tags << :preserve_exact_body_bytes if options[:preserve_exact_body_bytes]
68
+ @tags << :decode_compressed_response if options[:decode_compressed_response]
68
69
  @allow_playback_repeats = options[:allow_playback_repeats]
69
70
  @exclusive = options[:exclusive]
70
71
  @serializer = VCR.cassette_serializers[options[:serialize_with]]
@@ -442,6 +442,10 @@ module VCR
442
442
  interaction.response.update_content_length_header
443
443
  end
444
444
 
445
+ before_record(:decode_compressed_response) do |interaction|
446
+ interaction.response.decompress if interaction.response.compressed?
447
+ end
448
+
445
449
  preserve_exact_body_bytes do |http_message, cassette|
446
450
  cassette && cassette.tags.include?(:preserve_exact_body_bytes)
447
451
  end
data/lib/vcr/errors.rb CHANGED
@@ -40,6 +40,11 @@ module VCR
40
40
  # @see VCR::Configuration#around_http_request
41
41
  class NotSupportedError < Error; end
42
42
 
43
+ # Error raised when you ask VCR to decode a compressed response
44
+ # body but the content encoding isn't one of the known ones.
45
+ # @see VCR::Response#decompress
46
+ class UnknownContentEncodingError < Error; end
47
+
43
48
  # Error raised when an HTTP request is made that VCR is unable to handle.
44
49
  # @note VCR will raise this to force you to do something about the
45
50
  # HTTP request. The idea is that you want to handle _every_ HTTP
data/lib/vcr/structs.rb CHANGED
@@ -100,6 +100,7 @@ module VCR
100
100
 
101
101
  def normalize_headers
102
102
  new_headers = {}
103
+ @normalized_header_keys = Hash.new {|h,k| k }
103
104
 
104
105
  headers.each do |k, v|
105
106
  val_array = case v
@@ -109,11 +110,36 @@ module VCR
109
110
  end
110
111
 
111
112
  new_headers[k] = convert_to_raw_strings(val_array)
113
+ @normalized_header_keys[k.downcase] = k
112
114
  end if headers
113
115
 
114
116
  self.headers = new_headers
115
117
  end
116
118
 
119
+ def header_key(key)
120
+ key = @normalized_header_keys[key.downcase]
121
+ key if headers.has_key? key
122
+ end
123
+
124
+ def get_header(key)
125
+ key = header_key(key)
126
+ headers[key] if key
127
+ end
128
+
129
+ def edit_header(key, value = nil)
130
+ if key = header_key(key)
131
+ value ||= yield headers[key]
132
+ headers[key] = Array(value)
133
+ end
134
+ end
135
+
136
+ def delete_header(key)
137
+ if key = header_key(key)
138
+ @normalized_header_keys.delete key.downcase
139
+ headers.delete key
140
+ end
141
+ end
142
+
117
143
  def convert_to_raw_strings(array)
118
144
  # Ensure the values are raw strings.
119
145
  # Apparently for Paperclip uploads to S3, headers
@@ -268,15 +294,6 @@ module VCR
268
294
  undef method
269
295
  end
270
296
 
271
- # Transforms the request into a fiber aware one by extending
272
- # the {FiberAware} module onto the instance. Necessary for the
273
- # {VCR::Configuration#around_http_request} hook.
274
- #
275
- # @return [Request] the request instance
276
- def fiber_aware
277
- extend FiberAware
278
- end
279
-
280
297
  private
281
298
 
282
299
  def without_standard_port(uri)
@@ -326,9 +343,65 @@ module VCR
326
343
  # Updates the Content-Length response header so that it is
327
344
  # accurate for the response body.
328
345
  def update_content_length_header
329
- value = body ? body.bytesize.to_s : '0'
330
- key = %w[ Content-Length content-length ].find { |k| headers.has_key?(k) }
331
- headers[key] = [value] if key
346
+ edit_header('Content-Length') { body ? body.bytesize.to_s : '0' }
347
+ end
348
+
349
+ # The type of encoding.
350
+ #
351
+ # @return [String] encoding type
352
+ def content_encoding
353
+ enc = get_header('Content-Encoding') and enc.first
354
+ end
355
+
356
+ # Checks if the type of encoding is one of "gzip" or "deflate".
357
+ def compressed?
358
+ %w[ gzip deflate ].include? content_encoding
359
+ end
360
+
361
+ # Decodes the compressed body and deletes evidence that it was ever compressed.
362
+ #
363
+ # @return self
364
+ # @raise [VCR::Errors::UnknownContentEncodingError] if the content encoding
365
+ # is not a known encoding.
366
+ def decompress
367
+ self.class.decompress(body, content_encoding) { |new_body|
368
+ self.body = new_body
369
+ update_content_length_header
370
+ delete_header('Content-Encoding')
371
+ }
372
+ return self
373
+ end
374
+
375
+ begin
376
+ require 'zlib'
377
+ require 'stringio'
378
+ HAVE_ZLIB = true
379
+ rescue LoadError
380
+ HAVE_ZLIB = false
381
+ end
382
+
383
+ # Decode string compressed with gzip or deflate
384
+ #
385
+ # @raise [VCR::Errors::UnknownContentEncodingError] if the content encoding
386
+ # is not a known encoding.
387
+ def self.decompress(body, type)
388
+ unless HAVE_ZLIB
389
+ warn "VCR: cannot decompress response; Zlib not available"
390
+ return
391
+ end
392
+
393
+ case type
394
+ when 'gzip'
395
+ args = [StringIO.new(body)]
396
+ args << { :encoding => 'ASCII-8BIT' } if ''.respond_to?(:encoding)
397
+ yield Zlib::GzipReader.new(*args).read
398
+ when 'deflate'
399
+ yield Zlib::Inflate.inflate(body)
400
+ when 'identity', NilClass
401
+ return
402
+ else
403
+ raise Errors::UnknownContentEncodingError, "unknown content encoding: #{type}"
404
+ end
332
405
  end
333
406
  end
334
407
 
@@ -24,7 +24,7 @@ module VCR
24
24
  # will cause a VCR cassette to be used for scenarios with matching tags.
25
25
  #
26
26
  # @param [Array<String>] tag_names the cucumber scenario tags
27
- # @param [(optional) Hash] options the cassette options
27
+ # @param [(optional) Hash] options the cassette options. Specify :use_scenario_name => true to automatically name the cassette according to the scenario name.
28
28
  def tags(*tag_names)
29
29
  options = tag_names.last.is_a?(::Hash) ? tag_names.pop : {}
30
30
  tag_names.each do |tag_name|
@@ -35,7 +35,9 @@ module VCR
35
35
  # cucumber has a bug: background steps do not run
36
36
  # within an around hook.
37
37
  # https://gist.github.com/652968
38
- @main_object.Before(tag_name) do
38
+ @main_object.Before(tag_name) do |scenario|
39
+ options = options.dup
40
+ cassette_name = "#{scenario.feature.name}/#{scenario.name}" if options.delete(:use_scenario_name)
39
41
  VCR.insert_cassette(cassette_name, options)
40
42
  end
41
43
 
data/lib/vcr/version.rb CHANGED
@@ -10,7 +10,7 @@ module VCR
10
10
  # * `parts` [Array<Integer>] List of the version parts.
11
11
  def version
12
12
  @version ||= begin
13
- string = '2.0.1'
13
+ string = '2.1.0'
14
14
 
15
15
  def string.parts
16
16
  split('.').map { |p| p.to_i }
data/spec/spec_helper.rb CHANGED
@@ -1,20 +1,23 @@
1
1
  require 'rubygems'
2
- require 'simplecov'
3
2
 
4
- SimpleCov.start do
5
- add_filter "/spec"
6
- add_filter "/features"
3
+ if RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == 'ruby'
4
+ require 'simplecov'
7
5
 
8
- # internet_connection mostly contains logic copied from the ruby 1.8.7
9
- # stdlib for which I haven't written tests.
10
- add_filter "internet_connection"
11
- end
6
+ SimpleCov.start do
7
+ add_filter "/spec"
8
+ add_filter "/features"
9
+
10
+ # internet_connection mostly contains logic copied from the ruby 1.8.7
11
+ # stdlib for which I haven't written tests.
12
+ add_filter "internet_connection"
13
+ end
12
14
 
13
- SimpleCov.at_exit do
14
- File.open(File.join(SimpleCov.coverage_path, 'coverage_percent.txt'), 'w') do |f|
15
- f.write SimpleCov.result.covered_percent
15
+ SimpleCov.at_exit do
16
+ File.open(File.join(SimpleCov.coverage_path, 'coverage_percent.txt'), 'w') do |f|
17
+ f.write SimpleCov.result.covered_percent
18
+ end
19
+ SimpleCov.result.format!
16
20
  end
17
- SimpleCov.result.format!
18
21
  end
19
22
 
20
23
  using_git = File.exist?(File.expand_path('../../.git/', __FILE__))
@@ -11,7 +11,6 @@ describe VCR::Middleware::Faraday do
11
11
 
12
12
  context 'when making parallel requests' do
13
13
  include VCRStubHelpers
14
- let(:parallel_manager) { ::Faraday::Adapter::Typhoeus.setup_parallel_manager }
15
14
  let(:connection) { ::Faraday.new { |b| b.adapter :typhoeus } }
16
15
  let(:request_url) { "http://localhost:#{VCR::SinatraApp.port}/" }
17
16
 
@@ -20,7 +19,7 @@ describe VCR::Middleware::Faraday do
20
19
  responses = []
21
20
 
22
21
  VCR.use_cassette("multiple_parallel") do
23
- connection.in_parallel(parallel_manager) do
22
+ connection.in_parallel do
24
23
  responses << connection.get(request_url)
25
24
  responses << connection.get(request_url)
26
25
  end
@@ -36,7 +35,7 @@ describe VCR::Middleware::Faraday do
36
35
 
37
36
  shared_examples_for "exclusive library hook" do
38
37
  def make_request
39
- connection.in_parallel(parallel_manager) { connection.get(request_url) }
38
+ connection.in_parallel { connection.get(request_url) }
40
39
  end
41
40
 
42
41
  it 'makes the faraday middleware exclusively enabled for the duration of the request' do
@@ -78,7 +77,7 @@ describe VCR::Middleware::Faraday do
78
77
  undef make_request
79
78
  def make_request
80
79
  expect {
81
- connection.in_parallel(parallel_manager) { connection.get(request_url) }
80
+ connection.in_parallel { connection.get(request_url) }
82
81
  }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
83
82
  end
84
83
  end
@@ -90,7 +89,7 @@ describe VCR::Middleware::Faraday do
90
89
  undef make_request
91
90
  def make_request(disabled = false)
92
91
  response = nil
93
- connection.in_parallel(parallel_manager) do
92
+ connection.in_parallel do
94
93
  response = connection.get(request_url)
95
94
  end
96
95
  response
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'yaml'
4
4
  require 'vcr/structs'
5
+ require 'vcr/errors'
6
+ require 'zlib'
7
+ require 'stringio'
8
+ require 'uri'
5
9
 
6
10
  shared_examples_for "a header normalizer" do
7
11
  let(:instance) do
@@ -520,6 +524,76 @@ module VCR
520
524
  end
521
525
  end
522
526
  end
527
+
528
+ describe '#decompress' do
529
+ %w[ content-encoding Content-Encoding ].each do |header|
530
+ context "for the #{header} header" do
531
+ define_method :instance do |body, content_encoding|
532
+ headers = { 'content-type' => 'text',
533
+ 'content-length' => body.bytesize.to_s }
534
+ headers[header] = content_encoding if content_encoding
535
+ described_class.new(VCR::ResponseStatus.new, headers, body)
536
+ end
537
+
538
+ let(:content) { 'The quick brown fox jumps over the lazy dog' }
539
+
540
+ it "does nothing when no compression" do
541
+ resp = instance('Hello', nil)
542
+ resp.should_not be_compressed
543
+ expect {
544
+ resp.decompress.should equal(resp)
545
+ }.to_not change { resp.headers['content-length'] }
546
+ end
547
+
548
+ it "does nothing when encoding is 'identity'" do
549
+ resp = instance('Hello', 'identity')
550
+ resp.should_not be_compressed
551
+ expect {
552
+ resp.decompress.should equal(resp)
553
+ }.to_not change { resp.headers['content-length'] }
554
+ end
555
+
556
+ it "raises error for unrecognized encoding" do
557
+ resp = instance('Hello', 'flabbergaster')
558
+ resp.should_not be_compressed
559
+ expect { resp.decompress }.
560
+ to raise_error(Errors::UnknownContentEncodingError, 'unknown content encoding: flabbergaster')
561
+ end
562
+
563
+ it "unzips gzipped response" do
564
+ io = StringIO.new
565
+
566
+ writer = Zlib::GzipWriter.new(io)
567
+ writer << content
568
+ writer.close
569
+
570
+ gzipped = io.string
571
+ resp = instance(gzipped, 'gzip')
572
+ resp.should be_compressed
573
+ expect {
574
+ resp.decompress.should equal(resp)
575
+ resp.should_not be_compressed
576
+ resp.body.should eq(content)
577
+ }.to change { resp.headers['content-length'] }.
578
+ from([gzipped.bytesize.to_s]).
579
+ to([content.bytesize.to_s])
580
+ end
581
+
582
+ it "inflates deflated response" do
583
+ deflated = Zlib::Deflate.deflate(content)
584
+ resp = instance(deflated, 'deflate')
585
+ resp.should be_compressed
586
+ expect {
587
+ resp.decompress.should equal(resp)
588
+ resp.should_not be_compressed
589
+ resp.body.should eq(content)
590
+ }.to change { resp.headers['content-length'] }.
591
+ from([deflated.bytesize.to_s]).
592
+ to([content.bytesize.to_s])
593
+ end
594
+ end
595
+ end
596
+ end
523
597
  end
524
598
  end
525
599
 
@@ -4,6 +4,8 @@ describe VCR::CucumberTags do
4
4
  subject { described_class.new(self) }
5
5
  let(:before_blocks_for_tags) { {} }
6
6
  let(:after_blocks_for_tags) { {} }
7
+ let(:current_scenario) { stub(:name => "My scenario name",
8
+ :feature => stub(:name => "My feature name")) }
7
9
 
8
10
  # define our own Before/After so we can test this in isolation from cucumber's implementation.
9
11
  def Before(tag, &block)
@@ -17,9 +19,9 @@ describe VCR::CucumberTags do
17
19
  def test_tag(cassette_attribute, tag, expected_value)
18
20
  VCR.current_cassette.should be_nil
19
21
 
20
- before_blocks_for_tags[tag].call
22
+ before_blocks_for_tags[tag].call(current_scenario)
21
23
  VCR.current_cassette.send(cassette_attribute).should eq(expected_value)
22
- after_blocks_for_tags[tag].call
24
+ after_blocks_for_tags[tag].call(current_scenario)
23
25
 
24
26
  VCR.current_cassette.should be_nil
25
27
  end
@@ -47,6 +49,31 @@ describe VCR::CucumberTags do
47
49
  test_tag(:record_mode, 'tag1', :none)
48
50
  test_tag(:record_mode, 'tag2', :new_episodes)
49
51
  end
52
+
53
+ context 'with :use_scenario_name as an option' do
54
+ it "uses the scenario's name as the cassette name" do
55
+ subject.send(tag_method, 'tag1', :use_scenario_name => true)
56
+
57
+ test_tag(:name, 'tag1', 'My feature name/My scenario name')
58
+ end
59
+
60
+ it 'does not pass :use_scenario_name along the given options to the cassette' do
61
+ subject.send(tag_method, 'tag1', :use_scenario_name => true)
62
+
63
+ VCR::Cassette.should_receive(:new).with(anything, hash_not_including(:use_scenario_name))
64
+ before_blocks_for_tags['tag1'].call(current_scenario)
65
+ end
66
+
67
+ it 'does not modify the options passed to the cassette' do
68
+ original_options = { :use_scenario_name => true, :record => :none }
69
+ subject.send(tag_method, 'tag1', original_options)
70
+ before_blocks_for_tags['tag1'].call(current_scenario)
71
+
72
+ original_options.should have(2).items
73
+ original_options[:use_scenario_name].should eq(true)
74
+ original_options[:record].should eq(:none)
75
+ end
76
+ end
50
77
  end
51
78
  end
52
79
 
data/spec/vcr_spec.rb CHANGED
@@ -95,6 +95,12 @@ describe VCR do
95
95
  VCR.should_not_receive(:eject_cassette)
96
96
  expect { VCR.use_cassette(:test) { } }.to raise_error(StandardError, 'Boom!')
97
97
  end
98
+
99
+ it 'raises a helpful error if no block is given' do
100
+ expect {
101
+ VCR.use_cassette(:test)
102
+ }.to raise_error(/requires a block/)
103
+ end
98
104
  end
99
105
 
100
106
  describe '.http_interactions' do
data/vcr.gemspec CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_development_dependency 'sinatra', '~> 1.3.2'
39
39
  s.add_development_dependency 'multi_json', '~> 1.0.3'
40
40
  s.add_development_dependency 'json', '~> 1.6.5'
41
- s.add_development_dependency 'limited_red', '~> 0.3.8'
41
+ s.add_development_dependency 'limited_red', '~> 0.3.9'
42
42
  s.add_development_dependency 'simplecov', '~> 0.5.3'
43
43
 
44
44
  unless RUBY_PLATFORM == 'java'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vcr
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 0
9
8
  - 1
10
- version: 2.0.1
9
+ - 0
10
+ version: 2.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Myron Marston
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-30 00:00:00 Z
18
+ date: 2012-04-19 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  version_requirements: &id001 !ruby/object:Gem::Requirement
@@ -289,12 +289,12 @@ dependencies:
289
289
  requirements:
290
290
  - - ~>
291
291
  - !ruby/object:Gem::Version
292
- hash: 3
292
+ hash: 1
293
293
  segments:
294
294
  - 0
295
295
  - 3
296
- - 8
297
- version: 0.3.8
296
+ - 9
297
+ version: 0.3.9
298
298
  name: limited_red
299
299
  type: :development
300
300
  prerelease: false
@@ -404,7 +404,6 @@ extensions: []
404
404
  extra_rdoc_files: []
405
405
 
406
406
  files:
407
- - .document
408
407
  - .gemtest
409
408
  - .gitignore
410
409
  - .gitmodules
@@ -425,6 +424,7 @@ files:
425
424
  - features/.nav
426
425
  - features/about_these_examples.md
427
426
  - features/cassettes/automatic_re_recording.feature
427
+ - features/cassettes/decompress.feature
428
428
  - features/cassettes/dynamic_erb.feature
429
429
  - features/cassettes/exclusive.feature
430
430
  - features/cassettes/format.feature
@@ -597,6 +597,7 @@ summary: Record your test suite's HTTP interactions and replay them during futur
597
597
  test_files:
598
598
  - features/about_these_examples.md
599
599
  - features/cassettes/automatic_re_recording.feature
600
+ - features/cassettes/decompress.feature
600
601
  - features/cassettes/dynamic_erb.feature
601
602
  - features/cassettes/exclusive.feature
602
603
  - features/cassettes/format.feature
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE