vcr 2.0.0.rc1 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.gitignore +2 -0
  2. data/.limited_red +1 -0
  3. data/.travis.yml +10 -1
  4. data/.yardopts +9 -0
  5. data/CHANGELOG.md +51 -1
  6. data/Gemfile +5 -1
  7. data/LICENSE +1 -1
  8. data/README.md +23 -28
  9. data/Rakefile +63 -18
  10. data/Upgrade.md +200 -0
  11. data/features/.nav +2 -0
  12. data/features/cassettes/automatic_re_recording.feature +19 -15
  13. data/features/cassettes/dynamic_erb.feature +12 -4
  14. data/features/cassettes/exclusive.feature +31 -23
  15. data/features/cassettes/format.feature +54 -30
  16. data/features/cassettes/naming.feature +1 -1
  17. data/features/cassettes/update_content_length_header.feature +16 -12
  18. data/features/configuration/allow_http_connections_when_no_cassette.feature +1 -1
  19. data/features/configuration/debug_logging.feature +52 -0
  20. data/features/configuration/filter_sensitive_data.feature +4 -4
  21. data/features/configuration/hook_into.feature +5 -2
  22. data/features/configuration/ignore_request.feature +5 -3
  23. data/features/configuration/preserve_exact_body_bytes.feature +103 -0
  24. data/features/hooks/after_http_request.feature +17 -4
  25. data/features/hooks/around_http_request.feature +2 -1
  26. data/features/hooks/before_http_request.feature +25 -8
  27. data/features/hooks/before_playback.feature +16 -12
  28. data/features/hooks/before_record.feature +2 -2
  29. data/features/http_libraries/em_http_request.feature +82 -58
  30. data/features/http_libraries/net_http.feature +6 -6
  31. data/features/middleware/faraday.feature +2 -1
  32. data/features/middleware/rack.feature +2 -2
  33. data/features/record_modes/all.feature +19 -15
  34. data/features/record_modes/new_episodes.feature +17 -13
  35. data/features/record_modes/none.feature +15 -11
  36. data/features/record_modes/once.feature +16 -12
  37. data/features/request_matching/body.feature +28 -20
  38. data/features/request_matching/custom_matcher.feature +28 -20
  39. data/features/request_matching/headers.feature +34 -26
  40. data/features/request_matching/host.feature +28 -20
  41. data/features/request_matching/identical_request_sequence.feature +28 -20
  42. data/features/request_matching/method.feature +28 -20
  43. data/features/request_matching/path.feature +28 -20
  44. data/features/request_matching/playback_repeats.feature +28 -20
  45. data/features/request_matching/uri.feature +28 -20
  46. data/features/request_matching/uri_without_param.feature +28 -20
  47. data/features/support/env.rb +7 -6
  48. data/features/support/vcr_cucumber_helpers.rb +1 -0
  49. data/features/test_frameworks/cucumber.feature +8 -8
  50. data/features/test_frameworks/rspec_macro.feature +4 -4
  51. data/features/test_frameworks/rspec_metadata.feature +6 -6
  52. data/features/test_frameworks/shoulda.feature +1 -1
  53. data/features/test_frameworks/test_unit.feature +1 -1
  54. data/lib/vcr.rb +156 -5
  55. data/lib/vcr/cassette.rb +80 -30
  56. data/lib/vcr/cassette/http_interaction_list.rb +33 -4
  57. data/lib/vcr/cassette/migrator.rb +2 -3
  58. data/lib/vcr/cassette/reader.rb +1 -0
  59. data/lib/vcr/cassette/serializers.rb +22 -0
  60. data/lib/vcr/cassette/serializers/json.rb +27 -2
  61. data/lib/vcr/cassette/serializers/psych.rb +26 -2
  62. data/lib/vcr/cassette/serializers/syck.rb +28 -2
  63. data/lib/vcr/cassette/serializers/yaml.rb +28 -2
  64. data/lib/vcr/configuration.rb +348 -10
  65. data/lib/vcr/deprecations.rb +8 -0
  66. data/lib/vcr/errors.rb +40 -0
  67. data/lib/vcr/extensions/net_http_response.rb +12 -11
  68. data/lib/vcr/library_hooks.rb +1 -0
  69. data/lib/vcr/library_hooks/excon.rb +24 -3
  70. data/lib/vcr/library_hooks/fakeweb.rb +32 -16
  71. data/lib/vcr/library_hooks/faraday.rb +3 -0
  72. data/lib/vcr/library_hooks/typhoeus.rb +40 -37
  73. data/lib/vcr/library_hooks/webmock.rb +54 -34
  74. data/lib/vcr/middleware/faraday.rb +13 -0
  75. data/lib/vcr/middleware/rack.rb +35 -0
  76. data/lib/vcr/request_handler.rb +60 -8
  77. data/lib/vcr/request_ignorer.rb +1 -0
  78. data/lib/vcr/request_matcher_registry.rb +28 -0
  79. data/lib/vcr/structs.rb +245 -38
  80. data/lib/vcr/test_frameworks/cucumber.rb +10 -0
  81. data/lib/vcr/test_frameworks/rspec.rb +26 -1
  82. data/lib/vcr/util/hooks.rb +29 -27
  83. data/lib/vcr/util/internet_connection.rb +2 -0
  84. data/lib/vcr/util/logger.rb +25 -0
  85. data/lib/vcr/util/variable_args_block_caller.rb +1 -0
  86. data/lib/vcr/util/version_checker.rb +1 -0
  87. data/lib/vcr/version.rb +8 -1
  88. data/spec/capture_warnings.rb +3 -3
  89. data/spec/monkey_patches.rb +28 -13
  90. data/spec/spec_helper.rb +17 -0
  91. data/spec/support/http_library_adapters.rb +7 -4
  92. data/spec/support/shared_example_groups/hook_into_http_library.rb +96 -32
  93. data/spec/support/shared_example_groups/request_hooks.rb +9 -8
  94. data/spec/support/sinatra_app.rb +3 -1
  95. data/spec/support/vcr_localhost_server.rb +1 -0
  96. data/spec/vcr/cassette/http_interaction_list_spec.rb +119 -54
  97. data/spec/vcr/cassette/migrator_spec.rb +19 -6
  98. data/spec/vcr/cassette/serializers_spec.rb +51 -6
  99. data/spec/vcr/cassette_spec.rb +44 -19
  100. data/spec/vcr/configuration_spec.rb +91 -6
  101. data/spec/vcr/library_hooks/excon_spec.rb +54 -16
  102. data/spec/vcr/library_hooks/fakeweb_spec.rb +12 -21
  103. data/spec/vcr/library_hooks/typhoeus_spec.rb +2 -29
  104. data/spec/vcr/library_hooks/webmock_spec.rb +4 -18
  105. data/spec/vcr/middleware/faraday_spec.rb +1 -16
  106. data/spec/vcr/structs_spec.rb +194 -61
  107. data/spec/vcr/test_frameworks/rspec_spec.rb +10 -0
  108. data/spec/vcr/util/hooks_spec.rb +104 -56
  109. data/spec/vcr/util/version_checker_spec.rb +45 -0
  110. data/spec/vcr_spec.rb +11 -0
  111. data/vcr.gemspec +30 -34
  112. metadata +149 -95
  113. data/spec/support/shared_example_groups/version_checking.rb +0 -34
