vcr 3.0.2 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +5 -5
  2. data/lib/vcr.rb +33 -1
  3. data/lib/vcr/cassette.rb +47 -12
  4. data/lib/vcr/cassette/http_interaction_list.rb +14 -9
  5. data/lib/vcr/cassette/migrator.rb +0 -5
  6. data/lib/vcr/cassette/persisters/file_system.rb +9 -1
  7. data/lib/vcr/cassette/serializers/compressed.rb +2 -2
  8. data/lib/vcr/cassette/serializers/json.rb +7 -7
  9. data/lib/vcr/cassette/serializers/psych.rb +3 -1
  10. data/lib/vcr/cassette/serializers/yaml.rb +3 -1
  11. data/lib/vcr/configuration.rb +20 -8
  12. data/lib/vcr/deprecations.rb +0 -62
  13. data/lib/vcr/errors.rb +17 -12
  14. data/lib/vcr/library_hooks/excon.rb +8 -0
  15. data/lib/vcr/library_hooks/typhoeus.rb +37 -8
  16. data/lib/vcr/linked_cassette.rb +4 -4
  17. data/lib/vcr/middleware/faraday.rb +10 -1
  18. data/lib/vcr/request_ignorer.rb +4 -1
  19. data/lib/vcr/request_matcher_registry.rb +1 -1
  20. data/lib/vcr/structs.rb +48 -32
  21. data/lib/vcr/test_frameworks/cucumber.rb +4 -4
  22. data/lib/vcr/test_frameworks/rspec.rb +12 -3
  23. data/lib/vcr/util/hooks.rb +1 -0
  24. data/lib/vcr/util/internet_connection.rb +15 -21
  25. data/lib/vcr/version.rb +1 -1
  26. metadata +36 -263
  27. data/features/CHANGELOG.md +0 -1
  28. data/features/CONTRIBUTING.md +0 -1
  29. data/features/LICENSE.md +0 -1
  30. data/features/README.md +0 -1
  31. data/features/Upgrade.md +0 -1
  32. data/features/about_these_examples.md +0 -18
  33. data/features/cassettes/allow_unused_http_interactions.feature +0 -100
  34. data/features/cassettes/automatic_re_recording.feature +0 -72
  35. data/features/cassettes/decompress.feature +0 -74
  36. data/features/cassettes/dynamic_erb.feature +0 -100
  37. data/features/cassettes/exclusive.feature +0 -126
  38. data/features/cassettes/format.feature +0 -411
  39. data/features/cassettes/freezing_time.feature +0 -68
  40. data/features/cassettes/naming.feature +0 -28
  41. data/features/cassettes/no_cassette.feature +0 -152
  42. data/features/cassettes/update_content_length_header.feature +0 -112
  43. data/features/configuration/allow_http_connections_when_no_cassette.feature +0 -55
  44. data/features/configuration/cassette_library_dir.feature +0 -31
  45. data/features/configuration/debug_logging.feature +0 -58
  46. data/features/configuration/default_cassette_options.feature +0 -100
  47. data/features/configuration/filter_sensitive_data.feature +0 -153
  48. data/features/configuration/hook_into.feature +0 -172
  49. data/features/configuration/ignore_request.feature +0 -192
  50. data/features/configuration/preserve_exact_body_bytes.feature +0 -108
  51. data/features/configuration/query_parser.feature +0 -84
  52. data/features/configuration/uri_parser.feature +0 -93
  53. data/features/getting_started.md +0 -82
  54. data/features/hooks/after_http_request.feature +0 -58
  55. data/features/hooks/around_http_request.feature +0 -57
  56. data/features/hooks/before_http_request.feature +0 -63
  57. data/features/hooks/before_playback.feature +0 -184
  58. data/features/hooks/before_record.feature +0 -172
  59. data/features/http_libraries/em_http_request.feature +0 -250
  60. data/features/http_libraries/net_http.feature +0 -179
  61. data/features/middleware/faraday.feature +0 -56
  62. data/features/middleware/rack.feature +0 -92
  63. data/features/record_modes/all.feature +0 -82
  64. data/features/record_modes/new_episodes.feature +0 -79
  65. data/features/record_modes/none.feature +0 -72
  66. data/features/record_modes/once.feature +0 -95
  67. data/features/request_matching/README.md +0 -30
  68. data/features/request_matching/body.feature +0 -91
  69. data/features/request_matching/body_as_json.feature +0 -90
  70. data/features/request_matching/custom_matcher.feature +0 -135
  71. data/features/request_matching/headers.feature +0 -85
  72. data/features/request_matching/host.feature +0 -95
  73. data/features/request_matching/identical_request_sequence.feature +0 -89
  74. data/features/request_matching/method.feature +0 -96
  75. data/features/request_matching/path.feature +0 -96
  76. data/features/request_matching/playback_repeats.feature +0 -98
  77. data/features/request_matching/query.feature +0 -97
  78. data/features/request_matching/uri.feature +0 -94
  79. data/features/request_matching/uri_without_param.feature +0 -101
  80. data/features/step_definitions/cli_steps.rb +0 -199
  81. data/features/support/env.rb +0 -46
  82. data/features/support/http_lib_filters.rb +0 -46
  83. data/features/test_frameworks/cucumber.feature +0 -211
  84. data/features/test_frameworks/rspec_macro.feature +0 -81
  85. data/features/test_frameworks/rspec_metadata.feature +0 -150
  86. data/features/test_frameworks/test_unit.feature +0 -49
  87. data/lib/vcr/extensions/net_http_response.rb +0 -36
  88. data/lib/vcr/library_hooks/fakeweb.rb +0 -197
  89. data/spec/acceptance/concurrency_spec.rb +0 -51
  90. data/spec/acceptance/threading_spec.rb +0 -34
  91. data/spec/fixtures/cassette_spec/1_x_cassette.yml +0 -110
  92. data/spec/fixtures/cassette_spec/empty.yml +0 -0
  93. data/spec/fixtures/cassette_spec/example.yml +0 -111
  94. data/spec/fixtures/cassette_spec/with_localhost_requests.yml +0 -111
  95. data/spec/fixtures/fake_example_responses.yml +0 -110
  96. data/spec/fixtures/match_requests_on.yml +0 -187
  97. data/spec/lib/vcr/cassette/erb_renderer_spec.rb +0 -53
  98. data/spec/lib/vcr/cassette/http_interaction_list_spec.rb +0 -295
  99. data/spec/lib/vcr/cassette/migrator_spec.rb +0 -196
  100. data/spec/lib/vcr/cassette/persisters/file_system_spec.rb +0 -75
  101. data/spec/lib/vcr/cassette/persisters_spec.rb +0 -39
  102. data/spec/lib/vcr/cassette/serializers_spec.rb +0 -182
  103. data/spec/lib/vcr/cassette_spec.rb +0 -618
  104. data/spec/lib/vcr/configuration_spec.rb +0 -326
  105. data/spec/lib/vcr/deprecations_spec.rb +0 -85
  106. data/spec/lib/vcr/errors_spec.rb +0 -178
  107. data/spec/lib/vcr/extensions/net_http_response_spec.rb +0 -86
  108. data/spec/lib/vcr/library_hooks/excon_spec.rb +0 -104
  109. data/spec/lib/vcr/library_hooks/fakeweb_spec.rb +0 -169
  110. data/spec/lib/vcr/library_hooks/faraday_spec.rb +0 -68
  111. data/spec/lib/vcr/library_hooks/typhoeus_0.4_spec.rb +0 -36
  112. data/spec/lib/vcr/library_hooks/typhoeus_spec.rb +0 -162
  113. data/spec/lib/vcr/library_hooks/webmock_spec.rb +0 -117
  114. data/spec/lib/vcr/library_hooks_spec.rb +0 -51
  115. data/spec/lib/vcr/middleware/faraday_spec.rb +0 -181
  116. data/spec/lib/vcr/middleware/rack_spec.rb +0 -115
  117. data/spec/lib/vcr/request_ignorer_spec.rb +0 -70
  118. data/spec/lib/vcr/request_matcher_registry_spec.rb +0 -345
  119. data/spec/lib/vcr/structs_spec.rb +0 -732
  120. data/spec/lib/vcr/test_frameworks/cucumber_spec.rb +0 -107
  121. data/spec/lib/vcr/test_frameworks/rspec_spec.rb +0 -94
  122. data/spec/lib/vcr/util/hooks_spec.rb +0 -158
  123. data/spec/lib/vcr/util/internet_connection_spec.rb +0 -37
  124. data/spec/lib/vcr/util/version_checker_spec.rb +0 -31
  125. data/spec/lib/vcr/version_spec.rb +0 -27
  126. data/spec/lib/vcr_spec.rb +0 -354
  127. data/spec/monkey_patches.rb +0 -186
  128. data/spec/spec_helper.rb +0 -63
  129. data/spec/support/configuration_stubbing.rb +0 -8
  130. data/spec/support/cucumber_helpers.rb +0 -39
  131. data/spec/support/fixnum_extension.rb +0 -10
  132. data/spec/support/http_library_adapters.rb +0 -289
  133. data/spec/support/limited_uri.rb +0 -21
  134. data/spec/support/ruby_interpreter.rb +0 -7
  135. data/spec/support/shared_example_groups/excon.rb +0 -63
  136. data/spec/support/shared_example_groups/hook_into_http_library.rb +0 -594
  137. data/spec/support/shared_example_groups/request_hooks.rb +0 -59
  138. data/spec/support/sinatra_app.rb +0 -86
  139. data/spec/support/vcr_localhost_server.rb +0 -76
  140. data/spec/support/vcr_stub_helpers.rb +0 -17
