vcr 4.0.0 → 6.1.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.
- checksums.yaml +5 -5
- data/lib/vcr/cassette/erb_renderer.rb +4 -2
- data/lib/vcr/cassette/http_interaction_list.rb +14 -9
- data/lib/vcr/cassette/migrator.rb +5 -6
- data/lib/vcr/cassette/persisters/file_system.rb +9 -1
- data/lib/vcr/cassette/serializers/compressed.rb +2 -2
- data/lib/vcr/cassette/serializers/json.rb +14 -8
- data/lib/vcr/cassette/serializers/psych.rb +10 -2
- data/lib/vcr/cassette/serializers/syck.rb +7 -1
- data/lib/vcr/cassette/serializers/yaml.rb +14 -2
- data/lib/vcr/cassette/serializers.rb +10 -0
- data/lib/vcr/cassette.rb +41 -14
- data/lib/vcr/configuration.rb +17 -3
- data/lib/vcr/errors.rb +1 -12
- data/lib/vcr/library_hooks/excon.rb +8 -0
- data/lib/vcr/library_hooks/typhoeus.rb +94 -111
- data/lib/vcr/library_hooks/webmock.rb +2 -11
- data/lib/vcr/linked_cassette.rb +4 -4
- data/lib/vcr/middleware/excon.rb +1 -1
- data/lib/vcr/middleware/faraday.rb +5 -0
- data/lib/vcr/request_ignorer.rb +8 -1
- data/lib/vcr/request_matcher_registry.rb +3 -3
- data/lib/vcr/structs.rb +47 -31
- data/lib/vcr/test_frameworks/cucumber.rb +16 -5
- data/lib/vcr/test_frameworks/rspec.rb +34 -22
- data/lib/vcr/util/internet_connection.rb +15 -21
- data/lib/vcr/version.rb +2 -2
- data/lib/vcr.rb +44 -11
- metadata +50 -37
- data/lib/vcr/library_hooks/typhoeus_0.4.rb +0 -103
@@ -2,137 +2,121 @@ require 'vcr/util/version_checker'
|
|
2
2
|
require 'vcr/request_handler'
|
3
3
|
require 'typhoeus'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
module VCR
|
11
|
-
class LibraryHooks
|
5
|
+
module VCR
|
6
|
+
class LibraryHooks
|
7
|
+
# @private
|
8
|
+
module Typhoeus
|
12
9
|
# @private
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
request.block_connection = false if VCR.turned_on?
|
20
|
-
end
|
21
|
-
|
22
|
-
def vcr_request
|
23
|
-
@vcr_request ||= VCR::Request.new \
|
24
|
-
request.options.fetch(:method, :get),
|
25
|
-
request.url,
|
26
|
-
request_body,
|
27
|
-
request.options.fetch(:headers, {})
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
10
|
+
class RequestHandler < ::VCR::RequestHandler
|
11
|
+
attr_reader :request
|
12
|
+
def initialize(request)
|
13
|
+
@request = request
|
14
|
+
request.block_connection = false if VCR.turned_on?
|
15
|
+
end
|
31
16
|
|
32
|
-
|
33
|
-
|
34
|
-
|
17
|
+
def vcr_request
|
18
|
+
@vcr_request ||= VCR::Request.new \
|
19
|
+
request.options.fetch(:method, :get),
|
20
|
+
request.url,
|
21
|
+
request.encoded_body,
|
22
|
+
request.options.fetch(:headers, {})
|
23
|
+
end
|
35
24
|
|
36
|
-
|
37
|
-
super
|
38
|
-
request.instance_variable_set(:@__typed_vcr_request, @after_hook_typed_request)
|
39
|
-
end
|
25
|
+
private
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
27
|
+
def externally_stubbed?
|
28
|
+
::Typhoeus::Expectation.find_by(request)
|
29
|
+
end
|
45
30
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
:status_message => stubbed_response.status.message,
|
51
|
-
:headers => stubbed_response_headers,
|
52
|
-
:body => stubbed_response.body,
|
53
|
-
:effective_url => stubbed_response.adapter_metadata.fetch('effective_url', request.url),
|
54
|
-
:mock => true
|
55
|
-
|
56
|
-
first_header_line = "HTTP/#{stubbed_response.http_version} #{response.code} #{response.status_message}\r\n"
|
57
|
-
response.instance_variable_set(:@first_header_line, first_header_line)
|
58
|
-
response.instance_variable_get(:@options)[:response_headers] =
|
59
|
-
first_header_line + response.headers.map { |k,v| "#{k}: #{v}"}.join("\r\n")
|
60
|
-
|
61
|
-
response
|
62
|
-
end
|
31
|
+
def set_typed_request_for_after_hook(*args)
|
32
|
+
super
|
33
|
+
request.instance_variable_set(:@__typed_vcr_request, @after_hook_typed_request)
|
34
|
+
end
|
63
35
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end if stubbed_response.headers
|
69
|
-
end
|
70
|
-
end
|
36
|
+
def on_unhandled_request
|
37
|
+
invoke_after_request_hook(nil)
|
38
|
+
super
|
39
|
+
end
|
71
40
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
41
|
+
def on_stubbed_by_vcr_request
|
42
|
+
response = ::Typhoeus::Response.new \
|
43
|
+
:http_version => stubbed_response.http_version,
|
44
|
+
:code => stubbed_response.status.code,
|
45
|
+
:status_message => stubbed_response.status.message,
|
46
|
+
:headers => stubbed_response_headers,
|
47
|
+
:body => stubbed_response.body,
|
48
|
+
:effective_url => stubbed_response.adapter_metadata.fetch('effective_url', request.url),
|
49
|
+
:mock => true
|
50
|
+
|
51
|
+
first_header_line = "HTTP/#{stubbed_response.http_version} #{response.code} #{response.status_message}\r\n"
|
52
|
+
response.instance_variable_set(:@first_header_line, first_header_line)
|
53
|
+
response.instance_variable_get(:@options)[:response_headers] =
|
54
|
+
first_header_line + response.headers.map { |k,v| "#{k}: #{v}"}.join("\r\n")
|
55
|
+
|
56
|
+
response
|
81
57
|
end
|
82
58
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
response.headers,
|
89
|
-
response.body,
|
90
|
-
response.http_version,
|
91
|
-
{ "effective_url" => response.effective_url }
|
59
|
+
def stubbed_response_headers
|
60
|
+
@stubbed_response_headers ||= {}.tap do |hash|
|
61
|
+
stubbed_response.headers.each do |key, values|
|
62
|
+
hash[key] = values.size == 1 ? values.first : values
|
63
|
+
end if stubbed_response.headers
|
92
64
|
end
|
65
|
+
end
|
66
|
+
end
|
93
67
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
68
|
+
# @private
|
69
|
+
class << self
|
70
|
+
def vcr_response_from(response)
|
71
|
+
VCR::Response.new \
|
72
|
+
VCR::ResponseStatus.new(response.code, response.status_message),
|
73
|
+
response.headers,
|
74
|
+
response.body,
|
75
|
+
response.http_version,
|
76
|
+
{ "effective_url" => response.effective_url }
|
77
|
+
end
|
103
78
|
|
104
|
-
|
105
|
-
|
106
|
-
|
79
|
+
def collect_chunks(request)
|
80
|
+
chunks = ''
|
81
|
+
request.on_body.unshift(
|
82
|
+
Proc.new do |body, response|
|
83
|
+
chunks += body
|
84
|
+
request.instance_variable_set(:@chunked_body, chunks)
|
85
|
+
end
|
86
|
+
)
|
107
87
|
end
|
108
88
|
|
109
|
-
|
110
|
-
|
89
|
+
def restore_body_from_chunks(response, request)
|
90
|
+
response.options[:response_body] = request.instance_variable_get(:@chunked_body)
|
91
|
+
end
|
92
|
+
end
|
111
93
|
|
112
|
-
|
94
|
+
::Typhoeus.on_complete do |response|
|
95
|
+
request = response.request
|
113
96
|
|
114
|
-
|
115
|
-
vcr_response = vcr_response_from(response)
|
116
|
-
typed_vcr_request = request.send(:remove_instance_variable, :@__typed_vcr_request)
|
97
|
+
restore_body_from_chunks(response, request) if request.streaming?
|
117
98
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
99
|
+
unless VCR.library_hooks.disabled?(:typhoeus)
|
100
|
+
vcr_response = vcr_response_from(response)
|
101
|
+
typed_vcr_request = request.send(:remove_instance_variable, :@__typed_vcr_request)
|
122
102
|
|
123
|
-
|
103
|
+
unless request.response.mock
|
104
|
+
http_interaction = VCR::HTTPInteraction.new(typed_vcr_request, vcr_response)
|
105
|
+
VCR.record_http_interaction(http_interaction)
|
124
106
|
end
|
107
|
+
|
108
|
+
VCR.configuration.invoke_hook(:after_http_request, typed_vcr_request, vcr_response)
|
125
109
|
end
|
110
|
+
end
|
126
111
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
112
|
+
::Typhoeus.before do |request|
|
113
|
+
collect_chunks(request) if request.streaming?
|
114
|
+
if response = VCR::LibraryHooks::Typhoeus::RequestHandler.new(request).handle
|
115
|
+
request.on_headers.each { |cb| cb.call(response) }
|
116
|
+
request.on_body.each { |cb| cb.call(response.body, response) }
|
117
|
+
request.finish(response)
|
118
|
+
else
|
119
|
+
true
|
136
120
|
end
|
137
121
|
end
|
138
122
|
end
|
@@ -146,4 +130,3 @@ VCR.configuration.after_library_hooks_loaded do
|
|
146
130
|
WebMock::HttpLibAdapters::TyphoeusAdapter.disable!
|
147
131
|
end
|
148
132
|
end
|
149
|
-
|
@@ -12,8 +12,6 @@ module VCR
|
|
12
12
|
module WebMock
|
13
13
|
extend self
|
14
14
|
|
15
|
-
@global_hook_disabled_requests = {}
|
16
|
-
|
17
15
|
def with_global_hook_disabled(request)
|
18
16
|
global_hook_disabled_requests << request
|
19
17
|
|
@@ -25,19 +23,12 @@ module VCR
|
|
25
23
|
end
|
26
24
|
|
27
25
|
def global_hook_disabled?(request)
|
28
|
-
requests =
|
26
|
+
requests = Thread.current[:_vcr_webmock_disabled_requests]
|
29
27
|
requests && requests.include?(request)
|
30
28
|
end
|
31
29
|
|
32
30
|
def global_hook_disabled_requests
|
33
|
-
|
34
|
-
return requests if requests
|
35
|
-
|
36
|
-
ObjectSpace.define_finalizer(Thread.current, lambda {
|
37
|
-
@global_hook_disabled_requests.delete(Thread.current.object_id)
|
38
|
-
})
|
39
|
-
|
40
|
-
@global_hook_disabled_requests[Thread.current.object_id] = []
|
31
|
+
Thread.current[:_vcr_webmock_disabled_requests] ||= []
|
41
32
|
end
|
42
33
|
|
43
34
|
# @private
|
data/lib/vcr/linked_cassette.rb
CHANGED
@@ -9,8 +9,8 @@ module VCR
|
|
9
9
|
include Enumerable
|
10
10
|
|
11
11
|
# Creates a new list of context-owned cassettes and linked cassettes
|
12
|
-
# @param [Array] context-owned cassettes
|
13
|
-
# @param [Array] context-unowned (linked) cassettes
|
12
|
+
# @param cassettes [Array] context-owned cassettes
|
13
|
+
# @param linked_cassettes [Array] context-unowned (linked) cassettes
|
14
14
|
def initialize(cassettes, linked_cassettes)
|
15
15
|
@cassettes = cassettes
|
16
16
|
@linked_cassettes = linked_cassettes
|
@@ -52,8 +52,8 @@ module VCR
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# Create a new CassetteList
|
55
|
-
# @param [Array] context-owned cassettes
|
56
|
-
# @param [Array] context-unowned (linked) cassettes
|
55
|
+
# @param cassettes [Array] context-owned cassettes
|
56
|
+
# @param linked_cassettes [Array] context-unowned (linked) cassettes
|
57
57
|
def self.list(cassettes, linked_cassettes)
|
58
58
|
CassetteList.new(cassettes, linked_cassettes)
|
59
59
|
end
|
data/lib/vcr/middleware/excon.rb
CHANGED
data/lib/vcr/request_ignorer.rb
CHANGED
@@ -25,10 +25,18 @@ module VCR
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
def localhost_ignored?
|
29
|
+
(LOCALHOST_ALIASES & ignore_hosts.to_a).any?
|
30
|
+
end
|
31
|
+
|
28
32
|
def ignore_hosts(*hosts)
|
29
33
|
ignored_hosts.merge(hosts)
|
30
34
|
end
|
31
35
|
|
36
|
+
def unignore_hosts(*hosts)
|
37
|
+
ignored_hosts.subtract(hosts)
|
38
|
+
end
|
39
|
+
|
32
40
|
def ignore?(request)
|
33
41
|
invoke_hook(:ignore_request, request).any?
|
34
42
|
end
|
@@ -40,4 +48,3 @@ module VCR
|
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
43
|
-
|
@@ -110,12 +110,12 @@ module VCR
|
|
110
110
|
|
111
111
|
def register_built_ins
|
112
112
|
register(:method) { |r1, r2| r1.method == r2.method }
|
113
|
-
register(:uri) { |r1, r2| r1.
|
113
|
+
register(:uri) { |r1, r2| r1.parsed_uri == r2.parsed_uri }
|
114
114
|
register(:body) { |r1, r2| r1.body == r2.body }
|
115
115
|
register(:headers) { |r1, r2| r1.headers == r2.headers }
|
116
116
|
|
117
117
|
register(:host) do |r1, r2|
|
118
|
-
r1.parsed_uri.host == r2.parsed_uri.host
|
118
|
+
r1.parsed_uri.host.chomp('.') == r2.parsed_uri.host.chomp('.')
|
119
119
|
end
|
120
120
|
register(:path) do |r1, r2|
|
121
121
|
r1.parsed_uri.path == r2.parsed_uri.path
|
@@ -138,7 +138,7 @@ module VCR
|
|
138
138
|
|
139
139
|
register(:body_as_json) do |r1, r2|
|
140
140
|
begin
|
141
|
-
JSON.parse(r1.body) == JSON.parse(r2.body)
|
141
|
+
r1.body == r2.body || JSON.parse(r1.body) == JSON.parse(r2.body)
|
142
142
|
rescue JSON::ParserError
|
143
143
|
false
|
144
144
|
end
|
data/lib/vcr/structs.rb
CHANGED
@@ -62,7 +62,7 @@ module VCR
|
|
62
62
|
super
|
63
63
|
|
64
64
|
if body && !body.is_a?(String)
|
65
|
-
raise ArgumentError, "#{self.class} initialized with an invalid body: #{body.inspect}."
|
65
|
+
raise ArgumentError, "#{self.class} initialized with an invalid (non-String) body of class #{body.class}: #{body.inspect}."
|
66
66
|
end
|
67
67
|
|
68
68
|
# Ensure that the body is a raw string, in case the string instance
|
@@ -167,25 +167,6 @@ module VCR
|
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
170
|
-
# @private
|
171
|
-
module OrderedHashSerializer
|
172
|
-
def each
|
173
|
-
@ordered_keys.each do |key|
|
174
|
-
yield key, self[key] if has_key?(key)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
if RUBY_VERSION.to_f > 1.8
|
179
|
-
# 1.9+ hashes are already ordered.
|
180
|
-
def self.apply_to(*args); end
|
181
|
-
else
|
182
|
-
def self.apply_to(hash, keys)
|
183
|
-
hash.instance_variable_set(:@ordered_keys, keys)
|
184
|
-
hash.extend self
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
170
|
# The request of an {HTTPInteraction}.
|
190
171
|
#
|
191
172
|
# @attr [Symbol] method the HTTP method (i.e. :head, :options, :get, :post, :put, :patch or :delete)
|
@@ -219,7 +200,7 @@ module VCR
|
|
219
200
|
'uri' => uri,
|
220
201
|
'body' => serializable_body,
|
221
202
|
'headers' => headers
|
222
|
-
}
|
203
|
+
}
|
223
204
|
end
|
224
205
|
|
225
206
|
# Constructs a new instance from a hash.
|
@@ -365,11 +346,10 @@ module VCR
|
|
365
346
|
{
|
366
347
|
'status' => status.to_hash,
|
367
348
|
'headers' => headers,
|
368
|
-
'body' => serializable_body
|
369
|
-
'http_version' => http_version
|
349
|
+
'body' => serializable_body
|
370
350
|
}.tap do |hash|
|
351
|
+
hash['http_version'] = http_version if http_version
|
371
352
|
hash['adapter_metadata'] = adapter_metadata unless adapter_metadata.empty?
|
372
|
-
OrderedHashSerializer.apply_to(hash, members)
|
373
353
|
end
|
374
354
|
end
|
375
355
|
|
@@ -403,6 +383,11 @@ module VCR
|
|
403
383
|
%w[ gzip deflate ].include? content_encoding
|
404
384
|
end
|
405
385
|
|
386
|
+
# Checks if VCR decompressed the response body
|
387
|
+
def vcr_decompressed?
|
388
|
+
adapter_metadata['vcr_decompressed']
|
389
|
+
end
|
390
|
+
|
406
391
|
# Decodes the compressed body and deletes evidence that it was ever compressed.
|
407
392
|
#
|
408
393
|
# @return self
|
@@ -412,11 +397,43 @@ module VCR
|
|
412
397
|
self.class.decompress(body, content_encoding) { |new_body|
|
413
398
|
self.body = new_body
|
414
399
|
update_content_length_header
|
400
|
+
adapter_metadata['vcr_decompressed'] = content_encoding
|
415
401
|
delete_header('Content-Encoding')
|
416
402
|
}
|
417
403
|
return self
|
418
404
|
end
|
419
405
|
|
406
|
+
# Recompresses the decompressed body according to adapter metadata.
|
407
|
+
#
|
408
|
+
# @raise [VCR::Errors::UnknownContentEncodingError] if the content encoding
|
409
|
+
# stored in the adapter metadata is unknown
|
410
|
+
def recompress
|
411
|
+
type = adapter_metadata['vcr_decompressed']
|
412
|
+
new_body = begin
|
413
|
+
case type
|
414
|
+
when 'gzip'
|
415
|
+
body_str = ''
|
416
|
+
args = [StringIO.new(body_str)]
|
417
|
+
args << { :encoding => 'ASCII-8BIT' } if ''.respond_to?(:encoding)
|
418
|
+
writer = Zlib::GzipWriter.new(*args)
|
419
|
+
writer.write(body)
|
420
|
+
writer.close
|
421
|
+
body_str
|
422
|
+
when 'deflate'
|
423
|
+
Zlib::Deflate.inflate(body)
|
424
|
+
when 'identity', NilClass
|
425
|
+
nil
|
426
|
+
else
|
427
|
+
raise Errors::UnknownContentEncodingError, "unknown content encoding: #{type}"
|
428
|
+
end
|
429
|
+
end
|
430
|
+
if new_body
|
431
|
+
self.body = new_body
|
432
|
+
update_content_length_header
|
433
|
+
headers['Content-Encoding'] = type
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
420
437
|
begin
|
421
438
|
require 'zlib'
|
422
439
|
require 'stringio'
|
@@ -437,9 +454,10 @@ module VCR
|
|
437
454
|
|
438
455
|
case type
|
439
456
|
when 'gzip'
|
440
|
-
|
441
|
-
|
442
|
-
yield Zlib::GzipReader.new(
|
457
|
+
gzip_reader_options = {}
|
458
|
+
gzip_reader_options[:encoding] = 'ASCII-8BIT' if ''.respond_to?(:encoding)
|
459
|
+
yield Zlib::GzipReader.new(StringIO.new(body),
|
460
|
+
**gzip_reader_options).read
|
443
461
|
when 'deflate'
|
444
462
|
yield Zlib::Inflate.inflate(body)
|
445
463
|
when 'identity', NilClass
|
@@ -463,7 +481,7 @@ module VCR
|
|
463
481
|
def to_hash
|
464
482
|
{
|
465
483
|
'code' => code, 'message' => message
|
466
|
-
}
|
484
|
+
}
|
467
485
|
end
|
468
486
|
|
469
487
|
# Constructs a new instance from a hash.
|
@@ -496,9 +514,7 @@ module VCR
|
|
496
514
|
'request' => request.to_hash,
|
497
515
|
'response' => response.to_hash,
|
498
516
|
'recorded_at' => recorded_at.httpdate
|
499
|
-
}
|
500
|
-
OrderedHashSerializer.apply_to(hash, members)
|
501
|
-
end
|
517
|
+
}
|
502
518
|
end
|
503
519
|
|
504
520
|
# Constructs a new instance from a hash.
|
@@ -23,10 +23,10 @@ module VCR
|
|
23
23
|
# Adds `Before` and `After` cucumber hooks for the named tags that
|
24
24
|
# will cause a VCR cassette to be used for scenarios with matching tags.
|
25
25
|
#
|
26
|
-
# @param [Array<String>]
|
27
|
-
#
|
28
|
-
# `:use_scenario_name => true` to automatically name the
|
29
|
-
#
|
26
|
+
# @param tag_names [Array<String,Hash>] the cucumber scenario tags. If
|
27
|
+
# the last argument is a hash it is treated as cassette options.
|
28
|
+
# - `:use_scenario_name => true` to automatically name the
|
29
|
+
# cassette according to the scenario name.
|
30
30
|
def tags(*tag_names)
|
31
31
|
original_options = tag_names.last.is_a?(::Hash) ? tag_names.pop : {}
|
32
32
|
tag_names.each do |tag_name|
|
@@ -47,10 +47,21 @@ module VCR
|
|
47
47
|
scenario.scenario_outline.name,
|
48
48
|
scenario.name.split("\n").first
|
49
49
|
].join("/")
|
50
|
-
|
50
|
+
elsif scenario.respond_to?(:feature)
|
51
51
|
[ scenario.feature.name.split("\n").first,
|
52
52
|
scenario.name.split("\n").first
|
53
53
|
].join("/")
|
54
|
+
elsif scenario.location.lines.min == scenario.location.lines.max
|
55
|
+
# test case from a regular scenario in cucumber version 4
|
56
|
+
[ scenario.location.file.split("/").last.split(".").first,
|
57
|
+
scenario.name.split("\n").first
|
58
|
+
].join("/")
|
59
|
+
else
|
60
|
+
# test case from a scenario with examples ("scenario outline") in cucumber version 4
|
61
|
+
[ scenario.location.file.split("/").last.split(".").first,
|
62
|
+
scenario.name.split("\n").first,
|
63
|
+
"Example at line #{scenario.location.lines.max}"
|
64
|
+
].join("/")
|
54
65
|
end
|
55
66
|
else
|
56
67
|
"cucumber_tags/#{tag_name.gsub(/\A@/, '')}"
|
@@ -5,38 +5,50 @@ module VCR
|
|
5
5
|
module Metadata
|
6
6
|
extend self
|
7
7
|
|
8
|
+
def vcr_cassette_name_for(metadata)
|
9
|
+
description =
|
10
|
+
if metadata[:description].empty?
|
11
|
+
# we have an "it { is_expected.to be something }" block
|
12
|
+
metadata[:scoped_id]
|
13
|
+
else
|
14
|
+
metadata[:description]
|
15
|
+
end
|
16
|
+
example_group =
|
17
|
+
if metadata.key?(:example_group)
|
18
|
+
metadata[:example_group]
|
19
|
+
else
|
20
|
+
metadata[:parent_example_group]
|
21
|
+
end
|
22
|
+
|
23
|
+
if example_group
|
24
|
+
[vcr_cassette_name_for(example_group), description].join('/')
|
25
|
+
else
|
26
|
+
description
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
8
30
|
def configure!
|
9
31
|
::RSpec.configure do |config|
|
10
|
-
vcr_cassette_name_for = lambda do |metadata|
|
11
|
-
description = if metadata[:description].empty?
|
12
|
-
# we have an "it { is_expected.to be something }" block
|
13
|
-
metadata[:scoped_id]
|
14
|
-
else
|
15
|
-
metadata[:description]
|
16
|
-
end
|
17
|
-
example_group = if metadata.key?(:example_group)
|
18
|
-
metadata[:example_group]
|
19
|
-
else
|
20
|
-
metadata[:parent_example_group]
|
21
|
-
end
|
22
|
-
|
23
|
-
if example_group
|
24
|
-
[vcr_cassette_name_for[example_group], description].join('/')
|
25
|
-
else
|
26
|
-
description
|
27
|
-
end
|
28
|
-
end
|
29
32
|
|
30
33
|
when_tagged_with_vcr = { :vcr => lambda { |v| !!v } }
|
31
34
|
|
32
35
|
config.before(:each, when_tagged_with_vcr) do |ex|
|
33
36
|
example = ex.respond_to?(:metadata) ? ex : ex.example
|
34
37
|
|
38
|
+
cassette_name = nil
|
35
39
|
options = example.metadata[:vcr]
|
36
|
-
options =
|
40
|
+
options = case options
|
41
|
+
when Hash #=> vcr: { cassette_name: 'foo' }
|
42
|
+
options.dup
|
43
|
+
when String #=> vcr: 'bar'
|
44
|
+
cassette_name = options.dup
|
45
|
+
{}
|
46
|
+
else #=> :vcr or vcr: true
|
47
|
+
{}
|
48
|
+
end
|
37
49
|
|
38
|
-
cassette_name
|
39
|
-
|
50
|
+
cassette_name ||= options.delete(:cassette_name) ||
|
51
|
+
VCR::RSpec::Metadata.vcr_cassette_name_for(example.metadata)
|
40
52
|
VCR.insert_cassette(cassette_name, options)
|
41
53
|
end
|
42
54
|
|
@@ -1,31 +1,25 @@
|
|
1
1
|
module VCR
|
2
2
|
# Ruby 1.8 provides Ping.pingecho, but it was removed in 1.9.
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
Ping = ::Ping
|
7
|
-
rescue LoadError
|
8
|
-
# This is copied, verbatim, from Ruby 1.8.7's ping.rb.
|
9
|
-
require 'timeout'
|
10
|
-
require "socket"
|
3
|
+
# This is copied, verbatim, from Ruby 1.8.7's ping.rb.
|
4
|
+
require 'timeout'
|
5
|
+
require "socket"
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
rescue Errno::ECONNREFUSED
|
21
|
-
return true
|
22
|
-
rescue Timeout::Error, StandardError
|
23
|
-
return false
|
7
|
+
# @private
|
8
|
+
module Ping
|
9
|
+
def pingecho(host, timeout=5, service="echo")
|
10
|
+
begin
|
11
|
+
Timeout.timeout(timeout) do
|
12
|
+
s = TCPSocket.new(host, service)
|
13
|
+
s.close
|
24
14
|
end
|
15
|
+
rescue Errno::ECONNREFUSED
|
25
16
|
return true
|
17
|
+
rescue Timeout::Error, StandardError
|
18
|
+
return false
|
26
19
|
end
|
27
|
-
|
20
|
+
return true
|
28
21
|
end
|
22
|
+
module_function :pingecho
|
29
23
|
end
|
30
24
|
|
31
25
|
# @private
|