@@ -1,13 +1,6 @@
1
- shared_examples_for "request hooks" do |library_hook_name|
1
+ shared_examples_for "request hooks" do |library_hook_name, request_type|
2
2
  let(:request_url) { "http://localhost:#{VCR::SinatraApp.port}/foo" }
3
3
 
4
- before(:each) do
5
- # ensure that all the other library hooks are disabled so that we don't
6
- # get double-hookage (such as for WebMock and Typhoeus both invoking the
7
- # hooks for a typhoeus request)
8
- VCR.library_hooks.stub(:disabled?) { |lib_name| lib_name != library_hook_name }
9
- end
10
-
11
4
  def make_request(disabled = false)
12
5
  make_http_request(:get, request_url)
13
6
  end
@@ -45,6 +38,14 @@ shared_examples_for "request hooks" do |library_hook_name|
45
38
  make_request(:disabled)
46
39
  hook_called.should be_false
47
40
  end
41
+
42
+ specify "the #type of the yielded request given to the #{hook} hook is #{request_type}" do
43
+ request = nil
44
+ VCR.configuration.send(hook) { |r| request = r }
45
+
46
+ make_request
47
+ request.type.should be(request_type)
48
+ end
48
49
  end
49
50
 
50
51
  specify "the after_http_request hook yields the response if there is one and the second block arg is given" do