@@ -1,732 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'support/ruby_interpreter'
4
-
5
- require 'yaml'
6
- require 'vcr/structs'
7
- require 'vcr/errors'
8
- require 'zlib'
9
- require 'stringio'
10
- require 'support/limited_uri'
11
- require 'support/configuration_stubbing'
12
-
13
- shared_examples_for "a header normalizer" do
14
- let(:instance) do
15
- with_headers('Some_Header' => 'value1', 'aNother' => ['a', 'b'], 'third' => [], 'fourth' => nil)
16
- end
17
-
18
- it 'ensures header keys are serialized to yaml as raw strings' do
19
- key = 'my-key'
20
- key.instance_variable_set(:@foo, 7)
21
- instance = with_headers(key => ['value1'])
22
- expect(YAML.dump(instance.headers)).to eq(YAML.dump('my-key' => ['value1']))
23
- end
24
-
25
- it 'ensures header values are serialized to yaml as raw strings' do
26
- value = 'my-value'
27
- value.instance_variable_set(:@foo, 7)
28
- instance = with_headers('my-key' => [value])
29
- expect(YAML.dump(instance.headers)).to eq(YAML.dump('my-key' => ['my-value']))
30
- end
31
-
32
- it 'handles nested arrays' do
33
- accept_encoding = [["gzip", "1.0"], ["deflate", "1.0"], ["sdch", "1.0"]]
34
- instance = with_headers('accept-encoding' => accept_encoding)
35
- expect(instance.headers['accept-encoding']).to eq(accept_encoding)
36
- end
37
-
38
- it 'handles nested arrays with floats' do
39
- accept_encoding = [["gzip", 1.0], ["deflate", 1.0], ["sdch", 1.0]]
40
- instance = with_headers('accept-encoding' => accept_encoding)
41
- expect(instance.headers['accept-encoding']).to eq(accept_encoding)
42
- end
43
- end
44
-
45
- shared_examples_for "a body normalizer" do
46
- it "ensures the body is serialized to yaml as a raw string" do
47
- body = "My String"
48
- body.instance_variable_set(:@foo, 7)
49
- expect(YAML.dump(instance(body).body)).to eq(YAML.dump("My String"))
50
- end
51
-
52
- it 'converts nil to a blank string' do
53
- expect(instance(nil).body).to eq("")
54
- end
55
-
56
- it 'raises an error if given another type of object as the body' do
57
- expect {
58
- instance(:a => "hash")
59
- }.to raise_error(ArgumentError)
60
- end
61
- end
62
-
63
- module VCR
64
- describe HTTPInteraction do
65
- include_context "configuration stubbing"
66
- before { allow(config).to receive(:uri_parser) { LimitedURI } }
67
-
68
- if ''.respond_to?(:encoding)
69
- def body_hash(key, value)
70
- { key => value, 'encoding' => 'UTF-8' }
71
- end
72
- else
73
- def body_hash(key, value)
74
- { key => value }
75
- end
76
- end
77
-
78
- describe "#recorded_at" do
79
- let(:now) { Time.now }
80
-
81
- it 'is initialized to the current time' do
82
- allow(Time).to receive(:now).and_return(now)
83
- expect(VCR::HTTPInteraction.new.recorded_at).to eq(now)
84
- end
85
- end
86
-
87
- let(:status) { ResponseStatus.new(200, "OK") }
88
- let(:response) { Response.new(status, { "foo" => ["bar"] }, "res body", "1.1") }
89
- let(:request) { Request.new(:get, "http://foo.com/", "req body", { "bar" => ["foo"] }) }
90
- let(:recorded_at) { Time.utc(2011, 5, 4, 12, 30) }
91
- let(:interaction) { HTTPInteraction.new(request, response, recorded_at) }
92
-
93
- describe ".from_hash" do
94
- let(:hash) do
95
- {
96
- 'request' => {
97
- 'method' => 'get',
98
- 'uri' => 'http://foo.com/',
99
- 'body' => body_hash('string', 'req body'),
100
- 'headers' => { "bar" => ["foo"] }
101
- },
102
- 'response' => {
103
- 'status' => {
104
- 'code' => 200,
105
- 'message' => 'OK'
106
- },
107
- 'headers' => { "foo" => ["bar"] },
108
- 'body' => body_hash('string', 'res body'),
109
- 'http_version' => '1.1'
110
- },
111
- 'recorded_at' => "Wed, 04 May 2011 12:30:00 GMT"
112
- }
113
- end
114
-
115
- it 'constructs an HTTP interaction from the given hash' do
116
- expect(HTTPInteraction.from_hash(hash)).to eq(interaction)
117
- end
118
-
119
- it 'initializes the recorded_at timestamp from the hash' do
120
- expect(HTTPInteraction.from_hash(hash).recorded_at).to eq(recorded_at)
121
- end
122
-
123
- it 'initializes the response adapter_metadata from the hash if it is included' do
124
- hash['response']['adapter_metadata'] = { 'foo' => 12 }
125
- interaction = HTTPInteraction.from_hash(hash)
126
- expect(interaction.response.adapter_metadata).to eq("foo" => 12)
127
- end
128
-
129
- it 'works when the response adapter_metadata is missing' do
130
- expect(hash['response'].keys).not_to include('adapter_metadata')
131
- interaction = HTTPInteraction.from_hash(hash)
132
- expect(interaction.response.adapter_metadata).to eq({})
133
- end
134
-
135
- it 'uses a blank request when the hash lacks one' do
136
- hash.delete('request')
137
- i = HTTPInteraction.from_hash(hash)
138
- expect(i.request).to eq(Request.new)
139
- end
140
-
141
- it 'uses a blank response when the hash lacks one' do
142
- hash.delete('response')
143
- i = HTTPInteraction.from_hash(hash)
144
- expect(i.response).to eq(Response.new(ResponseStatus.new))
145
- end
146
-
147
- it 'decodes the base64 body string' do
148
- hash['request']['body'] = body_hash('base64_string', Base64.encode64('req body'))
149
- hash['response']['body'] = body_hash('base64_string', Base64.encode64('res body'))
150
-
151
- i = HTTPInteraction.from_hash(hash)
152
- expect(i.request.body).to eq('req body')
153
- expect(i.response.body).to eq('res body')
154
- end
155
-
156
- if ''.respond_to?(:encoding)
157
- it 'force encodes the decoded base64 string as the original encoding' do
158
- string = "café"
159
- string.force_encoding("US-ASCII")
160
- expect(string).not_to be_valid_encoding
161
-
162
- hash['request']['body'] = { 'base64_string' => Base64.encode64(string.dup), 'encoding' => 'US-ASCII' }
163
- hash['response']['body'] = { 'base64_string' => Base64.encode64(string.dup), 'encoding' => 'US-ASCII' }
164
-
165
- i = HTTPInteraction.from_hash(hash)
166
- expect(i.request.body.encoding.name).to eq("US-ASCII")
167
- expect(i.response.body.encoding.name).to eq("US-ASCII")
168
- expect(i.request.body.bytes.to_a).to eq(string.bytes.to_a)
169
- expect(i.response.body.bytes.to_a).to eq(string.bytes.to_a)
170
- expect(i.request.body).not_to be_valid_encoding
171
- expect(i.response.body).not_to be_valid_encoding
172
- end
173
-
174
- it 'does not attempt to force encode the decoded base64 string when there is no encoding given (i.e. if the cassette was recorded on ruby 1.8)' do
175
- hash['request']['body'] = { 'base64_string' => Base64.encode64('foo') }
176
-
177
- i = HTTPInteraction.from_hash(hash)
178
- expect(i.request.body).to eq('foo')
179
- expect(i.request.body.encoding.name).to eq("ASCII-8BIT")
180
- end
181
-
182
- it 'tries to encode strings to the original encoding' do
183
- hash['request']['body'] = { 'string' => "abc", 'encoding' => 'ISO-8859-1' }
184
- hash['response']['body'] = { 'string' => "abc", 'encoding' => 'ISO-8859-1' }
185
-
186
- i = HTTPInteraction.from_hash(hash)
187
- expect(i.request.body).to eq("abc")
188
- expect(i.response.body).to eq("abc")
189
- expect(i.request.body.encoding.name).to eq("ISO-8859-1")
190
- expect(i.response.body.encoding.name).to eq("ISO-8859-1")
191
- end
192
-
193
- it 'does not attempt to encode the string when there is no encoding given (i.e. if the cassette was recorded on ruby 1.8)' do
194
- string = 'foo'
195
- string.force_encoding("ISO-8859-1")
196
- hash['request']['body'] = { 'string' => string }
197
-
198
- i = HTTPInteraction.from_hash(hash)
199
- expect(i.request.body).to eq('foo')
200
- expect(i.request.body.encoding.name).to eq("ISO-8859-1")
201
- end
202
-
203
- it 'force encodes to ASCII-8BIT (since it just means "no encoding" or binary)' do
204
- string = "\u00f6"
205
- string.encode("UTF-8")
206
- expect(string).to be_valid_encoding
207
- hash['request']['body'] = { 'string' => string, 'encoding' => 'ASCII-8BIT' }
208
-
209
- expect(Request).not_to receive(:warn)
210
- i = HTTPInteraction.from_hash(hash)
211
- expect(i.request.body).to eq(string)
212
- expect(i.request.body.bytes.to_a).to eq(string.bytes.to_a)
213
- expect(i.request.body.encoding.name).to eq("ASCII-8BIT")
214
- end
215
-
216
- context 'when the string cannot be encoded as the original encoding' do
217
- def verify_encoding_error
218
- expect { "\xFAbc".encode("ISO-8859-1") }.to raise_error(EncodingError)
219
- end
220
-
221
- before do
222
- allow(Request).to receive(:warn)
223
- allow(Response).to receive(:warn)
224
-
225
- hash['request']['body'] = { 'string' => "\xFAbc", 'encoding' => 'ISO-8859-1' }
226
- hash['response']['body'] = { 'string' => "\xFAbc", 'encoding' => 'ISO-8859-1' }
227
-
228
- verify_encoding_error
229
- end
230
-
231
- it 'does not force the encoding' do
232
- i = HTTPInteraction.from_hash(hash)
233
- expect(i.request.body).to eq("\xFAbc")
234
- expect(i.response.body).to eq("\xFAbc")
235
- expect(i.request.body.encoding.name).not_to eq("ISO-8859-1")
236
- expect(i.response.body.encoding.name).not_to eq("ISO-8859-1")
237
- end
238
-
239
- it 'prints a warning and informs users of the :preserve_exact_body_bytes option' do
240
- expect(Request).to receive(:warn).with(/ISO-8859-1.*preserve_exact_body_bytes/)
241
- expect(Response).to receive(:warn).with(/ISO-8859-1.*preserve_exact_body_bytes/)
242
-
243
- HTTPInteraction.from_hash(hash)
244
- end
245
- end
246
- end
247
- end
248
-
249
- describe "#to_hash" do
250
- include_context "configuration stubbing"
251
-
252
- before(:each) do
253
- allow(config).to receive(:preserve_exact_body_bytes_for?).and_return(false)
254
- allow(config).to receive(:uri_parser).and_return(URI)
255
- end
256
-
257
- let(:hash) { interaction.to_hash }
258
-
259
- it 'returns a nested hash containing all of the pertinent details' do
260
- expect(hash.keys).to match_array %w[ request response recorded_at ]
261
-
262
- expect(hash['recorded_at']).to eq(interaction.recorded_at.httpdate)
263
-
264
- expect(hash['request']).to eq({
265
- 'method' => 'get',
266
- 'uri' => 'http://foo.com/',
267
- 'body' => body_hash('string', 'req body'),
268
- 'headers' => { "bar" => ["foo"] }
269
- })
270
-
271
- expect(hash['response']).to eq({
272
- 'status' => {
273
- 'code' => 200,
274
- 'message' => 'OK'
275
- },
276
- 'headers' => { "foo" => ["bar"] },
277
- 'body' => body_hash('string', 'res body'),
278
- 'http_version' => '1.1'
279
- })
280
- end
281
-
282
- it 'includes the response adapter metadata when it is not empty' do
283
- interaction.response.adapter_metadata['foo'] = 17
284
- expect(hash['response']['adapter_metadata']).to eq('foo' => 17)
285
- end
286
-
287
- it 'does not include the response adapter metadata when it is empty' do
288
- expect(interaction.response.adapter_metadata).to eq({})
289
- expect(hash['response'].keys).not_to include('adapter_metadata')
290
- end
291
-
292
- context "when the body is extended with a module and some state" do
293
- it 'serializes to YAML w/o the extra state' do
294
- interaction.request.body.extend Module.new { attr_accessor :foo }
295
- interaction.response.body.extend Module.new { attr_accessor :foo }
296
- interaction.request.body.foo = 98765
297
- interaction.response.body.foo = 98765
298
-
299
- expect(YAML.dump(interaction.to_hash)).not_to include("98765")
300
- end
301
- end
302
-
303
- it 'encodes the body as base64 when the configuration is so set' do
304
- allow(config).to receive(:preserve_exact_body_bytes_for?).and_return(true)
305
- expect(hash['request']['body']).to eq(body_hash('base64_string', Base64.encode64('req body')))
306
- expect(hash['response']['body']).to eq(body_hash('base64_string', Base64.encode64('res body')))
307
- end
308
-
309
- it "sets the string's original encoding", :if => ''.respond_to?(:encoding) do
310
- interaction.request.body.force_encoding('ISO-8859-10')
311
- interaction.response.body.force_encoding('ASCII-8BIT')
312
-
313
- expect(hash['request']['body']['encoding']).to eq('ISO-8859-10')
314
- expect(hash['response']['body']['encoding']).to eq('ASCII-8BIT')
315
- end
316
-
317
- def assert_yielded_keys(hash, *keys)
318
- yielded_keys = []
319
- hash.each { |k, v| yielded_keys << k }
320
- expect(yielded_keys).to eq(keys)
321
- end
322
-
323
- it 'yields the entries in the expected order so the hash can be serialized in that order' do
324
- assert_yielded_keys hash, 'request', 'response', 'recorded_at'
325
- assert_yielded_keys hash['request'], 'method', 'uri', 'body', 'headers'
326
- assert_yielded_keys hash['response'], 'status', 'headers', 'body', 'http_version'
327
- assert_yielded_keys hash['response']['status'], 'code', 'message'
328
- end
329
-
330
- it 'yields `adapter_metadata` if it has any data' do
331
- interaction.response.adapter_metadata['foo'] = 17
332
- assert_yielded_keys hash['response'], 'status', 'headers', 'body', 'http_version', 'adapter_metadata'
333
- end
334
- end
335
-
336
- describe "#parsed_uri" do
337
- before :each do
338
- allow(uri_parser).to receive(:parse).and_return(uri)
339
- allow(config).to receive(:uri_parser).and_return(uri_parser)
340
- end
341
-
342
- let(:uri_parser){ double('parser') }
343
- let(:uri){ double('uri').as_null_object }
344
-
345
- it "parses the uri using the current uri_parser" do
346
- expect(uri_parser).to receive(:parse).with(request.uri)
347
- request.parsed_uri
348
- end
349
-
350
- it "returns the parsed uri" do
351
- expect(request.parsed_uri).to eq uri
352
- end
353
- end
354
- end
355
-
356
- describe HTTPInteraction::HookAware do
357
- include_context "configuration stubbing"
358
-
359
- before do
360
- allow(config).to receive(:uri_parser) { LimitedURI }
361
- end
362
-
363
- let(:response_status) { VCR::ResponseStatus.new(200, "OK foo") }
364
- let(:body) { "The body foo this is (foo-Foo)" }
365
- let(:headers) do {
366
- 'x-http-foo' => ['bar23', '23foo'],
367
- 'x-http-bar' => ['foo23', '18']
368
- } end
369
-
370
- let(:response) do
371
- VCR::Response.new(
372
- response_status,
373
- headers.dup,
374
- body.dup,
375
- '1.1'
376
- )
377
- end
378
-
379
- let(:request) do
380
- VCR::Request.new(
381
- :get,
382
- 'http://example-foo.com:80/foo/',
383
- body.dup,
384
- headers.dup
385
- )
386
- end
387
-
388
- let(:interaction) { VCR::HTTPInteraction.new(request, response) }
389
- subject { HTTPInteraction::HookAware.new(interaction) }
390
-
391
- describe '#ignored?' do
392
- it 'returns false by default' do
393
- should_not be_ignored
394
- end
395
-
396
- it 'returns true when #ignore! has been called' do
397
- subject.ignore!
398
- should be_ignored
399
- end
400
- end
401
-
402
- describe '#filter!' do
403
- let(:filtered) { subject.filter!('foo', 'AAA') }
404
-
405
- it 'does nothing when given a blank argument' do
406
- expect {
407
- subject.filter!(nil, 'AAA')
408
- subject.filter!('foo', nil)
409
- subject.filter!("", 'AAA')
410
- subject.filter!('foo', "")
411
- }.not_to change { interaction }
412
- end
413
-
414
- [:request, :response].each do |part|
415
- it "replaces the sensitive text in the #{part} header keys and values" do
416
- expect(filtered.send(part).headers).to eq({
417
- 'x-http-AAA' => ['bar23', '23AAA'],
418
- 'x-http-bar' => ['AAA23', '18']
419
- })
420
- end
421
-
422
- it "replaces the sensitive text in the #{part} body" do
423
- expect(filtered.send(part).body).to eq("The body AAA this is (AAA-Foo)")
424
- end
425
- end
426
-
427
- it 'replaces the sensitive text in the response status' do
428
- expect(filtered.response.status.message).to eq('OK AAA')
429
- end
430
-
431
- it 'replaces sensitive text in the request URI' do
432
- expect(filtered.request.uri).to eq('http://example-AAA.com/AAA/')
433
- end
434
-
435
- it 'handles numbers (such as the port) properly' do
436
- request.uri = "http://foo.com:9000/bar"
437
- subject.filter!(9000, "<PORT>")
438
- expect(request.uri).to eq("http://foo.com:<PORT>/bar")
439
- end
440
- end
441
- end
442
-
443
- describe Request::Typed do
444
- [:uri, :method, :headers, :body].each do |method|
445
- it "delegates ##{method} to the request" do
446
- request = double(method => "delegated value")
447
- expect(Request::Typed.new(request, :type).send(method)).to eq("delegated value")
448
- end
449
- end
450
-
451
- describe "#type" do
452
- it 'returns the initialized type' do
453
- expect(Request::Typed.new(double, :ignored).type).to be(:ignored)
454
- end
455
- end
456
-
457
- valid_types = [:ignored, :stubbed_by_vcr, :externally_stubbed, :recordable, :unhandled]
458
- valid_types.each do |type|
459
- describe "##{type}?" do
460
- it "returns true if the type is set to :#{type}" do
461
- expect(Request::Typed.new(double, type).send("#{type}?")).to be true
462
- end
463
-
464
- it "returns false if the type is set to :other" do
465
- expect(Request::Typed.new(double, :other).send("#{type}?")).to be false
466
- end
467
- end
468
- end
469
-
470
- describe "#real?" do
471
- real_types = [:ignored, :recordable]
472
- real_types.each do |type|
473
- it "returns true if the type is set to :#{type}" do
474
- expect(Request::Typed.new(double, type)).to be_real
475
- end
476
- end
477
-
478
- (valid_types - real_types).each do |type|
479
- it "returns false if the type is set to :#{type}" do
480
- expect(Request::Typed.new(double, type)).not_to be_real
481
- end
482
- end
483
- end
484
-
485
- describe "#stubbed?" do
486
- stubbed_types = [:externally_stubbed, :stubbed_by_vcr]
487
- stubbed_types.each do |type|
488
- it "returns true if the type is set to :#{type}" do
489
- expect(Request::Typed.new(double, type)).to be_stubbed
490
- end
491
- end
492
-
493
- (valid_types - stubbed_types).each do |type|
494
- it "returns false if the type is set to :#{type}" do
495
- expect(Request::Typed.new(double, type)).not_to be_stubbed
496
- end
497
- end
498
- end
499
- end
500
-
501
- describe Request do
502
- include_context "configuration stubbing"
503
-
504
- before do
505
- allow(config).to receive(:uri_parser) { LimitedURI }
506
- end
507
-
508
- describe '#method' do
509
- subject { VCR::Request.new(:get) }
510
-
511
- context 'when given no arguments' do
512
- it 'returns the HTTP method' do
513
- expect(subject.method).to eq(:get)
514
- end
515
- end
516
-
517
- context 'when given an argument' do
518
- it 'returns the method object for the named method' do
519
- m = subject.method(:class)
520
- expect(m).to be_a(Method)
521
- expect(m.call).to eq(described_class)
522
- end
523
- end
524
-
525
- it 'gets normalized to a lowercase symbol' do
526
- expect(VCR::Request.new("GET").method).to eq(:get)
527
- expect(VCR::Request.new(:GET).method).to eq(:get)
528
- expect(VCR::Request.new(:get).method).to eq(:get)
529
- expect(VCR::Request.new("get").method).to eq(:get)
530
- end
531
- end
532
-
533
- describe "#uri" do
534
- def uri_for(uri)
535
- VCR::Request.new(:get, uri).uri
536
- end
537
-
538
- it 'removes the default http port' do
539
- expect(uri_for("http://foo.com:80/bar")).to eq("http://foo.com/bar")
540
- end
541
-
542
- it 'removes the default https port' do
543
- expect(uri_for("https://foo.com:443/bar")).to eq("https://foo.com/bar")
544
- end
545
-
546
- it 'does not remove a non-standard http port' do
547
- expect(uri_for("http://foo.com:81/bar")).to eq("http://foo.com:81/bar")
548
- end
549
-
550
- it 'does not remove a non-standard https port' do
551
- expect(uri_for("https://foo.com:442/bar")).to eq("https://foo.com:442/bar")
552
- end
553
- end
554
-
555
- describe Request::FiberAware do
556
- subject { Request::FiberAware.new(Request.new) }
557
-
558
- it 'adds a #proceed method that yields in a fiber' do
559
- fiber = Fiber.new do |request|
560
- request.proceed
561
- :done
562
- end
563
-
564
- expect(fiber.resume(subject)).to be_nil
565
- expect(fiber.resume).to eq(:done)
566
- end
567
-
568
- it 'can be cast to a proc' do
569
- expect(Fiber).to receive(:yield)
570
- lambda(&subject).call
571
- end
572
- end if RUBY_VERSION > '1.9'
573
-
574
- it_behaves_like 'a header normalizer' do
575
- def with_headers(headers)
576
- described_class.new(:get, 'http://example.com/', nil, headers)
577
- end
578
- end
579
-
580
- it_behaves_like 'a body normalizer' do
581
- def instance(body)
582
- described_class.new(:get, 'http://example.com/', body, {})
583
- end
584
- end
585
- end
586
-
587
- describe Response do
588
- it_behaves_like 'a header normalizer' do
589
- def with_headers(headers)
590
- described_class.new(:status, headers, nil, '1.1')
591
- end
592
- end
593
-
594
- it_behaves_like 'a body normalizer' do
595
- def instance(body)
596
- described_class.new(:status, {}, body, '1.1')
597
- end
598
- end
599
-
600
- describe "#adapter_metadata" do
601
- it 'returns the hash given as the last #initialize argument' do
602
- response = Response.new(
603
- ResponseStatus.new(200, "OK"),
604
- {}, "the body", "1.1",
605
- { "meta" => "value" }
606
- )
607
-
608
- expect(response.adapter_metadata).to eq("meta" => "value")
609
- end
610
-
611
- it 'returns a blank hash when nil is passed to #initialize' do
612
- response = Response.new(
613
- ResponseStatus.new(200, "OK"),
614
- {}, "the body", "1.1", nil
615
- )
616
-
617
- expect(response.adapter_metadata).to eq({})
618
- end
619
- end
620
-
621
- describe '#update_content_length_header' do
622
- %w[ content-length Content-Length ].each do |header|
623
- context "for the #{header} header" do
624
- define_method :instance do |body, content_length|
625
- headers = { 'content-type' => 'text' }
626
- headers.merge!(header => content_length) if content_length
627
- described_class.new(VCR::ResponseStatus.new, headers, body)
628
- end
629
-
630
- it 'does nothing when the response lacks a content_length header' do
631
- inst = instance('the body', nil)
632
- expect {
633
- inst.update_content_length_header
634
- }.not_to change { inst.headers[header] }
635
- end
636
-
637
- it 'sets the content_length header to the response body length when the header is present' do
638
- inst = instance('the body', '3')
639
- expect {
640
- inst.update_content_length_header
641
- }.to change { inst.headers[header] }.from(['3']).to(['8'])
642
- end
643
-
644
- it 'sets the content_length header to 0 if the response body is nil' do
645
- inst = instance(nil, '3')
646
- expect {
647
- inst.update_content_length_header
648
- }.to change { inst.headers[header] }.from(['3']).to(['0'])
649
- end
650
-
651
- it 'sets the header according to RFC 2616 based on the number of bytes (not the number of characters)' do
652
- inst = instance('aؼ', '2') # the second char is a double byte char
653
- expect {
654
- inst.update_content_length_header
655
- }.to change { inst.headers[header] }.from(['2']).to(['3'])
656
- end
657
- end
658
- end
659
- end
660
-
661
- describe '#decompress' do
662
- %w[ content-encoding Content-Encoding ].each do |header|
663
- context "for the #{header} header" do
664
- define_method :instance do |body, content_encoding|
665
- headers = { 'content-type' => 'text',
666
- 'content-length' => body.bytesize.to_s }
667
- headers[header] = content_encoding if content_encoding
668
- described_class.new(VCR::ResponseStatus.new, headers, body)
669
- end
670
-
671
- let(:content) { 'The quick brown fox jumps over the lazy dog' }
672
-
673
- it "does nothing when no compression" do
674
- resp = instance('Hello', nil)
675
- expect(resp).not_to be_compressed
676
- expect {
677
- expect(resp.decompress).to equal(resp)
678
- }.to_not change { resp.headers['content-length'] }
679
- end
680
-
681
- it "does nothing when encoding is 'identity'" do
682
- resp = instance('Hello', 'identity')
683
- expect(resp).not_to be_compressed
684
- expect {
685
- expect(resp.decompress).to equal(resp)
686
- }.to_not change { resp.headers['content-length'] }
687
- end
688
-
689
- it "raises error for unrecognized encoding" do
690
- resp = instance('Hello', 'flabbergaster')
691
- expect(resp).not_to be_compressed
692
- expect { resp.decompress }.
693
- to raise_error(Errors::UnknownContentEncodingError, 'unknown content encoding: flabbergaster')
694
- end
695
-
696
- it "unzips gzipped response" do
697
- io = StringIO.new
698
-
699
- writer = Zlib::GzipWriter.new(io)
700
- writer << content
701
- writer.close
702
-
703
- gzipped = io.string
704
- resp = instance(gzipped, 'gzip')
705
- expect(resp).to be_compressed
706
- expect {
707
- expect(resp.decompress).to equal(resp)
708
- expect(resp).not_to be_compressed
709
- expect(resp.body).to eq(content)
710
- }.to change { resp.headers['content-length'] }.
711
- from([gzipped.bytesize.to_s]).
712
- to([content.bytesize.to_s])
713
- end
714
-
715
- it "inflates deflated response" do
716
- deflated = Zlib::Deflate.deflate(content)
717
- resp = instance(deflated, 'deflate')
718
- expect(resp).to be_compressed
719
- expect {
720
- expect(resp.decompress).to equal(resp)
721
- expect(resp).not_to be_compressed
722
- expect(resp.body).to eq(content)
723
- }.to change { resp.headers['content-length'] }.
724
- from([deflated.bytesize.to_s]).
725
- to([content.bytesize.to_s])
726
- end
727
- end
728
- end
729
- end
730
- end
731
- end
732
-