vcr 2.0.0.beta1 → 2.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +37 -2
- data/Gemfile +2 -2
- data/README.md +10 -1
- data/Rakefile +43 -7
- data/Upgrade.md +45 -0
- data/features/.nav +1 -0
- data/features/cassettes/automatic_re_recording.feature +19 -17
- data/features/cassettes/dynamic_erb.feature +32 -28
- data/features/cassettes/exclusive.feature +28 -24
- data/features/cassettes/format.feature +213 -31
- data/features/cassettes/update_content_length_header.feature +20 -18
- data/features/configuration/filter_sensitive_data.feature +4 -4
- data/features/configuration/hooks.feature +27 -23
- data/features/http_libraries/em_http_request.feature +79 -75
- data/features/record_modes/all.feature +14 -14
- data/features/record_modes/new_episodes.feature +15 -15
- data/features/record_modes/none.feature +15 -15
- data/features/record_modes/once.feature +15 -15
- data/features/request_matching/body.feature +25 -23
- data/features/request_matching/custom_matcher.feature +25 -23
- data/features/request_matching/headers.feature +32 -36
- data/features/request_matching/host.feature +27 -25
- data/features/request_matching/identical_request_sequence.feature +27 -25
- data/features/request_matching/method.feature +27 -25
- data/features/request_matching/path.feature +27 -25
- data/features/request_matching/playback_repeats.feature +27 -25
- data/features/request_matching/uri.feature +27 -25
- data/features/request_matching/uri_without_param.feature +28 -26
- data/features/step_definitions/cli_steps.rb +71 -17
- data/features/support/env.rb +3 -1
- data/features/support/http_lib_filters.rb +6 -3
- data/features/support/vcr_cucumber_helpers.rb +4 -2
- data/lib/vcr.rb +6 -2
- data/lib/vcr/cassette.rb +75 -51
- data/lib/vcr/cassette/migrator.rb +111 -0
- data/lib/vcr/cassette/serializers.rb +35 -0
- data/lib/vcr/cassette/serializers/json.rb +23 -0
- data/lib/vcr/cassette/serializers/psych.rb +24 -0
- data/lib/vcr/cassette/serializers/syck.rb +35 -0
- data/lib/vcr/cassette/serializers/yaml.rb +24 -0
- data/lib/vcr/configuration.rb +6 -1
- data/lib/vcr/errors.rb +1 -1
- data/lib/vcr/library_hooks/excon.rb +1 -7
- data/lib/vcr/library_hooks/typhoeus.rb +6 -22
- data/lib/vcr/library_hooks/webmock.rb +1 -1
- data/lib/vcr/middleware/faraday.rb +1 -1
- data/lib/vcr/request_matcher_registry.rb +43 -30
- data/lib/vcr/structs.rb +209 -0
- data/lib/vcr/tasks/vcr.rake +9 -0
- data/lib/vcr/version.rb +1 -1
- data/spec/fixtures/cassette_spec/1_x_cassette.yml +110 -0
- data/spec/fixtures/cassette_spec/example.yml +79 -78
- data/spec/fixtures/cassette_spec/with_localhost_requests.yml +79 -77
- data/spec/fixtures/fake_example.com_responses.yml +78 -76
- data/spec/fixtures/match_requests_on.yml +147 -145
- data/spec/monkey_patches.rb +5 -5
- data/spec/support/http_library_adapters.rb +48 -0
- data/spec/support/shared_example_groups/hook_into_http_library.rb +53 -20
- data/spec/support/sinatra_app.rb +12 -0
- data/spec/vcr/cassette/http_interaction_list_spec.rb +1 -1
- data/spec/vcr/cassette/migrator_spec.rb +183 -0
- data/spec/vcr/cassette/serializers_spec.rb +122 -0
- data/spec/vcr/cassette_spec.rb +147 -83
- data/spec/vcr/configuration_spec.rb +11 -1
- data/spec/vcr/library_hooks/typhoeus_spec.rb +3 -3
- data/spec/vcr/library_hooks/webmock_spec.rb +7 -1
- data/spec/vcr/request_ignorer_spec.rb +1 -1
- data/spec/vcr/request_matcher_registry_spec.rb +46 -4
- data/spec/vcr/structs_spec.rb +309 -0
- data/spec/vcr_spec.rb +7 -0
- data/vcr.gemspec +9 -12
- metadata +75 -61
- data/lib/vcr/structs/http_interaction.rb +0 -58
- data/lib/vcr/structs/normalizers/body.rb +0 -24
- data/lib/vcr/structs/normalizers/header.rb +0 -64
- data/lib/vcr/structs/normalizers/status_message.rb +0 -17
- data/lib/vcr/structs/normalizers/uri.rb +0 -34
- data/lib/vcr/structs/request.rb +0 -13
- data/lib/vcr/structs/response.rb +0 -13
- data/lib/vcr/structs/response_status.rb +0 -5
- data/lib/vcr/util/yaml.rb +0 -11
- data/spec/support/shared_example_groups/normalizers.rb +0 -94
- data/spec/vcr/structs/http_interaction_spec.rb +0 -89
- data/spec/vcr/structs/request_spec.rb +0 -39
- data/spec/vcr/structs/response_spec.rb +0 -44
- data/spec/vcr/structs/response_status_spec.rb +0 -9
@@ -18,7 +18,8 @@ describe VCR::Configuration do
|
|
18
18
|
it 'has a hash with some defaults' do
|
19
19
|
subject.default_cassette_options.should eq({
|
20
20
|
:match_requests_on => VCR::RequestMatcherRegistry::DEFAULT_MATCHERS,
|
21
|
-
:record => :once
|
21
|
+
:record => :once,
|
22
|
+
:serialize_with => :yaml
|
22
23
|
})
|
23
24
|
end
|
24
25
|
|
@@ -140,4 +141,13 @@ describe VCR::Configuration do
|
|
140
141
|
yielded_interaction.should equal(interaction)
|
141
142
|
end
|
142
143
|
end
|
144
|
+
|
145
|
+
describe "#cassette_serializers" do
|
146
|
+
let(:custom_serializer) { stub }
|
147
|
+
it 'allows a custom serializer to be registered' do
|
148
|
+
expect { subject.cassette_serializers[:custom] }.to raise_error(ArgumentError)
|
149
|
+
subject.cassette_serializers[:custom] = custom_serializer
|
150
|
+
subject.cassette_serializers[:custom].should be(custom_serializer)
|
151
|
+
end
|
152
|
+
end
|
143
153
|
end
|
@@ -4,9 +4,9 @@ describe "Typhoeus hook", :with_monkey_patches => :typhoeus do
|
|
4
4
|
it_behaves_like 'a hook into an HTTP library', 'typhoeus'
|
5
5
|
|
6
6
|
it_performs('version checking', 'Typhoeus',
|
7
|
-
:valid => %w[ 0.2
|
8
|
-
:too_low => %w[ 0.
|
9
|
-
:too_high => %w[ 0.
|
7
|
+
:valid => %w[ 0.3.2 0.3.10 ],
|
8
|
+
:too_low => %w[ 0.2.0 0.2.31 0.3.1 ],
|
9
|
+
:too_high => %w[ 0.4.0 1.0.0 ]
|
10
10
|
) do
|
11
11
|
before(:each) { @orig_version = Typhoeus::VERSION }
|
12
12
|
after(:each) { Typhoeus::VERSION = @orig_version }
|
@@ -2,7 +2,13 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "WebMock hook", :with_monkey_patches => :webmock do
|
4
4
|
%w[net/http patron httpclient em-http-request curb typhoeus].each do |lib|
|
5
|
-
it_behaves_like 'a hook into an HTTP library', lib
|
5
|
+
it_behaves_like 'a hook into an HTTP library', lib do
|
6
|
+
if lib == 'net/http'
|
7
|
+
def normalize_request_headers(headers)
|
8
|
+
headers.merge(DEFAULT_REQUEST_HEADERS)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
6
12
|
end
|
7
13
|
|
8
14
|
it_performs('version checking', 'WebMock',
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'vcr/request_matcher_registry'
|
2
|
-
require 'vcr/structs
|
2
|
+
require 'vcr/structs'
|
3
3
|
require 'uri'
|
4
4
|
|
5
5
|
module VCR
|
@@ -41,7 +41,7 @@ module VCR
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
describe "#
|
44
|
+
describe "#[]" do
|
45
45
|
it 'returns a previously registered matcher' do
|
46
46
|
matcher = lambda { }
|
47
47
|
subject.register(:my_matcher, &matcher)
|
@@ -51,7 +51,7 @@ module VCR
|
|
51
51
|
it 'raises an ArgumentError when no matcher has been registered for the given name' do
|
52
52
|
expect {
|
53
53
|
subject[:some_unregistered_matcher]
|
54
|
-
}.to raise_error(UnregisteredMatcherError)
|
54
|
+
}.to raise_error(VCR::Errors::UnregisteredMatcherError)
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'returns an object that calls the named block when #matches? is called on it' do
|
@@ -70,6 +70,15 @@ module VCR
|
|
70
70
|
|
71
71
|
[:uri_without_param, :uri_without_params].each do |meth|
|
72
72
|
describe "##{meth}" do
|
73
|
+
it 'returns a matcher that can be registered for later use' do
|
74
|
+
matcher = subject.send(meth, :foo)
|
75
|
+
subject.register(:uri_without_foo, &matcher)
|
76
|
+
subject[:uri_without_foo].matches?(
|
77
|
+
request_with(:uri => 'http://example.com/search?foo=123'),
|
78
|
+
request_with(:uri => 'http://example.com/search?foo=123')
|
79
|
+
).should be_true
|
80
|
+
end
|
81
|
+
|
73
82
|
it 'matches two requests with URIs that are identical' do
|
74
83
|
subject[subject.send(meth, :foo)].matches?(
|
75
84
|
request_with(:uri => 'http://example.com/search?foo=123'),
|
@@ -77,7 +86,7 @@ module VCR
|
|
77
86
|
).should be_true
|
78
87
|
end
|
79
88
|
|
80
|
-
it 'does not
|
89
|
+
it 'does not match two requests with different path parts' do
|
81
90
|
subject[subject.send(meth, :foo)].matches?(
|
82
91
|
request_with(:uri => 'http://example.com/search?foo=123'),
|
83
92
|
request_with(:uri => 'http://example.com/find?foo=123')
|
@@ -118,6 +127,13 @@ module VCR
|
|
118
127
|
request_with(:uri => 'http://example.com/search?foo=124&baz=9&bar=q')
|
119
128
|
).should be_true
|
120
129
|
end
|
130
|
+
|
131
|
+
it 'matches two requests with URIs that have no params' do
|
132
|
+
subject[subject.send(meth, :foo, :bar)].matches?(
|
133
|
+
request_with(:uri => 'http://example.com/search'),
|
134
|
+
request_with(:uri => 'http://example.com/search')
|
135
|
+
).should be_true
|
136
|
+
end
|
121
137
|
end
|
122
138
|
end
|
123
139
|
|
@@ -152,6 +168,32 @@ module VCR
|
|
152
168
|
request_with(:uri => 'http://foo2.com/bar?baz=7')
|
153
169
|
).should be_false
|
154
170
|
end
|
171
|
+
|
172
|
+
it 'does not consider the standard HTTP port' do
|
173
|
+
subject[:uri].matches?(
|
174
|
+
request_with(:uri => 'http://foo.com:80/bar?baz=7'),
|
175
|
+
request_with(:uri => 'http://foo.com/bar?baz=7')
|
176
|
+
).should be_true
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'does not consider the standard HTTPS port' do
|
180
|
+
subject[:uri].matches?(
|
181
|
+
request_with(:uri => 'https://foo.com/bar?baz=7'),
|
182
|
+
request_with(:uri => 'https://foo.com:443/bar?baz=7')
|
183
|
+
).should be_true
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'considers non-standard ports' do
|
187
|
+
subject[:uri].matches?(
|
188
|
+
request_with(:uri => 'http://foo.com:79/bar?baz=7'),
|
189
|
+
request_with(:uri => 'http://foo.com:78/bar?baz=7')
|
190
|
+
).should be_false
|
191
|
+
|
192
|
+
subject[:uri].matches?(
|
193
|
+
request_with(:uri => 'https://foo.com:442/bar?baz=7'),
|
194
|
+
request_with(:uri => 'https://foo.com:441/bar?baz=7')
|
195
|
+
).should be_false
|
196
|
+
end
|
155
197
|
end
|
156
198
|
|
157
199
|
describe ":host" do
|
@@ -0,0 +1,309 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'vcr/structs'
|
3
|
+
|
4
|
+
shared_examples_for "a header normalizer" do
|
5
|
+
let(:instance) do
|
6
|
+
with_headers('Some_Header' => 'value1', 'aNother' => ['a', 'b'], 'third' => [], 'fourth' => nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'ensures header keys are serialized to yaml as raw strings' do
|
10
|
+
key = 'my-key'
|
11
|
+
key.instance_variable_set(:@foo, 7)
|
12
|
+
instance = with_headers(key => ['value1'])
|
13
|
+
YAML.dump(instance.headers).should eq(YAML.dump('my-key' => ['value1']))
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'ensures header values are serialized to yaml as raw strings' do
|
17
|
+
value = 'my-value'
|
18
|
+
value.instance_variable_set(:@foo, 7)
|
19
|
+
instance = with_headers('my-key' => [value])
|
20
|
+
YAML.dump(instance.headers).should eq(YAML.dump('my-key' => ['my-value']))
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'handles nested arrays' do
|
24
|
+
accept_encoding = [["gzip", "1.0"], ["deflate", "1.0"], ["sdch", "1.0"]]
|
25
|
+
instance = with_headers('accept-encoding' => accept_encoding)
|
26
|
+
instance.headers['accept-encoding'].should eq(accept_encoding)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'handles nested arrays with floats' do
|
30
|
+
accept_encoding = [["gzip", 1.0], ["deflate", 1.0], ["sdch", 1.0]]
|
31
|
+
instance = with_headers('accept-encoding' => accept_encoding)
|
32
|
+
instance.headers['accept-encoding'].should eq(accept_encoding)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
shared_examples_for "a body normalizer" do
|
37
|
+
it "ensures the body is serialized to yaml as a raw string" do
|
38
|
+
body = "My String"
|
39
|
+
body.instance_variable_set(:@foo, 7)
|
40
|
+
YAML.dump(instance(body).body).should eq(YAML.dump("My String"))
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'converts nil to a blank string' do
|
44
|
+
instance(nil).body.should eq("")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module VCR
|
49
|
+
describe HTTPInteraction do
|
50
|
+
%w( uri method ).each do |attr|
|
51
|
+
it "delegates :#{attr} to the request" do
|
52
|
+
sig = mock('request')
|
53
|
+
sig.should_receive(attr).and_return(:the_value)
|
54
|
+
instance = described_class.new(sig, nil)
|
55
|
+
instance.send(attr).should eq(:the_value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#ignored?' do
|
60
|
+
it 'returns false by default' do
|
61
|
+
should_not be_ignored
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns true when #ignore! has been called' do
|
65
|
+
subject.ignore!
|
66
|
+
should be_ignored
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#recorded_at" do
|
71
|
+
let(:now) { Time.now }
|
72
|
+
|
73
|
+
it 'is initialized to the current time' do
|
74
|
+
Time.stub(:now => now)
|
75
|
+
VCR::HTTPInteraction.new.recorded_at.should eq(now)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
let(:status) { ResponseStatus.new(200, "OK") }
|
80
|
+
let(:response) { Response.new(status, { "foo" => ["bar"] }, "res body", "1.1") }
|
81
|
+
let(:request) { Request.new(:get, "http://foo.com/", "req body", { "bar" => ["foo"] }) }
|
82
|
+
let(:recorded_at) { Time.utc(2011, 5, 4, 12, 30) }
|
83
|
+
let(:interaction) { HTTPInteraction.new(request, response, recorded_at) }
|
84
|
+
|
85
|
+
describe ".from_hash" do
|
86
|
+
let(:hash) do
|
87
|
+
{
|
88
|
+
'request' => {
|
89
|
+
'method' => 'get',
|
90
|
+
'uri' => 'http://foo.com/',
|
91
|
+
'body' => 'req body',
|
92
|
+
'headers' => { "bar" => ["foo"] }
|
93
|
+
},
|
94
|
+
'response' => {
|
95
|
+
'status' => {
|
96
|
+
'code' => 200,
|
97
|
+
'message' => 'OK'
|
98
|
+
},
|
99
|
+
'headers' => { "foo" => ["bar"] },
|
100
|
+
'body' => 'res body',
|
101
|
+
'http_version' => '1.1'
|
102
|
+
},
|
103
|
+
'recorded_at' => "Wed, 04 May 2011 12:30:00 GMT"
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'constructs an HTTP interaction from the given hash' do
|
108
|
+
HTTPInteraction.from_hash(hash).should eq(interaction)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'initializes the recorded_at timestamp from the hash' do
|
112
|
+
HTTPInteraction.from_hash(hash).recorded_at.should eq(recorded_at)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'uses a blank request when the hash lacks one' do
|
116
|
+
hash.delete('request')
|
117
|
+
i = HTTPInteraction.from_hash(hash)
|
118
|
+
i.request.should eq(Request.new)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'uses a blank response when the hash lacks one' do
|
122
|
+
hash.delete('response')
|
123
|
+
i = HTTPInteraction.from_hash(hash)
|
124
|
+
i.response.should eq(Response.new(ResponseStatus.new))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#to_hash" do
|
129
|
+
let(:hash) { interaction.to_hash }
|
130
|
+
|
131
|
+
it 'returns a nested hash containing all of the pertinent details' do
|
132
|
+
hash.keys.should =~ %w[ request response recorded_at ]
|
133
|
+
|
134
|
+
hash['recorded_at'].should eq(interaction.recorded_at.httpdate)
|
135
|
+
|
136
|
+
hash['request'].should eq({
|
137
|
+
'method' => 'get',
|
138
|
+
'uri' => 'http://foo.com/',
|
139
|
+
'body' => 'req body',
|
140
|
+
'headers' => { "bar" => ["foo"] }
|
141
|
+
})
|
142
|
+
|
143
|
+
hash['response'].should eq({
|
144
|
+
'status' => {
|
145
|
+
'code' => 200,
|
146
|
+
'message' => 'OK'
|
147
|
+
},
|
148
|
+
'headers' => { "foo" => ["bar"] },
|
149
|
+
'body' => 'res body',
|
150
|
+
'http_version' => '1.1'
|
151
|
+
})
|
152
|
+
end
|
153
|
+
|
154
|
+
def assert_yielded_keys(hash, *keys)
|
155
|
+
yielded_keys = []
|
156
|
+
hash.each { |k, v| yielded_keys << k }
|
157
|
+
yielded_keys.should eq(keys)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'yields the entries in the expected order so the hash can be serialized in that order' do
|
161
|
+
assert_yielded_keys hash, 'request', 'response', 'recorded_at'
|
162
|
+
assert_yielded_keys hash['request'], 'method', 'uri', 'body', 'headers'
|
163
|
+
assert_yielded_keys hash['response'], 'status', 'headers', 'body', 'http_version'
|
164
|
+
assert_yielded_keys hash['response']['status'], 'code', 'message'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#filter!' do
|
169
|
+
let(:response_status) { VCR::ResponseStatus.new(200, "OK foo") }
|
170
|
+
let(:body) { "The body foo this is (foo-Foo)" }
|
171
|
+
let(:headers) do {
|
172
|
+
'x-http-foo' => ['bar23', '23foo'],
|
173
|
+
'x-http-bar' => ['foo23', '18']
|
174
|
+
} end
|
175
|
+
|
176
|
+
let(:response) do
|
177
|
+
VCR::Response.new(
|
178
|
+
response_status,
|
179
|
+
headers.dup,
|
180
|
+
body.dup,
|
181
|
+
'1.1'
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
let(:request) do
|
186
|
+
VCR::Request.new(
|
187
|
+
:get,
|
188
|
+
'http://example-foo.com:80/foo/',
|
189
|
+
body.dup,
|
190
|
+
headers.dup
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
let(:interaction) { VCR::HTTPInteraction.new(request, response) }
|
195
|
+
|
196
|
+
subject { interaction.filter!('foo', 'AAA') }
|
197
|
+
|
198
|
+
it 'does nothing when given a blank argument' do
|
199
|
+
expect {
|
200
|
+
interaction.filter!(nil, 'AAA')
|
201
|
+
interaction.filter!('foo', nil)
|
202
|
+
interaction.filter!("", 'AAA')
|
203
|
+
interaction.filter!('foo', "")
|
204
|
+
}.not_to change { interaction }
|
205
|
+
end
|
206
|
+
|
207
|
+
[:request, :response].each do |part|
|
208
|
+
it "replaces the sensitive text in the #{part} header keys and values" do
|
209
|
+
subject.send(part).headers.should eq({
|
210
|
+
'x-http-AAA' => ['bar23', '23AAA'],
|
211
|
+
'x-http-bar' => ['AAA23', '18']
|
212
|
+
})
|
213
|
+
end
|
214
|
+
|
215
|
+
it "replaces the sensitive text in the #{part} body" do
|
216
|
+
subject.send(part).body.should eq("The body AAA this is (AAA-Foo)")
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'replaces the sensitive text in the response status' do
|
221
|
+
subject.response.status.message.should eq('OK AAA')
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'replaces sensitive text in the request URI' do
|
225
|
+
subject.request.uri.should eq('http://example-AAA.com:80/AAA/')
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe Request do
|
231
|
+
describe '#method' do
|
232
|
+
subject { VCR::Request.new(:get) }
|
233
|
+
|
234
|
+
context 'when given no arguments' do
|
235
|
+
it 'returns the HTTP method' do
|
236
|
+
subject.method.should eq(:get)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'when given an argument' do
|
241
|
+
it 'returns the method object for the named method' do
|
242
|
+
m = subject.method(:class)
|
243
|
+
m.should be_a(Method)
|
244
|
+
m.call.should eq(described_class)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
it_behaves_like 'a header normalizer' do
|
250
|
+
def with_headers(headers)
|
251
|
+
described_class.new(:get, 'http://example.com/', nil, headers)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
it_behaves_like 'a body normalizer' do
|
256
|
+
def instance(body)
|
257
|
+
described_class.new(:get, 'http://example.com/', body, {})
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe Response do
|
263
|
+
it_behaves_like 'a header normalizer' do
|
264
|
+
def with_headers(headers)
|
265
|
+
described_class.new(:status, headers, nil, '1.1')
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
it_behaves_like 'a body normalizer' do
|
270
|
+
def instance(body)
|
271
|
+
described_class.new(:status, {}, body, '1.1')
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe '#update_content_length_header' do
|
276
|
+
%w[ content-length Content-Length ].each do |header|
|
277
|
+
context "for the #{header} header" do
|
278
|
+
define_method :instance do |body, content_length|
|
279
|
+
headers = { 'content-type' => 'text' }
|
280
|
+
headers.merge!(header => content_length) if content_length
|
281
|
+
described_class.new(VCR::ResponseStatus.new, headers, body)
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'does nothing when the response lacks a content_length header' do
|
285
|
+
inst = instance('the body', nil)
|
286
|
+
expect {
|
287
|
+
inst.update_content_length_header
|
288
|
+
}.not_to change { inst.headers[header] }
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'sets the content_length header to the response body length when the header is present' do
|
292
|
+
inst = instance('the body', '3')
|
293
|
+
expect {
|
294
|
+
inst.update_content_length_header
|
295
|
+
}.to change { inst.headers[header] }.from(['3']).to(['8'])
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'sets the content_length header to 0 if the response body is nil' do
|
299
|
+
inst = instance(nil, '3')
|
300
|
+
expect {
|
301
|
+
inst.update_content_length_header
|
302
|
+
}.to change { inst.headers[header] }.from(['3']).to(['0'])
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|