@@ -2,6 +2,8 @@ require 'sinatra'
2
2
 
3
3
  module VCR
4
4
  class SinatraApp < ::Sinatra::Base
5
+ disable :protection
6
+
5
7
  get '/' do
6
8
  "GET to root"
7
9
  end
@@ -28,7 +30,7 @@ module VCR
28
30
  end
29
31
 
30
32
  get '/set-cookie-headers/2' do
31
- headers 'Set-Cookie' => %w[ foo bar ]
33
+ headers 'Set-Cookie' => %w[ bar foo ]
32
34
  'header set'
33
35
  end
34
36
 
@@ -59,6 +59,7 @@ module VCR
59
59
  def concurrently
60
60
  if should_use_subprocess?
61
61
  pid = Process.fork do
62
+ trap(:INT) { ::Rack::Handler::WEBrick.shutdown }
62
63
  yield
63
64
  exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet.
64
65
  end
@@ -1,3 +1,4 @@
1
+ require 'vcr/util/logger'
1
2
  require 'vcr/cassette/http_interaction_list'
2
3
  require 'vcr/request_matcher_registry'
3
4
  require 'vcr/structs'
@@ -5,57 +6,14 @@ require 'uri'
5
6
 
6
7
  module VCR
7
8
  class Cassette
8
-
9
- shared_examples_for "an HTTP interaction finding method" do |method|
10
- it 'returns nil when the list is empty' do
11
- HTTPInteractionList.new([], [:method]).send(method, stub).should respond_with(nil)
12
- end
13
-
14
- it 'returns nil when there is no matching interaction' do
15
- HTTPInteractionList.new([
16
- interaction('foo', :method => :post),
17
- interaction('foo', :method => :put)
18
- ], [:method]).send(method,
19
- request_with(:method => :get)
20
- ).should respond_with(nil)
21
- end
22
-
23
- it 'returns the first matching interaction' do
24
- list = HTTPInteractionList.new([
25
- interaction('put response', :method => :put),
26
- interaction('post response 1', :method => :post),
27
- interaction('post response 2', :method => :post)
28
- ], [:method])
29
-
30
- list.send(method, request_with(:method => :post)).should respond_with("post response 1")
31
- end
32
-
33
- it 'invokes each matcher block to find the matching interaction' do
34
- VCR.request_matchers.register(:foo) { |r1, r2| true }
35
- VCR.request_matchers.register(:bar) { |r1, r2| true }
36
-
37
- calls = 0
38
- VCR.request_matchers.register(:baz) { |r1, r2| calls += 1; calls == 2 }
39
-
40
- list = HTTPInteractionList.new([
41
- interaction('response', :method => :put)
42
- ], [:foo, :bar, :baz])
43
-
44
- list.send(method, request_with(:method => :post)).should respond_with(nil)
45
- list.send(method, request_with(:method => :post)).should respond_with('response')
46
- end
47
-
48
- it "delegates to the parent list when it can't find a matching interaction" do
49
- parent_list = mock(method => response('parent'))
50
- HTTPInteractionList.new(
51
- [], [:method], false, parent_list
52
- ).send(method, stub).should respond_with('parent')
9
+ describe HTTPInteractionList do
10
+ ::RSpec::Matchers.define :respond_with do |expected|
11
+ match { |a| expected.nil? ? a.nil? : a.body == expected }
53
12
  end
54
- end
55
13
 
56
- describe HTTPInteractionList do
57
14
  before(:each) do
58
15
  VCR.stub(:request_matchers => VCR::RequestMatcherRegistry.new)
16
+ VCR.stub_chain(:configuration, :debug_logger).and_return(stub.as_null_object)
59
17
  end
60
18
 
