vcr 2.0.0.rc2 → 2.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.
- data/.travis.yml +2 -0
- data/CHANGELOG.md +19 -2
- data/README.md +17 -5
- data/Upgrade.md +33 -0
- data/benchmarks/http_stubbing_libraries.rb +2 -2
- data/features/getting_started.md +1 -1
- data/features/http_libraries/em_http_request.feature +6 -3
- data/lib/vcr.rb +46 -47
- data/lib/vcr/cassette.rb +16 -3
- data/lib/vcr/configuration.rb +146 -138
- data/lib/vcr/library_hooks/excon.rb +1 -1
- data/lib/vcr/library_hooks/faraday.rb +1 -1
- data/lib/vcr/middleware/faraday.rb +1 -1
- data/lib/vcr/structs.rb +79 -72
- data/lib/vcr/version.rb +1 -1
- data/spec/quality_spec.rb +51 -0
- data/spec/vcr/cassette/migrator_spec.rb +33 -33
- data/spec/vcr/configuration_spec.rb +13 -1
- data/spec/vcr/library_hooks/faraday_spec.rb +0 -1
- data/vcr.gemspec +4 -4
- metadata +51 -42
@@ -2,7 +2,7 @@ require 'vcr/util/version_checker'
|
|
2
2
|
require 'vcr/request_handler'
|
3
3
|
require 'excon'
|
4
4
|
|
5
|
-
VCR::VersionChecker.new('Excon', Excon::VERSION, '0.9.6', '0.
|
5
|
+
VCR::VersionChecker.new('Excon', Excon::VERSION, '0.9.6', '0.10').check_version!
|
6
6
|
|
7
7
|
module VCR
|
8
8
|
class LibraryHooks
|
@@ -2,7 +2,7 @@ require 'faraday'
|
|
2
2
|
require 'vcr/util/version_checker'
|
3
3
|
require 'vcr/request_handler'
|
4
4
|
|
5
|
-
VCR::VersionChecker.new('Faraday', Faraday::VERSION, '0.7.0', '0.
|
5
|
+
VCR::VersionChecker.new('Faraday', Faraday::VERSION, '0.7.0', '0.8').check_version!
|
6
6
|
|
7
7
|
module VCR
|
8
8
|
# Contains middlewares for use with different libraries.
|
data/lib/vcr/structs.rb
CHANGED
@@ -155,9 +155,15 @@ module VCR
|
|
155
155
|
include Normalizers::Body
|
156
156
|
|
157
157
|
def initialize(*args)
|
158
|
-
|
158
|
+
skip_port_stripping = false
|
159
|
+
if args.last == :skip_port_stripping
|
160
|
+
skip_port_stripping = true
|
161
|
+
args.pop
|
162
|
+
end
|
163
|
+
|
164
|
+
super(*args)
|
159
165
|
self.method = self.method.to_s.downcase.to_sym if self.method
|
160
|
-
self.uri = without_standard_port(self.uri)
|
166
|
+
self.uri = without_standard_port(self.uri) unless skip_port_stripping
|
161
167
|
end
|
162
168
|
|
163
169
|
# Builds a serializable hash from the request data.
|
@@ -184,7 +190,8 @@ module VCR
|
|
184
190
|
new method,
|
185
191
|
hash['uri'],
|
186
192
|
body_from(hash['body']),
|
187
|
-
hash['headers']
|
193
|
+
hash['headers'],
|
194
|
+
:skip_port_stripping
|
188
195
|
end
|
189
196
|
|
190
197
|
@@object_method = Object.instance_method(:method)
|
@@ -275,6 +282,75 @@ module VCR
|
|
275
282
|
end
|
276
283
|
end
|
277
284
|
|
285
|
+
# The response of an {HTTPInteraction}.
|
286
|
+
#
|
287
|
+
# @attr [ResponseStatus] status the status of the response
|
288
|
+
# @attr [Hash{String => Array<String>}] headers the response headers
|
289
|
+
# @attr [String] body the response body
|
290
|
+
# @attr [nil, String] http_version the HTTP version
|
291
|
+
class Response < Struct.new(:status, :headers, :body, :http_version)
|
292
|
+
include Normalizers::Header
|
293
|
+
include Normalizers::Body
|
294
|
+
|
295
|
+
# Builds a serializable hash from the response data.
|
296
|
+
#
|
297
|
+
# @return [Hash] hash that represents this response
|
298
|
+
# and can be easily serialized.
|
299
|
+
# @see Response.from_hash
|
300
|
+
def to_hash
|
301
|
+
{
|
302
|
+
'status' => status.to_hash,
|
303
|
+
'headers' => headers,
|
304
|
+
'body' => serializable_body,
|
305
|
+
'http_version' => http_version
|
306
|
+
}.tap { |h| OrderedHashSerializer.apply_to(h, members) }
|
307
|
+
end
|
308
|
+
|
309
|
+
# Constructs a new instance from a hash.
|
310
|
+
#
|
311
|
+
# @param [Hash] hash the hash to use to construct the instance.
|
312
|
+
# @return [Response] the response
|
313
|
+
def self.from_hash(hash)
|
314
|
+
new ResponseStatus.from_hash(hash.fetch('status', {})),
|
315
|
+
hash['headers'],
|
316
|
+
body_from(hash['body']),
|
317
|
+
hash['http_version']
|
318
|
+
end
|
319
|
+
|
320
|
+
# Updates the Content-Length response header so that it is
|
321
|
+
# accurate for the response body.
|
322
|
+
def update_content_length_header
|
323
|
+
value = body ? body.bytesize.to_s : '0'
|
324
|
+
key = %w[ Content-Length content-length ].find { |k| headers.has_key?(k) }
|
325
|
+
headers[key] = [value] if key
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# The response status of an {HTTPInteraction}.
|
330
|
+
#
|
331
|
+
# @attr [Integer] code the HTTP status code
|
332
|
+
# @attr [String] message the HTTP status message (e.g. "OK" for a status of 200)
|
333
|
+
class ResponseStatus < Struct.new(:code, :message)
|
334
|
+
# Builds a serializable hash from the response status data.
|
335
|
+
#
|
336
|
+
# @return [Hash] hash that represents this response status
|
337
|
+
# and can be easily serialized.
|
338
|
+
# @see ResponseStatus.from_hash
|
339
|
+
def to_hash
|
340
|
+
{
|
341
|
+
'code' => code, 'message' => message
|
342
|
+
}.tap { |h| OrderedHashSerializer.apply_to(h, members) }
|
343
|
+
end
|
344
|
+
|
345
|
+
# Constructs a new instance from a hash.
|
346
|
+
#
|
347
|
+
# @param [Hash] hash the hash to use to construct the instance.
|
348
|
+
# @return [ResponseStatus] the response status
|
349
|
+
def self.from_hash(hash)
|
350
|
+
new hash['code'], hash['message']
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
278
354
|
# Represents a single interaction over HTTP, containing a request and a response.
|
279
355
|
#
|
280
356
|
# @attr [Request] request the request
|
@@ -374,73 +450,4 @@ module VCR
|
|
374
450
|
end
|
375
451
|
end
|
376
452
|
end
|
377
|
-
|
378
|
-
# The response of an {HTTPInteraction}.
|
379
|
-
#
|
380
|
-
# @attr [ResponseStatus] status the status of the response
|
381
|
-
# @attr [Hash{String => Array<String>}] headers the response headers
|
382
|
-
# @attr [String] body the response body
|
383
|
-
# @attr [nil, String] http_version the HTTP version
|
384
|
-
class Response < Struct.new(:status, :headers, :body, :http_version)
|
385
|
-
include Normalizers::Header
|
386
|
-
include Normalizers::Body
|
387
|
-
|
388
|
-
# Builds a serializable hash from the response data.
|
389
|
-
#
|
390
|
-
# @return [Hash] hash that represents this response
|
391
|
-
# and can be easily serialized.
|
392
|
-
# @see Response.from_hash
|
393
|
-
def to_hash
|
394
|
-
{
|
395
|
-
'status' => status.to_hash,
|
396
|
-
'headers' => headers,
|
397
|
-
'body' => serializable_body,
|
398
|
-
'http_version' => http_version
|
399
|
-
}.tap { |h| OrderedHashSerializer.apply_to(h, members) }
|
400
|
-
end
|
401
|
-
|
402
|
-
# Constructs a new instance from a hash.
|
403
|
-
#
|
404
|
-
# @param [Hash] hash the hash to use to construct the instance.
|
405
|
-
# @return [Response] the response
|
406
|
-
def self.from_hash(hash)
|
407
|
-
new ResponseStatus.from_hash(hash.fetch('status', {})),
|
408
|
-
hash['headers'],
|
409
|
-
body_from(hash['body']),
|
410
|
-
hash['http_version']
|
411
|
-
end
|
412
|
-
|
413
|
-
# Updates the Content-Length response header so that it is
|
414
|
-
# accurate for the response body.
|
415
|
-
def update_content_length_header
|
416
|
-
value = body ? body.bytesize.to_s : '0'
|
417
|
-
key = %w[ Content-Length content-length ].find { |k| headers.has_key?(k) }
|
418
|
-
headers[key] = [value] if key
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
# The response status of an {HTTPInteraction}.
|
423
|
-
#
|
424
|
-
# @attr [Integer] code the HTTP status code
|
425
|
-
# @attr [String] message the HTTP status message (e.g. "OK" for a status of 200)
|
426
|
-
class ResponseStatus < Struct.new(:code, :message)
|
427
|
-
# Builds a serializable hash from the response status data.
|
428
|
-
#
|
429
|
-
# @return [Hash] hash that represents this response status
|
430
|
-
# and can be easily serialized.
|
431
|
-
# @see ResponseStatus.from_hash
|
432
|
-
def to_hash
|
433
|
-
{
|
434
|
-
'code' => code, 'message' => message
|
435
|
-
}.tap { |h| OrderedHashSerializer.apply_to(h, members) }
|
436
|
-
end
|
437
|
-
|
438
|
-
# Constructs a new instance from a hash.
|
439
|
-
#
|
440
|
-
# @param [Hash] hash the hash to use to construct the instance.
|
441
|
-
# @return [ResponseStatus] the response status
|
442
|
-
def self.from_hash(hash)
|
443
|
-
new hash['code'], hash['message']
|
444
|
-
end
|
445
|
-
end
|
446
453
|
end
|
data/lib/vcr/version.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Borrowed from:
|
2
|
+
# https://github.com/carlhuda/bundler/blob/v1.1.rc.7/spec/quality_spec.rb
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "The library itself" do
|
6
|
+
def check_for_tab_characters(filename)
|
7
|
+
failing_lines = []
|
8
|
+
File.readlines(filename).each_with_index do |line,number|
|
9
|
+
failing_lines << number + 1 if line =~ /\t/
|
10
|
+
end
|
11
|
+
|
12
|
+
unless failing_lines.empty?
|
13
|
+
"#{filename} has tab characters on lines #{failing_lines.join(', ')}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_for_extra_spaces(filename)
|
18
|
+
failing_lines = []
|
19
|
+
File.readlines(filename).each_with_index do |line,number|
|
20
|
+
next if line =~ /^\s+#.*\s+\n$/
|
21
|
+
failing_lines << number + 1 if line =~ /\s+\n$/
|
22
|
+
end
|
23
|
+
|
24
|
+
unless failing_lines.empty?
|
25
|
+
"#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec::Matchers.define :be_well_formed do
|
30
|
+
failure_message_for_should do |actual|
|
31
|
+
actual.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
match do |actual|
|
35
|
+
actual.empty?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "has no malformed whitespace" do
|
40
|
+
error_messages = []
|
41
|
+
Dir.chdir(File.expand_path("../..", __FILE__)) do
|
42
|
+
`git ls-files`.split("\n").each do |filename|
|
43
|
+
next if filename =~ /vendor|.feature|.yml|.gitmodules/
|
44
|
+
error_messages << check_for_tab_characters(filename)
|
45
|
+
error_messages << check_for_extra_spaces(filename)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
error_messages.compact.should be_well_formed
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -3,38 +3,38 @@ require 'vcr/cassette/migrator'
|
|
3
3
|
|
4
4
|
describe VCR::Cassette::Migrator do
|
5
5
|
let(:original_contents) { <<-EOF
|
6
|
-
---
|
7
|
-
- !ruby/struct:VCR::HTTPInteraction
|
8
|
-
request: !ruby/struct:VCR::Request
|
6
|
+
---
|
7
|
+
- !ruby/struct:VCR::HTTPInteraction
|
8
|
+
request: !ruby/struct:VCR::Request
|
9
9
|
method: :get
|
10
10
|
uri: http://example.com:80/foo
|
11
|
-
body:
|
12
|
-
headers:
|
13
|
-
response: !ruby/struct:VCR::Response
|
14
|
-
status: !ruby/struct:VCR::ResponseStatus
|
11
|
+
body:
|
12
|
+
headers:
|
13
|
+
response: !ruby/struct:VCR::Response
|
14
|
+
status: !ruby/struct:VCR::ResponseStatus
|
15
15
|
code: 200
|
16
16
|
message: OK
|
17
|
-
headers:
|
18
|
-
content-type:
|
17
|
+
headers:
|
18
|
+
content-type:
|
19
19
|
- text/html;charset=utf-8
|
20
|
-
content-length:
|
20
|
+
content-length:
|
21
21
|
- "9"
|
22
22
|
body: Hello foo
|
23
23
|
http_version: "1.1"
|
24
|
-
- !ruby/struct:VCR::HTTPInteraction
|
25
|
-
request: !ruby/struct:VCR::Request
|
24
|
+
- !ruby/struct:VCR::HTTPInteraction
|
25
|
+
request: !ruby/struct:VCR::Request
|
26
26
|
method: :get
|
27
27
|
uri: http://localhost:7777/bar
|
28
|
-
body:
|
29
|
-
headers:
|
30
|
-
response: !ruby/struct:VCR::Response
|
31
|
-
status: !ruby/struct:VCR::ResponseStatus
|
28
|
+
body:
|
29
|
+
headers:
|
30
|
+
response: !ruby/struct:VCR::Response
|
31
|
+
status: !ruby/struct:VCR::ResponseStatus
|
32
32
|
code: 200
|
33
33
|
message: OK
|
34
|
-
headers:
|
35
|
-
content-type:
|
34
|
+
headers:
|
35
|
+
content-type:
|
36
36
|
- text/html;charset=utf-8
|
37
|
-
content-length:
|
37
|
+
content-length:
|
38
38
|
- "9"
|
39
39
|
body: Hello bar
|
40
40
|
http_version: "1.1"
|
@@ -42,9 +42,9 @@ EOF
|
|
42
42
|
}
|
43
43
|
|
44
44
|
let(:updated_contents) { <<-EOF
|
45
|
-
---
|
46
|
-
http_interactions:
|
47
|
-
- request:
|
45
|
+
---
|
46
|
+
http_interactions:
|
47
|
+
- request:
|
48
48
|
method: get
|
49
49
|
uri: http://example.com/foo
|
50
50
|
body:
|
@@ -52,21 +52,21 @@ http_interactions:
|
|
52
52
|
string: ""
|
53
53
|
headers: {}
|
54
54
|
|
55
|
-
response:
|
56
|
-
status:
|
55
|
+
response:
|
56
|
+
status:
|
57
57
|
code: 200
|
58
58
|
message: OK
|
59
|
-
headers:
|
60
|
-
Content-Type:
|
59
|
+
headers:
|
60
|
+
Content-Type:
|
61
61
|
- text/html;charset=utf-8
|
62
|
-
Content-Length:
|
62
|
+
Content-Length:
|
63
63
|
- "9"
|
64
64
|
body:
|
65
65
|
encoding: UTF-8
|
66
66
|
string: Hello foo
|
67
67
|
http_version: "1.1"
|
68
68
|
recorded_at: Wed, 04 May 2011 12:30:00 GMT
|
69
|
-
- request:
|
69
|
+
- request:
|
70
70
|
method: get
|
71
71
|
uri: http://localhost:7777/bar
|
72
72
|
body:
|
@@ -74,14 +74,14 @@ http_interactions:
|
|
74
74
|
string: ""
|
75
75
|
headers: {}
|
76
76
|
|
77
|
-
response:
|
78
|
-
status:
|
77
|
+
response:
|
78
|
+
status:
|
79
79
|
code: 200
|
80
80
|
message: OK
|
81
|
-
headers:
|
82
|
-
Content-Type:
|
81
|
+
headers:
|
82
|
+
Content-Type:
|
83
83
|
- text/html;charset=utf-8
|
84
|
-
Content-Length:
|
84
|
+
Content-Length:
|
85
85
|
- "9"
|
86
86
|
body:
|
87
87
|
encoding: UTF-8
|
@@ -117,7 +117,7 @@ describe VCR::Configuration do
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
describe "
|
120
|
+
describe "request/configuration interactions", :with_monkey_patches => :fakeweb do
|
121
121
|
specify 'the request on the yielded interaction is not typed even though the request given to before_http_request is' do
|
122
122
|
before_record_req = before_request_req = nil
|
123
123
|
VCR.configure do |c|
|
@@ -132,6 +132,18 @@ describe VCR::Configuration do
|
|
132
132
|
before_record_req.should_not respond_to(:type)
|
133
133
|
before_request_req.should respond_to(:type)
|
134
134
|
end unless RUBY_VERSION =~ /^1\.8/
|
135
|
+
|
136
|
+
specify 'the filter_sensitive_data option works even when it modifies the URL in a way that makes it an invalid URI' do
|
137
|
+
VCR.configure do |c|
|
138
|
+
c.filter_sensitive_data('<HOST>') { 'localhost' }
|
139
|
+
end
|
140
|
+
|
141
|
+
2.times do
|
142
|
+
VCR.use_cassette("example") do
|
143
|
+
::Net::HTTP.get_response(URI("http://localhost:#{VCR::SinatraApp.port}/foo"))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
135
147
|
end
|
136
148
|
|
137
149
|
[:before_record, :before_playback].each do |hook_type|
|
data/vcr.gemspec
CHANGED
@@ -29,23 +29,23 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency 'fakeweb', '~> 1.3.0'
|
30
30
|
s.add_development_dependency 'webmock', '~> 1.8.0'
|
31
31
|
|
32
|
-
s.add_development_dependency 'faraday', '~> 0.
|
32
|
+
s.add_development_dependency 'faraday', '~> 0.8.0.rc2'
|
33
33
|
s.add_development_dependency 'httpclient', '~> 2.1.5.2'
|
34
|
-
s.add_development_dependency 'excon', '
|
34
|
+
s.add_development_dependency 'excon', '>= 0.9.6', '< 1.0'
|
35
35
|
|
36
36
|
s.add_development_dependency 'timecop', '~> 0.3.5'
|
37
37
|
s.add_development_dependency 'rack', '~> 1.3.6'
|
38
38
|
s.add_development_dependency 'sinatra', '~> 1.3.2'
|
39
39
|
s.add_development_dependency 'multi_json', '~> 1.0.3'
|
40
|
-
s.add_development_dependency 'yajl-ruby', '~> 1.1.0'
|
41
40
|
s.add_development_dependency 'json', '~> 1.6.5'
|
42
41
|
s.add_development_dependency 'limited_red', '~> 0.3.7'
|
43
42
|
s.add_development_dependency 'simplecov', '~> 0.5.3'
|
44
43
|
|
45
44
|
unless RUBY_PLATFORM == 'java'
|
46
45
|
s.add_development_dependency 'patron', '~> 0.4.15'
|
47
|
-
s.add_development_dependency 'em-http-request', '~> 0.
|
46
|
+
s.add_development_dependency 'em-http-request', '~> 1.0.1'
|
48
47
|
s.add_development_dependency 'curb', '~> 0.8.0'
|
49
48
|
s.add_development_dependency 'typhoeus', '~> 0.3.3'
|
49
|
+
s.add_development_dependency 'yajl-ruby', '~> 1.1.0'
|
50
50
|
end
|
51
51
|
end
|