vcr 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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