61
19
  def request_with(values)
@@ -67,7 +25,10 @@ module VCR
67
25
  end
68
26
 
69
27
  def response(body)
70
- VCR::Response.new.tap { |r| r.body = body }
28
+ VCR::Response.new.tap do |r|
29
+ r.body = body
30
+ r.status = VCR::ResponseStatus.new(200)
31
+ end
71
32
  end
72
33
 
73
34
  def interaction(body, request_values)
@@ -125,14 +86,118 @@ module VCR
125
86
  end
126
87
  end
127
88
 
128
- describe "#response_for" do
129
- it_behaves_like "an HTTP interaction finding method", :response_for do
130
- def respond_with(value)
131
- ::RSpec::Matchers::Matcher.new :respond_with, value do |expected|
132
- match { |a| expected.nil? ? a.nil? : a.body == expected }
133
- end
89
+ describe "has_interaction_matching?" do
90
+ it 'returns false when the list is empty' do
91
+ HTTPInteractionList.new([], [:method]).should_not have_interaction_matching(stub)
92
+ end
93
+
94
+ it 'returns false when there is no matching interaction' do
95
+ list.should_not have_interaction_matching(request_with(:method => :get))
96
+ end
97
+
98
+ it 'returns true when there is a matching interaction' do
99
+ list.should have_interaction_matching(request_with(:method => :post))
100
+ end
101
+
102
+ it 'does not consume the interactions when they match' do
103
+ list.should have_interaction_matching(request_with(:method => :post))
104
+ list.remaining_unused_interaction_count.should eq(3)
105
+ list.should have_interaction_matching(request_with(:method => :post))
106
+ list.remaining_unused_interaction_count.should eq(3)
107
+ end
108
+
109
+ it 'invokes each matcher block to find the matching interaction' do
110
+ VCR.request_matchers.register(:foo) { |r1, r2| true }
111
+ VCR.request_matchers.register(:bar) { |r1, r2| true }
112
+
113
+ calls = 0
114
+ VCR.request_matchers.register(:baz) { |r1, r2| calls += 1; calls == 2 }
115
+
116
+ list = HTTPInteractionList.new([
117
+ interaction('response', :method => :put)
118
+ ], [:foo, :bar, :baz])
119
+
120
+ list.should_not have_interaction_matching(request_with(:method => :post))
121
+ list.should have_interaction_matching(request_with(:method => :post))
122
+ end
123
+
124
+ it "delegates to the parent list when it can't find a matching interaction" do
125
+ parent_list = mock(:has_interaction_matching? => true)
126
+ HTTPInteractionList.new( [], [:method], false, parent_list).should have_interaction_matching(stub)
127
+ parent_list = mock(:has_interaction_matching? => false)
128
+ HTTPInteractionList.new( [], [:method], false, parent_list).should_not have_interaction_matching(stub)
129
+ end
130
+
131
+ context 'when allow_playback_repeats is set to true' do
132
+ let(:allow_playback_repeats) { true }
133
+
134
+ it 'considers used interactions' do
135
+ list.response_for(request_with(:method => :put))
136
+
137
+ 10.times.map {
138
+ list.has_interaction_matching?(request_with(:method => :put))
139
+ }.should eq([true] * 10)
140
+ end
141
+ end
142
+
143
+ context 'when allow_playback_repeats is set to false' do
144
+ let(:allow_playback_repeats) { false }
145
+
146
+ it 'does not consider used interactions' do
147
+ list.response_for(request_with(:method => :put))
148
+
149
+ 10.times.map {
150
+ list.has_interaction_matching?(request_with(:method => :put))
151
+ }.should eq([false] * 10)
134
152
  end
135
153
  end
