vcr 3.0.3 → 4.0.0

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.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vcr.rb +18 -1
  3. data/lib/vcr/cassette.rb +11 -3
  4. data/lib/vcr/cassette/persisters/file_system.rb +1 -1
  5. data/lib/vcr/configuration.rb +3 -5
  6. data/lib/vcr/deprecations.rb +0 -62
  7. data/lib/vcr/errors.rb +16 -0
  8. data/lib/vcr/library_hooks/typhoeus.rb +37 -8
  9. data/lib/vcr/middleware/faraday.rb +5 -1
  10. data/lib/vcr/structs.rb +1 -1
  11. data/lib/vcr/util/hooks.rb +1 -0
  12. data/lib/vcr/version.rb +1 -1
  13. metadata +9 -249
  14. data/features/CHANGELOG.md +0 -710
  15. data/features/CONTRIBUTING.md +0 -26
  16. data/features/LICENSE.md +0 -20
  17. data/features/README.md +0 -339
  18. data/features/Upgrade.md +0 -289
  19. data/features/about_these_examples.md +0 -18
  20. data/features/cassettes/allow_unused_http_interactions.feature +0 -100
  21. data/features/cassettes/automatic_re_recording.feature +0 -72
  22. data/features/cassettes/decompress.feature +0 -74
  23. data/features/cassettes/dynamic_erb.feature +0 -100
  24. data/features/cassettes/exclusive.feature +0 -126
  25. data/features/cassettes/format.feature +0 -411
  26. data/features/cassettes/freezing_time.feature +0 -68
  27. data/features/cassettes/naming.feature +0 -28
  28. data/features/cassettes/no_cassette.feature +0 -152
  29. data/features/cassettes/update_content_length_header.feature +0 -112
  30. data/features/configuration/allow_http_connections_when_no_cassette.feature +0 -55
  31. data/features/configuration/cassette_library_dir.feature +0 -31
  32. data/features/configuration/debug_logging.feature +0 -58
  33. data/features/configuration/default_cassette_options.feature +0 -100
  34. data/features/configuration/filter_sensitive_data.feature +0 -153
  35. data/features/configuration/hook_into.feature +0 -172
  36. data/features/configuration/ignore_request.feature +0 -192
  37. data/features/configuration/preserve_exact_body_bytes.feature +0 -108
  38. data/features/configuration/query_parser.feature +0 -84
  39. data/features/configuration/uri_parser.feature +0 -93
  40. data/features/getting_started.md +0 -82
  41. data/features/hooks/after_http_request.feature +0 -58
  42. data/features/hooks/around_http_request.feature +0 -57
  43. data/features/hooks/before_http_request.feature +0 -63
  44. data/features/hooks/before_playback.feature +0 -184
  45. data/features/hooks/before_record.feature +0 -172
  46. data/features/http_libraries/em_http_request.feature +0 -250
  47. data/features/http_libraries/net_http.feature +0 -179
  48. data/features/middleware/faraday.feature +0 -56
  49. data/features/middleware/rack.feature +0 -92
  50. data/features/record_modes/all.feature +0 -82
  51. data/features/record_modes/new_episodes.feature +0 -79
  52. data/features/record_modes/none.feature +0 -72
  53. data/features/record_modes/once.feature +0 -95
  54. data/features/request_matching/README.md +0 -30
  55. data/features/request_matching/body.feature +0 -91
  56. data/features/request_matching/body_as_json.feature +0 -90
  57. data/features/request_matching/custom_matcher.feature +0 -135
  58. data/features/request_matching/headers.feature +0 -85
  59. data/features/request_matching/host.feature +0 -95
  60. data/features/request_matching/identical_request_sequence.feature +0 -89
  61. data/features/request_matching/method.feature +0 -96
  62. data/features/request_matching/path.feature +0 -96
  63. data/features/request_matching/playback_repeats.feature +0 -98
  64. data/features/request_matching/query.feature +0 -97
  65. data/features/request_matching/uri.feature +0 -94
  66. data/features/request_matching/uri_without_param.feature +0 -101
  67. data/features/step_definitions/cli_steps.rb +0 -199
  68. data/features/support/env.rb +0 -46
  69. data/features/support/http_lib_filters.rb +0 -46
  70. data/features/test_frameworks/cucumber.feature +0 -211
  71. data/features/test_frameworks/rspec_macro.feature +0 -81
  72. data/features/test_frameworks/rspec_metadata.feature +0 -150
  73. data/features/test_frameworks/test_unit.feature +0 -49
  74. data/lib/vcr/extensions/net_http_response.rb +0 -36
  75. data/lib/vcr/library_hooks/fakeweb.rb +0 -197
  76. data/spec/acceptance/concurrency_spec.rb +0 -51
  77. data/spec/acceptance/threading_spec.rb +0 -34
  78. data/spec/fixtures/cassette_spec/1_x_cassette.yml +0 -110
  79. data/spec/fixtures/cassette_spec/empty.yml +0 -0
  80. data/spec/fixtures/cassette_spec/example.yml +0 -111
  81. data/spec/fixtures/cassette_spec/with_localhost_requests.yml +0 -111
  82. data/spec/fixtures/fake_example_responses.yml +0 -110
  83. data/spec/fixtures/match_requests_on.yml +0 -187
  84. data/spec/lib/vcr/cassette/erb_renderer_spec.rb +0 -53
  85. data/spec/lib/vcr/cassette/http_interaction_list_spec.rb +0 -295
  86. data/spec/lib/vcr/cassette/migrator_spec.rb +0 -196
  87. data/spec/lib/vcr/cassette/persisters/file_system_spec.rb +0 -75
  88. data/spec/lib/vcr/cassette/persisters_spec.rb +0 -39
  89. data/spec/lib/vcr/cassette/serializers_spec.rb +0 -182
  90. data/spec/lib/vcr/cassette_spec.rb +0 -618
  91. data/spec/lib/vcr/configuration_spec.rb +0 -326
  92. data/spec/lib/vcr/deprecations_spec.rb +0 -85
  93. data/spec/lib/vcr/errors_spec.rb +0 -178
  94. data/spec/lib/vcr/extensions/net_http_response_spec.rb +0 -86
  95. data/spec/lib/vcr/library_hooks/excon_spec.rb +0 -104
  96. data/spec/lib/vcr/library_hooks/fakeweb_spec.rb +0 -169
  97. data/spec/lib/vcr/library_hooks/faraday_spec.rb +0 -68
  98. data/spec/lib/vcr/library_hooks/typhoeus_0.4_spec.rb +0 -36
  99. data/spec/lib/vcr/library_hooks/typhoeus_spec.rb +0 -162
  100. data/spec/lib/vcr/library_hooks/webmock_spec.rb +0 -117
  101. data/spec/lib/vcr/library_hooks_spec.rb +0 -51
  102. data/spec/lib/vcr/middleware/faraday_spec.rb +0 -181
  103. data/spec/lib/vcr/middleware/rack_spec.rb +0 -115
  104. data/spec/lib/vcr/request_ignorer_spec.rb +0 -70
  105. data/spec/lib/vcr/request_matcher_registry_spec.rb +0 -345
  106. data/spec/lib/vcr/structs_spec.rb +0 -732
  107. data/spec/lib/vcr/test_frameworks/cucumber_spec.rb +0 -107
  108. data/spec/lib/vcr/test_frameworks/rspec_spec.rb +0 -94
  109. data/spec/lib/vcr/util/hooks_spec.rb +0 -158
  110. data/spec/lib/vcr/util/internet_connection_spec.rb +0 -37
  111. data/spec/lib/vcr/util/version_checker_spec.rb +0 -31
  112. data/spec/lib/vcr/version_spec.rb +0 -27
  113. data/spec/lib/vcr_spec.rb +0 -354
  114. data/spec/monkey_patches.rb +0 -186
  115. data/spec/spec_helper.rb +0 -63
  116. data/spec/support/configuration_stubbing.rb +0 -8
  117. data/spec/support/cucumber_helpers.rb +0 -39
  118. data/spec/support/fixnum_extension.rb +0 -10
  119. data/spec/support/http_library_adapters.rb +0 -289
  120. data/spec/support/limited_uri.rb +0 -21
  121. data/spec/support/ruby_interpreter.rb +0 -7
  122. data/spec/support/shared_example_groups/excon.rb +0 -63
  123. data/spec/support/shared_example_groups/hook_into_http_library.rb +0 -594
  124. data/spec/support/shared_example_groups/request_hooks.rb +0 -59
  125. data/spec/support/sinatra_app.rb +0 -86
  126. data/spec/support/vcr_localhost_server.rb +0 -76
  127. 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
-