vcr 2.0.0.beta1 → 2.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +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
|
+
|