154
+ end
155
+
156
+ describe "#response_for" do
157
+ it 'returns nil when the list is empty' do
158
+ HTTPInteractionList.new([], [:method]).response_for(stub).should respond_with(nil)
159
+ end
160
+
161
+ it 'returns nil when there is no matching interaction' do
162
+ HTTPInteractionList.new([
163
+ interaction('foo', :method => :post),
164
+ interaction('foo', :method => :put)
165
+ ], [:method]).response_for(
166
+ request_with(:method => :get)
167
+ ).should respond_with(nil)
168
+ end
169
+
170
+ it 'returns the first matching interaction' do
171
+ list = HTTPInteractionList.new([
172
+ interaction('put response', :method => :put),
173
+ interaction('post response 1', :method => :post),
174
+ interaction('post response 2', :method => :post)
175
+ ], [:method])
176
+
177
+ list.response_for(request_with(:method => :post)).should respond_with("post response 1")
178
+ end
179
+
180
+ it 'invokes each matcher block to find the matching interaction' do
181
+ VCR.request_matchers.register(:foo) { |r1, r2| true }
182
+ VCR.request_matchers.register(:bar) { |r1, r2| true }
183
+
184
+ calls = 0
185
+ VCR.request_matchers.register(:baz) { |r1, r2| calls += 1; calls == 2 }
186
+
187
+ list = HTTPInteractionList.new([
188
+ interaction('response', :method => :put)
189
+ ], [:foo, :bar, :baz])
190
+
191
+ list.response_for(request_with(:method => :post)).should respond_with(nil)
192
+ list.response_for(request_with(:method => :post)).should respond_with('response')
193
+ end
194
+
195
+ it "delegates to the parent list when it can't find a matching interaction" do
196
+ parent_list = mock(:response_for => response('parent'))
197
+ HTTPInteractionList.new(
198
+ [], [:method], false, parent_list
199
+ ).response_for(stub).should respond_with('parent')
200
+ end
136
201
 
137
202
  it 'consumes the first matching interaction so that it will not be used again' do
138
203
  list.response_for(request_with(:method => :post)).body.should eq("post response 1")
@@ -47,7 +47,9 @@ http_interactions:
47
47
  - request:
48
48
  method: get
49
49
  uri: http://example.com/foo
50
- body: ""
50
+ body:
51
+ encoding: US-ASCII
52
+ string: ""
51
53
  headers: {}
52
54
 
53
55
  response:
@@ -59,13 +61,17 @@ http_interactions:
59
61
  - text/html;charset=utf-8
60
62
  Content-Length:
61
63
  - "9"
62
- body: Hello foo
64
+ body:
65
+ encoding: UTF-8
66
+ string: Hello foo
63
67
  http_version: "1.1"
64
68
  recorded_at: Wed, 04 May 2011 12:30:00 GMT
65
69
  - request:
66
70
  method: get
67
71
  uri: http://localhost:7777/bar
68
- body: ""
72
+ body:
73
+ encoding: US-ASCII
74
+ string: ""
69
75
  headers: {}
70
76
 
71
77
  response:
@@ -77,7 +83,9 @@ http_interactions:
77
83
  - text/html;charset=utf-8
78
84
  Content-Length:
79
85
  - "9"
80
- body: Hello bar
86
+ body:
87
+ encoding: UTF-8
88
+ string: Hello bar
81
89
  http_version: "1.1"
82
90
  recorded_at: Wed, 04 May 2011 12:30:00 GMT
83
91
  recorded_with: VCR #{VCR.version}
@@ -92,6 +100,11 @@ EOF
92
100
  FileUtils.mkdir_p dir
93
101
  end
94
102
 
103
+ before(:each) do
104
+ # the encoding won't be set on rubies that don't support it
105
+ updated_contents.gsub!(/^\s+encoding:.*$/, '')
106
+ end unless ''.respond_to?(:encoding)
107
+
95
108
  # JRuby serializes YAML with some slightly different whitespace.
96
109
  before(:each) do
97
110
  [original_contents, updated_contents].each do |contents|
@@ -123,7 +136,7 @@ EOF
123
136
  it 'migrates a cassette from the 1.x to 2.x format' do
124
137
  File.open(file_name, 'w') { |f| f.write(original_contents) }
125
138
  subject.migrate!
126
- File.read(file_name).should eq(updated_contents)
139
+ YAML.load_file(file_name).should eq(YAML.load(updated_contents))
127
140
  output.should match(/Migrated example.yml/)
128
141
  end
129
142
 
@@ -145,7 +158,7 @@ EOF
145
158
  modified_contents = original_contents.gsub('example.com', '<HOST>')
