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.
- data/.gitignore +2 -0
- data/.limited_red +1 -0
- data/.travis.yml +10 -1
- data/.yardopts +9 -0
- data/CHANGELOG.md +51 -1
- data/Gemfile +5 -1
- data/LICENSE +1 -1
- data/README.md +23 -28
- data/Rakefile +63 -18
- data/Upgrade.md +200 -0
- data/features/.nav +2 -0
- data/features/cassettes/automatic_re_recording.feature +19 -15
- data/features/cassettes/dynamic_erb.feature +12 -4
- data/features/cassettes/exclusive.feature +31 -23
- data/features/cassettes/format.feature +54 -30
- data/features/cassettes/naming.feature +1 -1
- data/features/cassettes/update_content_length_header.feature +16 -12
- data/features/configuration/allow_http_connections_when_no_cassette.feature +1 -1
- data/features/configuration/debug_logging.feature +52 -0
- data/features/configuration/filter_sensitive_data.feature +4 -4
- data/features/configuration/hook_into.feature +5 -2
- data/features/configuration/ignore_request.feature +5 -3
- data/features/configuration/preserve_exact_body_bytes.feature +103 -0
- data/features/hooks/after_http_request.feature +17 -4
- data/features/hooks/around_http_request.feature +2 -1
- data/features/hooks/before_http_request.feature +25 -8
- data/features/hooks/before_playback.feature +16 -12
- data/features/hooks/before_record.feature +2 -2
- data/features/http_libraries/em_http_request.feature +82 -58
- data/features/http_libraries/net_http.feature +6 -6
- data/features/middleware/faraday.feature +2 -1
- data/features/middleware/rack.feature +2 -2
- data/features/record_modes/all.feature +19 -15
- data/features/record_modes/new_episodes.feature +17 -13
- data/features/record_modes/none.feature +15 -11
- data/features/record_modes/once.feature +16 -12
- data/features/request_matching/body.feature +28 -20
- data/features/request_matching/custom_matcher.feature +28 -20
- data/features/request_matching/headers.feature +34 -26
- data/features/request_matching/host.feature +28 -20
- data/features/request_matching/identical_request_sequence.feature +28 -20
- data/features/request_matching/method.feature +28 -20
- data/features/request_matching/path.feature +28 -20
- data/features/request_matching/playback_repeats.feature +28 -20
- data/features/request_matching/uri.feature +28 -20
- data/features/request_matching/uri_without_param.feature +28 -20
- data/features/support/env.rb +7 -6
- data/features/support/vcr_cucumber_helpers.rb +1 -0
- data/features/test_frameworks/cucumber.feature +8 -8
- data/features/test_frameworks/rspec_macro.feature +4 -4
- data/features/test_frameworks/rspec_metadata.feature +6 -6
- data/features/test_frameworks/shoulda.feature +1 -1
- data/features/test_frameworks/test_unit.feature +1 -1
- data/lib/vcr.rb +156 -5
- data/lib/vcr/cassette.rb +80 -30
- data/lib/vcr/cassette/http_interaction_list.rb +33 -4
- data/lib/vcr/cassette/migrator.rb +2 -3
- data/lib/vcr/cassette/reader.rb +1 -0
- data/lib/vcr/cassette/serializers.rb +22 -0
- data/lib/vcr/cassette/serializers/json.rb +27 -2
- data/lib/vcr/cassette/serializers/psych.rb +26 -2
- data/lib/vcr/cassette/serializers/syck.rb +28 -2
- data/lib/vcr/cassette/serializers/yaml.rb +28 -2
- data/lib/vcr/configuration.rb +348 -10
- data/lib/vcr/deprecations.rb +8 -0
- data/lib/vcr/errors.rb +40 -0
- data/lib/vcr/extensions/net_http_response.rb +12 -11
- data/lib/vcr/library_hooks.rb +1 -0
- data/lib/vcr/library_hooks/excon.rb +24 -3
- data/lib/vcr/library_hooks/fakeweb.rb +32 -16
- data/lib/vcr/library_hooks/faraday.rb +3 -0
- data/lib/vcr/library_hooks/typhoeus.rb +40 -37
- data/lib/vcr/library_hooks/webmock.rb +54 -34
- data/lib/vcr/middleware/faraday.rb +13 -0
- data/lib/vcr/middleware/rack.rb +35 -0
- data/lib/vcr/request_handler.rb +60 -8
- data/lib/vcr/request_ignorer.rb +1 -0
- data/lib/vcr/request_matcher_registry.rb +28 -0
- data/lib/vcr/structs.rb +245 -38
- data/lib/vcr/test_frameworks/cucumber.rb +10 -0
- data/lib/vcr/test_frameworks/rspec.rb +26 -1
- data/lib/vcr/util/hooks.rb +29 -27
- data/lib/vcr/util/internet_connection.rb +2 -0
- data/lib/vcr/util/logger.rb +25 -0
- data/lib/vcr/util/variable_args_block_caller.rb +1 -0
- data/lib/vcr/util/version_checker.rb +1 -0
- data/lib/vcr/version.rb +8 -1
- data/spec/capture_warnings.rb +3 -3
- data/spec/monkey_patches.rb +28 -13
- data/spec/spec_helper.rb +17 -0
- data/spec/support/http_library_adapters.rb +7 -4
- data/spec/support/shared_example_groups/hook_into_http_library.rb +96 -32
- data/spec/support/shared_example_groups/request_hooks.rb +9 -8
- data/spec/support/sinatra_app.rb +3 -1
- data/spec/support/vcr_localhost_server.rb +1 -0
- data/spec/vcr/cassette/http_interaction_list_spec.rb +119 -54
- data/spec/vcr/cassette/migrator_spec.rb +19 -6
- data/spec/vcr/cassette/serializers_spec.rb +51 -6
- data/spec/vcr/cassette_spec.rb +44 -19
- data/spec/vcr/configuration_spec.rb +91 -6
- data/spec/vcr/library_hooks/excon_spec.rb +54 -16
- data/spec/vcr/library_hooks/fakeweb_spec.rb +12 -21
- data/spec/vcr/library_hooks/typhoeus_spec.rb +2 -29
- data/spec/vcr/library_hooks/webmock_spec.rb +4 -18
- data/spec/vcr/middleware/faraday_spec.rb +1 -16
- data/spec/vcr/structs_spec.rb +194 -61
- data/spec/vcr/test_frameworks/rspec_spec.rb +10 -0
- data/spec/vcr/util/hooks_spec.rb +104 -56
- data/spec/vcr/util/version_checker_spec.rb +45 -0
- data/spec/vcr_spec.rb +11 -0
- data/vcr.gemspec +30 -34
- metadata +149 -95
- 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
|
data/spec/support/sinatra_app.rb
CHANGED
@@ -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
|
33
|
+
headers 'Set-Cookie' => %w[ bar foo ]
|
32
34
|
'header set'
|
33
35
|
end
|
34
36
|
|
@@ -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
|
-
|
10
|
-
|
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
|
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 "
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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:
|
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:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
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
|
data/spec/vcr/cassette_spec.rb
CHANGED
@@ -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(
|
47
|
-
cassette.new_recorded_interactions.should eq([
|
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(:
|
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
|
-
|
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
|
345
|
-
VCR.configuration.should_receive(:
|
364
|
+
it 'invokes the before_playback hooks' do
|
365
|
+
VCR.configuration.should_receive(:invoke_hook).with(
|
346
366
|
:before_playback,
|
347
|
-
|
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
|
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]
|
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]
|
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(:
|
427
|
+
VCR.configuration.should_receive(:invoke_hook).with(
|
407
428
|
:before_record,
|
408
|
-
|
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.
|
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
|
-
|
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])
|