146
159
  File.open(file_name, 'w') { |f| f.write(modified_contents) }
147
160
  subject.migrate!
148
- File.read(file_name).should eq(updated_contents.gsub('example.com', '<HOST>:80'))
161
+ YAML.load_file(file_name).should eq(YAML.load(updated_contents.gsub('example.com', '<HOST>:80')))
149
162
  end
150
163
 
151
164
  it 'ignores files that are empty' do
@@ -1,4 +1,5 @@
1
1
  require 'vcr/cassette/serializers'
2
+ require 'multi_json'
2
3
  begin
3
4
  require 'psych' # ensure psych is loaded for these tests if its available
4
5
  rescue LoadError
@@ -7,11 +8,21 @@ end
7
8
  module VCR
8
9
  class Cassette
9
10
  describe Serializers do
11
+ shared_examples_for "encoding error handling" do |name, error_class|
12
+ context "the #{name} serializer" do
13
+ it 'appends info about the :preserve_exact_body_bytes option to the error' do
14
+ expect {
15
+ result = serializer.serialize("a" => string)
16
+ serializer.deserialize(result)
17
+ }.to raise_error(error_class, /preserve_exact_body_bytes/)
18
+ end
19
+ end
20
+ end
10
21
 
11
22
  shared_examples_for "a serializer" do |name, file_extension, lazily_loaded|
12
- context "the #{name} serializer" do
13
- let(:serializer) { subject[name] }
23
+ let(:serializer) { subject[name] }
14
24
 
25
+ context "the #{name} serializer" do
15
26
  it 'lazily loads the serializer' do
16
27
  serializers = subject.instance_variable_get(:@serializers)
17
28
  serializers.should_not have_key(name)
@@ -34,10 +45,44 @@ module VCR
34
45
  end
35
46
  end
36
47
 
37
- it_behaves_like "a serializer", :yaml, "yml", :lazily_loaded
38
- it_behaves_like "a serializer", :syck, "yml", :lazily_loaded
39
- it_behaves_like "a serializer", :psych, "yml", :lazily_loaded if RUBY_VERSION =~ /1.9/
40
- it_behaves_like "a serializer", :json, "json", :lazily_loaded
48
+ it_behaves_like "a serializer", :yaml, "yml", :lazily_loaded do
49
+ it_behaves_like "encoding error handling", :yaml, ArgumentError do
50
+ let(:string) { "\xFA".force_encoding("UTF-8") }
51
+ before { ::YAML::ENGINE.yamler = 'psych' }
52
+ end if ''.respond_to?(:encoding)
53
+ end
54
+
55
+ it_behaves_like "a serializer", :syck, "yml", :lazily_loaded do
56
+ it_behaves_like "encoding error handling", :syck, ArgumentError do
57
+ let(:string) { "\xFA".force_encoding("UTF-8") }
58
+ end if ''.respond_to?(:encoding)
59
+ end
60
+
61
+ it_behaves_like "a serializer", :psych, "yml", :lazily_loaded do
62
+ it_behaves_like "encoding error handling", :psych, ArgumentError do
63
+ let(:string) { "\xFA".force_encoding("UTF-8") }
64
+ end if ''.respond_to?(:encoding)
65
+ end if RUBY_VERSION =~ /1.9/
66
+
67
+ it_behaves_like "a serializer", :json, "json", :lazily_loaded do
68
+ engines = {}
69
+
70
+ engines[:yajl] = ::MultiJson::DecodeError unless RUBY_INTERPRETER == :jruby
71
+
72
+ if RUBY_VERSION =~ /1.9/
73
+ engines[:json_gem] = EncodingError
74
+ engines[:json_pure] = EncodingError
75
+ end
76
+
77
+ engines.each do |engine, error|
78
+ context "when MultiJson is configured to use #{engine.inspect}" do
79
+ before { MultiJson.engine = engine }
80
+ it_behaves_like "encoding error handling", :json, error do
81
+ let(:string) { "\xFA" }
82
+ end
83
+ end
84
+ end
85
+ end
41
86
 
42
87
  context "a custom :ruby serializer" do
43
88
  let(:custom_serializer) do
@@ -39,18 +39,36 @@ describe VCR::Cassette do
39
39
  end
40
40
  end
41
41
 
42
+ describe '#tags' do
43
+ it 'returns a blank array if no tag has been set' do
44
+ VCR::Cassette.new("name").tags.should eq([])
45
+ end
46
+
47
+ it 'converts a single :tag to an array' do
48
+ VCR::Cassette.new("name", :tag => :foo).tags.should eq([:foo])
49
+ end
50
+
51
+ it 'accepts an array as the :tags option' do
52
+ VCR::Cassette.new("name", :tags => [:foo]).tags.should eq([:foo])
53
+ end
54
+ end
55
+
42
56
  describe '#record_http_interaction' do
57
+ let(:the_interaction) { stub(:request => stub(:method => :get).as_null_object).as_null_object }
58
+
43
59
  it 'adds the interaction to #new_recorded_interactions' do
44
60
  cassette = VCR::Cassette.new(:test_cassette)
45
61
  cassette.new_recorded_interactions.should eq([])
46
- cassette.record_http_interaction(:the_interaction)
47
- cassette.new_recorded_interactions.should eq([:the_interaction])
62
+ cassette.record_http_interaction(the_interaction)
63
+ cassette.new_recorded_interactions.should eq([the_interaction])
48
64
  end
49
65
  end
50
66
 
51
67
  describe "#serializable_hash" do
52
68
  subject { VCR::Cassette.new("foo") }
53
- let(:interactions) { [stub(:to_hash => { "i" => 1 }, :ignored? => false), stub(:to_hash => { "i" => 2 }, :ignored? => false)] }
69
+ let(:interaction_1) { http_interaction { |i| i.request.body = 'req body 1'; i.response.body = 'res body 1' } }
70
+ let(:interaction_2) { http_interaction { |i| i.request.body = 'req body 2'; i.response.body = 'res body 2' } }
71
+ let(:interactions) { [interaction_1, interaction_2] }
54
72
 
55
73
  before(:each) do
56
74
  interactions.each do |i|
@@ -61,7 +79,9 @@ describe VCR::Cassette do
61
79
  let(:metadata) { subject.serializable_hash.reject { |k,v| k == "http_interactions" } }
62
80
 
63
81
  it 'includes the hash form of all recorded interactions' do
64
- subject.serializable_hash.should include('http_interactions' => [{ "i" => 1 }, { "i" => 2 }])
82
+ interaction_1.stub(:to_hash => { "i" => 1, 'body' => '' })
83
+ interaction_2.stub(:to_hash => { "i" => 2, 'body' => '' })
84
+ subject.serializable_hash.should include('http_interactions' => [{ "i" => 1, 'body' => '' }, { "i" => 2, 'body' => '' }])
65
85
  end
66
86
 
67
87
  it 'includes additional metadata about the cassette' do
@@ -182,7 +202,7 @@ describe VCR::Cassette do
182
202
 
183
203
  it 'does not raise an error in the case of an empty file' do
184
204
  VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
185
- VCR::Cassette.new('empty', :record => :none).previously_recorded_interactions.should eq([])
205
+ VCR::Cassette.new('empty', :record => :none).send(:previously_recorded_interactions).should eq([])
186
206
  end
187
207
 
188
208
  VCR::Cassette::VALID_RECORD_MODES.each do |record_mode|
@@ -294,7 +314,7 @@ describe VCR::Cassette do
294
314
 
295
315
  VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
296
316
  cassette = VCR::Cassette.new('with_localhost_requests', :record => record_mode)
297
- cassette.previously_recorded_interactions.map { |i| URI.parse(i.uri).host }.should eq(%w[example.com])
317
+ cassette.send(:previously_recorded_interactions).map { |i| URI.parse(i.request.uri).host }.should eq(%w[example.com])
298
318
  end
299
319
 
300
320
  it "loads the recorded interactions from the library yml file" do
@@ -303,7 +323,7 @@ describe VCR::Cassette do
303
323
 
304
324
  cassette.should have(3).previously_recorded_interactions
305
325
 
306
- i1, i2, i3 = *cassette.previously_recorded_interactions
326
+ i1, i2, i3 = *cassette.send(:previously_recorded_interactions)
307
327
 
308
328
  i1.request.method.should eq(:get)
309
329
  i1.request.uri.should eq('http://example.com/')
@@ -341,15 +361,14 @@ describe VCR::Cassette do
341
361
  end
342
362
 
343
363
  if stub_requests
344
- it 'invokes the appropriately tagged before_playback hooks' do
345
- VCR.configuration.should_receive(:invoke_tagged_hook).with(
364
+ it 'invokes the before_playback hooks' do
365
+ VCR.configuration.should_receive(:invoke_hook).with(
346
366
  :before_playback,
347
- :foo,
348
- an_instance_of(VCR::HTTPInteraction),
367
+ an_instance_of(VCR::HTTPInteraction::HookAware),
349
368
  an_instance_of(VCR::Cassette)
350
369
  ).exactly(3).times
351
370
 
352
- cassette = VCR::Cassette.new('example', :record => record_mode, :tag => :foo)
371
+ cassette = VCR::Cassette.new('example', :record => record_mode)
353
372
  cassette.should have(3).previously_recorded_interactions
354
373
  end
355
374
 
@@ -367,14 +386,14 @@ describe VCR::Cassette do
367
386
  VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
368
387
  cassette = VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:body, :headers])
369
388
  cassette.http_interactions.interactions.should have(3).interactions
370
- cassette.http_interactions.request_matchers.should eq([:body, :headers].map { |m| VCR.request_matchers[m] })
389
+ cassette.http_interactions.request_matchers.should eq([:body, :headers])
371
390
  end
372
391
  else
373
392
  it 'instantiates the http_interactions with the no interactions and the request matchers' do
374
393
  VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
375
394
  cassette = VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:body, :headers])
376
395
  cassette.http_interactions.interactions.should have(0).interactions
377
- cassette.http_interactions.request_matchers.should eq([:body, :headers].map { |m| VCR.request_matchers[m] })
396
+ cassette.http_interactions.request_matchers.should eq([:body, :headers])
378
397
  end
379
398
  end
380
399
  end
@@ -402,11 +421,12 @@ describe VCR::Cassette do
402
421
  cassette = VCR::Cassette.new('example', :tag => :foo)
403
422
  cassette.stub!(:new_recorded_interactions).and_return(interactions)
404
423
 
424
+ VCR.configuration.stub(:invoke_hook).and_return([false])
425
+
405
426
  interactions.each do |i|
406
- VCR.configuration.should_receive(:invoke_tagged_hook).with(
427
+ VCR.configuration.should_receive(:invoke_hook).with(
407
428
  :before_record,
408
- :foo,
409
- i,
429
+ an_instance_of(VCR::HTTPInteraction::HookAware),
410
430
  cassette
411
431
  ).ordered
412
432
  end
@@ -418,7 +438,9 @@ describe VCR::Cassette do
418
438
  interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
419
439
  interaction_2 = http_interaction { |i| i.request.uri = 'http://bar.com/'; i.response.body = 'res 2' }
420
440
 
421
- interaction_1.ignore!
441
+ hook_aware_interaction_1 = interaction_1.hook_aware
442
+ interaction_1.stub(:hook_aware => hook_aware_interaction_1)
443
+ hook_aware_interaction_1.ignore!
422
444
 
423
445
  cassette = VCR::Cassette.new('test_cassette')
424
446
  cassette.stub!(:new_recorded_interactions).and_return([interaction_1, interaction_2])
@@ -430,7 +452,10 @@ describe VCR::Cassette do
430
452
 
431
453
  it 'does not write the cassette to disk if all interactions have been ignored' do
432
454
  interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
433
- interaction_1.ignore!
455
+
456
+ hook_aware_interaction_1 = interaction_1.hook_aware
457
+ interaction_1.stub(:hook_aware => hook_aware_interaction_1)
458
+ hook_aware_interaction_1.ignore!
434
459
 
435
460
  cassette = VCR::Cassette.new('test_cassette')
436
461
  cassette.stub!(:new_recorded_interactions).and_return([interaction_1])