vcr 2.0.0.beta2 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +0 -2
- data/CHANGELOG.md +22 -1
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +1 -9
- data/README.md +8 -2
- data/Rakefile +12 -1
- data/cucumber.yml +8 -9
- data/features/.nav +10 -4
- data/features/cassettes/format.feature +1 -1
- data/features/cassettes/no_cassette.feature +8 -11
- data/features/configuration/allow_http_connections_when_no_cassette.feature +4 -4
- data/features/configuration/filter_sensitive_data.feature +3 -0
- data/features/configuration/hook_into.feature +4 -8
- data/features/configuration/ignore_request.feature +191 -0
- data/features/getting_started.md +38 -21
- data/features/hooks/after_http_request.feature +44 -0
- data/features/hooks/around_http_request.feature +56 -0
- data/features/hooks/before_http_request.feature +44 -0
- data/features/hooks/before_playback.feature +181 -0
- data/features/hooks/before_record.feature +172 -0
- data/features/middleware/faraday.feature +7 -3
- data/features/record_modes/none.feature +2 -1
- data/features/record_modes/once.feature +2 -1
- data/features/request_matching/body.feature +2 -2
- data/features/request_matching/custom_matcher.feature +2 -2
- data/features/request_matching/headers.feature +2 -2
- data/features/request_matching/host.feature +2 -2
- data/features/request_matching/identical_request_sequence.feature +2 -2
- data/features/request_matching/method.feature +2 -2
- data/features/request_matching/path.feature +2 -2
- data/features/request_matching/playback_repeats.feature +2 -1
- data/features/request_matching/uri.feature +2 -2
- data/features/support/env.rb +21 -12
- data/features/test_frameworks/cucumber.feature +9 -4
- data/features/test_frameworks/{rspec.feature → rspec_macro.feature} +7 -7
- data/features/test_frameworks/rspec_metadata.feature +90 -0
- data/lib/vcr.rb +1 -1
- data/lib/vcr/cassette.rb +3 -3
- data/lib/vcr/cassette/http_interaction_list.rb +13 -9
- data/lib/vcr/cassette/migrator.rb +1 -1
- data/lib/vcr/configuration.rb +37 -0
- data/lib/vcr/errors.rb +172 -6
- data/lib/vcr/library_hooks.rb +4 -6
- data/lib/vcr/library_hooks/excon.rb +23 -11
- data/lib/vcr/library_hooks/fakeweb.rb +85 -24
- data/lib/vcr/library_hooks/faraday.rb +30 -2
- data/lib/vcr/library_hooks/typhoeus.rb +25 -3
- data/lib/vcr/library_hooks/webmock.rb +25 -36
- data/lib/vcr/middleware/faraday.rb +23 -5
- data/lib/vcr/request_handler.rb +12 -1
- data/lib/vcr/request_ignorer.rb +12 -1
- data/lib/vcr/request_matcher_registry.rb +1 -9
- data/lib/vcr/structs.rb +32 -2
- data/lib/vcr/test_frameworks/rspec.rb +28 -0
- data/lib/vcr/util/hooks.rb +12 -4
- data/lib/vcr/util/version_checker.rb +2 -0
- data/lib/vcr/version.rb +1 -1
- data/spec/fixtures/cassette_spec/example.yml +1 -1
- data/spec/fixtures/{fake_example.com_responses.yml → fake_example_responses.yml} +0 -0
- data/spec/monkey_patches.rb +1 -1
- data/spec/spec_helper.rb +3 -1
- data/spec/support/http_library_adapters.rb +4 -3
- data/spec/support/shared_example_groups/hook_into_http_library.rb +194 -12
- data/spec/support/shared_example_groups/request_hooks.rb +58 -0
- data/spec/support/shared_example_groups/version_checking.rb +5 -0
- data/spec/support/sinatra_app.rb +17 -9
- data/spec/support/vcr_stub_helpers.rb +17 -0
- data/spec/vcr/cassette/http_interaction_list_spec.rb +28 -29
- data/spec/vcr/cassette/migrator_spec.rb +6 -7
- data/spec/vcr/cassette_spec.rb +5 -5
- data/spec/vcr/configuration_spec.rb +51 -32
- data/spec/vcr/deprecations_spec.rb +0 -8
- data/spec/vcr/errors_spec.rb +129 -0
- data/spec/vcr/library_hooks/excon_spec.rb +21 -4
- data/spec/vcr/library_hooks/fakeweb_spec.rb +71 -3
- data/spec/vcr/library_hooks/faraday_spec.rb +45 -0
- data/spec/vcr/library_hooks/typhoeus_spec.rb +31 -1
- data/spec/vcr/library_hooks/webmock_spec.rb +26 -3
- data/spec/vcr/middleware/faraday_spec.rb +84 -1
- data/spec/vcr/request_ignorer_spec.rb +16 -0
- data/spec/vcr/request_matcher_registry_spec.rb +0 -26
- data/spec/vcr/structs_spec.rb +61 -1
- data/spec/vcr/test_frameworks/rspec_spec.rb +32 -0
- data/spec/vcr/util/hooks_spec.rb +73 -63
- data/spec/vcr_spec.rb +2 -2
- data/vcr.gemspec +5 -5
- metadata +51 -31
- data/features/configuration/hooks.feature +0 -270
- data/features/configuration/ignore_hosts.feature +0 -61
- data/features/configuration/ignore_localhost.feature +0 -97
data/lib/vcr/configuration.rb
CHANGED
@@ -9,6 +9,8 @@ module VCR
|
|
9
9
|
define_hook :before_record
|
10
10
|
define_hook :before_playback
|
11
11
|
define_hook :after_library_hooks_loaded
|
12
|
+
define_hook :before_http_request
|
13
|
+
define_hook :after_http_request, :prepend
|
12
14
|
|
13
15
|
def initialize
|
14
16
|
@allow_http_connections_when_no_cassette = nil
|
@@ -48,6 +50,10 @@ module VCR
|
|
48
50
|
VCR.request_ignorer.ignore_localhost = value
|
49
51
|
end
|
50
52
|
|
53
|
+
def ignore_request(&block)
|
54
|
+
VCR.request_ignorer.ignore_request(&block)
|
55
|
+
end
|
56
|
+
|
51
57
|
attr_writer :allow_http_connections_when_no_cassette
|
52
58
|
def allow_http_connections_when_no_cassette?
|
53
59
|
!!@allow_http_connections_when_no_cassette
|
@@ -62,11 +68,28 @@ module VCR
|
|
62
68
|
interaction.filter!(placeholder, call_block(block, interaction))
|
63
69
|
end
|
64
70
|
end
|
71
|
+
alias define_cassette_placeholder filter_sensitive_data
|
65
72
|
|
66
73
|
def cassette_serializers
|
67
74
|
VCR.cassette_serializers
|
68
75
|
end
|
69
76
|
|
77
|
+
def around_http_request(&block)
|
78
|
+
require 'fiber'
|
79
|
+
rescue LoadError
|
80
|
+
raise Errors::NotSupportedError.new \
|
81
|
+
"VCR::Configuration#around_http_request requires fibers, " +
|
82
|
+
"which are not available on your ruby intepreter."
|
83
|
+
else
|
84
|
+
fiber, hook_decaration = nil, caller.first
|
85
|
+
before_http_request { |request| fiber = start_new_fiber_for(request, block) }
|
86
|
+
after_http_request { |request| resume_fiber(fiber, hook_decaration) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def configure_rspec_metadata!
|
90
|
+
VCR::RSpec::Metadata.configure!
|
91
|
+
end
|
92
|
+
|
70
93
|
private
|
71
94
|
|
72
95
|
def load_library_hook(hook)
|
@@ -76,6 +99,20 @@ module VCR
|
|
76
99
|
raise e unless e.message.include?(file) # in case FakeWeb/WebMock/etc itself is not available
|
77
100
|
raise ArgumentError.new("#{hook.inspect} is not a supported VCR HTTP library hook.")
|
78
101
|
end
|
102
|
+
|
103
|
+
def resume_fiber(fiber, hook_declaration)
|
104
|
+
fiber.resume
|
105
|
+
rescue FiberError
|
106
|
+
raise Errors::AroundHTTPRequestHookError.new \
|
107
|
+
"Your around_http_request hook declared at #{hook_declaration}" +
|
108
|
+
" must call #proceed on the yielded request but did not."
|
109
|
+
end
|
110
|
+
|
111
|
+
def start_new_fiber_for(request, block)
|
112
|
+
Fiber.new(&block).tap do |fiber|
|
113
|
+
fiber.resume(request.fiber_aware)
|
114
|
+
end
|
115
|
+
end
|
79
116
|
end
|
80
117
|
end
|
81
118
|
|
data/lib/vcr/errors.rb
CHANGED
@@ -7,15 +7,181 @@ module VCR
|
|
7
7
|
class LibraryVersionTooLowError < Error; end
|
8
8
|
class UnregisteredMatcherError < Error; end
|
9
9
|
class InvalidCassetteFormatError < Error; end
|
10
|
+
class AroundHTTPRequestHookError < Error; end
|
11
|
+
class NotSupportedError < Error; end
|
12
|
+
|
13
|
+
class UnhandledHTTPRequestError < Error
|
14
|
+
attr_reader :request
|
10
15
|
|
11
|
-
class HTTPConnectionNotAllowedError < Error
|
12
16
|
def initialize(request)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
@request = request
|
18
|
+
super construct_message
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def relish_version_slug
|
24
|
+
@relish_version_slug ||= VCR.version.gsub(/\W/, '-')
|
25
|
+
end
|
26
|
+
|
27
|
+
def construct_message
|
28
|
+
["", "", "=" * 80,
|
29
|
+
"An HTTP request has been made that VCR does not know how to handle:",
|
30
|
+
" #{request_description}\n",
|
31
|
+
cassette_description,
|
32
|
+
formatted_suggestions,
|
33
|
+
"=" * 80, "", ""].join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_description
|
37
|
+
"#{request.method.to_s.upcase} #{request.uri}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def cassette_description
|
41
|
+
if cassette = VCR.current_cassette
|
42
|
+
["VCR is currently using the following cassette:",
|
43
|
+
" - #{cassette.file}",
|
44
|
+
" - :record => #{cassette.record_mode.inspect}",
|
45
|
+
" - :match_requests_on => #{cassette.match_requests_on.inspect}\n",
|
46
|
+
"Under the current configuration VCR can not find a suitable HTTP interaction",
|
47
|
+
"to replay and is prevented from recording new requests. There are a few ways",
|
48
|
+
"you can deal with this:\n"].join("\n")
|
49
|
+
else
|
50
|
+
["There is currently no cassette in use. There are a few ways",
|
51
|
+
"you can configure VCR to handle this request:\n"].join("\n")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def formatted_suggestions
|
56
|
+
formatted_points, formatted_foot_notes = [], []
|
57
|
+
|
58
|
+
suggestions.each_with_index do |suggestion, index|
|
59
|
+
bullet_point, foot_note = suggestion.first, suggestion.last
|
60
|
+
formatted_points << format_bullet_point(bullet_point, index)
|
61
|
+
formatted_foot_notes << format_foot_note(foot_note, index)
|
62
|
+
end
|
63
|
+
|
64
|
+
[
|
65
|
+
formatted_points.join("\n"),
|
66
|
+
formatted_foot_notes.join("\n")
|
67
|
+
].join("\n\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
def format_bullet_point(lines, index)
|
71
|
+
lines.first.insert(0, " * ")
|
72
|
+
lines.last << " [#{index + 1}]."
|
73
|
+
lines.join("\n ")
|
74
|
+
end
|
75
|
+
|
76
|
+
def format_foot_note(url, index)
|
77
|
+
"[#{index + 1}] #{url % relish_version_slug}"
|
78
|
+
end
|
79
|
+
|
80
|
+
ALL_SUGGESTIONS = {
|
81
|
+
:use_new_episodes => [
|
82
|
+
["You can use the :new_episodes record mode to allow VCR to",
|
83
|
+
"record this new request to the existing cassette"],
|
84
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/new-episodes"
|
85
|
+
],
|
86
|
+
|
87
|
+
:delete_cassette_for_once => [
|
88
|
+
["The current record mode (:once) does not allow new requests to be recorded",
|
89
|
+
"to a previously recorded cassette. You can delete the cassette file and re-run",
|
90
|
+
"your tests to allow the cassette to be recorded with this request"],
|
91
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/once"
|
92
|
+
],
|
93
|
+
|
94
|
+
:deal_with_none => [
|
95
|
+
["The current record mode (:none) does not allow requests to be recorded. You",
|
96
|
+
"can temporarily change the record mode to :once, delete the cassette file ",
|
97
|
+
"and re-run your tests to allow the cassette to be recorded with this request"],
|
98
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/none"
|
99
|
+
],
|
100
|
+
|
101
|
+
:use_a_cassette => [
|
102
|
+
["If you want VCR to record this request and play it back during future test",
|
103
|
+
"runs, you should wrap your test (or this portion of your test) in a",
|
104
|
+
"`VCR.use_cassette` block"],
|
105
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/getting-started"
|
106
|
+
],
|
107
|
+
|
108
|
+
:allow_http_connections_when_no_cassette => [
|
109
|
+
["If you only want VCR to handle requests made while a cassette is in use,",
|
110
|
+
"configure `allow_http_connections_when_no_cassette = true`. VCR will",
|
111
|
+
"ignore this request since it is made when there is no cassette"],
|
112
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/configuration/allow-http-connections-when-no-cassette"
|
113
|
+
],
|
114
|
+
|
115
|
+
:ignore_request => [
|
116
|
+
["If you want VCR to ignore this request (and others like it), you can",
|
117
|
+
"set an `ignore_request` callback"],
|
118
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/configuration/ignore-request"
|
119
|
+
],
|
120
|
+
|
121
|
+
:allow_playback_repeats => [
|
122
|
+
["The cassette contains an HTTP interaction that matches this request,",
|
123
|
+
"but it has already been played back. If you wish to allow a single HTTP",
|
124
|
+
"interaction to be played back multiple times, set the `:allow_playback_repeats`",
|
125
|
+
"cassette option"],
|
126
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/request-matching/playback-repeats"
|
127
|
+
],
|
128
|
+
|
129
|
+
:match_requests_on => [
|
130
|
+
["The cassette contains %s not been",
|
131
|
+
"played back. If your request is non-deterministic, you may need to",
|
132
|
+
"change your :match_requests_on cassette option to be more lenient",
|
133
|
+
"or use a custom request matcher to allow it to match"],
|
134
|
+
"https://www.relishapp.com/myronmarston/vcr/v/%s/docs/request-matching"
|
135
|
+
]
|
136
|
+
}
|
137
|
+
|
138
|
+
def suggestion_for(key)
|
139
|
+
bullet_point_lines, url = ALL_SUGGESTIONS[key]
|
140
|
+
bullet_point_lines = bullet_point_lines.map(&:dup)
|
141
|
+
url = url.dup
|
142
|
+
[bullet_point_lines, url]
|
143
|
+
end
|
144
|
+
|
145
|
+
def suggestions
|
146
|
+
return no_cassette_suggestions unless cassette = VCR.current_cassette
|
147
|
+
|
148
|
+
[:use_new_episodes, :ignore_request].tap do |suggestions|
|
149
|
+
suggestions.push(*record_mode_suggestion)
|
150
|
+
suggestions << :allow_playback_repeats if cassette.http_interactions.has_used_interaction_matching?(request)
|
151
|
+
suggestions.map! { |k| suggestion_for(k) }
|
152
|
+
suggestions.push(*match_requests_on_suggestion)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def no_cassette_suggestions
|
157
|
+
[:use_a_cassette, :allow_http_connections_when_no_cassette, :ignore_request].map do |key|
|
158
|
+
suggestion_for(key)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def record_mode_suggestion
|
163
|
+
case VCR.current_cassette.record_mode
|
164
|
+
when :none then [:deal_with_none]
|
165
|
+
when :once then [:delete_cassette_for_once]
|
166
|
+
else []
|
167
|
+
end
|
18
168
|
end
|
169
|
+
|
170
|
+
def match_requests_on_suggestion
|
171
|
+
num_remaining_interactions = VCR.current_cassette.http_interactions.remaining_unused_interaction_count
|
172
|
+
return [] if num_remaining_interactions.zero?
|
173
|
+
|
174
|
+
interaction_description = if num_remaining_interactions == 1
|
175
|
+
"1 HTTP interaction that has"
|
176
|
+
else
|
177
|
+
"#{num_remaining_interactions} HTTP interactions that have"
|
178
|
+
end
|
179
|
+
|
180
|
+
description_lines, link = suggestion_for(:match_requests_on)
|
181
|
+
description_lines[0] = description_lines[0] % interaction_description
|
182
|
+
[[description_lines, link]]
|
183
|
+
end
|
184
|
+
|
19
185
|
end
|
20
186
|
end
|
21
187
|
end
|
data/lib/vcr/library_hooks.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
module VCR
|
2
2
|
class LibraryHooks
|
3
|
-
|
4
|
-
@exclusive_hook = nil
|
5
|
-
end
|
3
|
+
attr_accessor :exclusive_hook
|
6
4
|
|
7
5
|
def disabled?(hook)
|
8
|
-
![nil, hook].include?(
|
6
|
+
![nil, hook].include?(exclusive_hook)
|
9
7
|
end
|
10
8
|
|
11
9
|
def exclusively_enabled(hook)
|
12
|
-
|
10
|
+
self.exclusive_hook = hook
|
13
11
|
yield
|
14
12
|
ensure
|
15
|
-
|
13
|
+
self.exclusive_hook = nil
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
@@ -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.6.5', '0.
|
5
|
+
VCR::VersionChecker.new('Excon', Excon::VERSION, '0.6.5', '0.7').check_version!
|
6
6
|
|
7
7
|
module VCR
|
8
8
|
class LibraryHooks
|
@@ -10,12 +10,20 @@ module VCR
|
|
10
10
|
class RequestHandler < ::VCR::RequestHandler
|
11
11
|
attr_reader :params
|
12
12
|
def initialize(params)
|
13
|
+
@vcr_response = nil
|
13
14
|
@params = params
|
14
15
|
end
|
15
16
|
|
17
|
+
def handle
|
18
|
+
super
|
19
|
+
ensure
|
20
|
+
invoke_after_request_hook(@vcr_response)
|
21
|
+
end
|
22
|
+
|
16
23
|
private
|
17
24
|
|
18
25
|
def on_stubbed_request
|
26
|
+
@vcr_response = stubbed_response
|
19
27
|
{
|
20
28
|
:body => stubbed_response.body,
|
21
29
|
:headers => normalized_headers(stubbed_response.headers || {}),
|
@@ -23,6 +31,10 @@ module VCR
|
|
23
31
|
}
|
24
32
|
end
|
25
33
|
|
34
|
+
def on_ignored_request
|
35
|
+
perform_real_request
|
36
|
+
end
|
37
|
+
|
26
38
|
def response_from_excon_error(error)
|
27
39
|
if error.respond_to?(:response)
|
28
40
|
error.response
|
@@ -34,20 +46,18 @@ module VCR
|
|
34
46
|
end
|
35
47
|
|
36
48
|
def perform_real_request
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
rescue ::Excon::Errors::Error => e
|
42
|
-
yield response_from_excon_error(e) if block_given?
|
43
|
-
raise e
|
49
|
+
begin
|
50
|
+
response = ::Excon.new(uri).request(params.merge(:mock => false))
|
51
|
+
rescue ::Excon::Errors::Error => excon_error
|
52
|
+
response = response_from_excon_error(excon_error)
|
44
53
|
end
|
45
54
|
|
55
|
+
@vcr_response = vcr_response_from(response)
|
46
56
|
yield response if block_given?
|
57
|
+
raise excon_error if excon_error
|
47
58
|
|
48
59
|
response.attributes
|
49
60
|
end
|
50
|
-
alias on_ignored_request perform_real_request
|
51
61
|
|
52
62
|
def on_recordable_request
|
53
63
|
perform_real_request do |response|
|
@@ -60,6 +70,8 @@ module VCR
|
|
60
70
|
@uri ||= "#{params[:scheme]}://#{params[:host]}:#{params[:port]}#{params[:path]}#{query}"
|
61
71
|
end
|
62
72
|
|
73
|
+
# based on:
|
74
|
+
# https://github.com/geemus/excon/blob/v0.7.8/lib/excon/connection.rb#L117-132
|
63
75
|
def query
|
64
76
|
@query ||= case params[:query]
|
65
77
|
when String
|
@@ -84,7 +96,7 @@ module VCR
|
|
84
96
|
def http_interaction_for(response)
|
85
97
|
VCR::HTTPInteraction.new \
|
86
98
|
vcr_request,
|
87
|
-
|
99
|
+
vcr_response_from(response)
|
88
100
|
end
|
89
101
|
|
90
102
|
def vcr_request
|
@@ -100,7 +112,7 @@ module VCR
|
|
100
112
|
end
|
101
113
|
end
|
102
114
|
|
103
|
-
def
|
115
|
+
def vcr_response_from(response)
|
104
116
|
VCR::Response.new \
|
105
117
|
VCR::ResponseStatus.new(response.status, nil),
|
106
118
|
response.headers,
|
@@ -3,6 +3,7 @@ require 'fakeweb'
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'vcr/extensions/net_http_response'
|
5
5
|
require 'vcr/request_handler'
|
6
|
+
require 'set'
|
6
7
|
|
7
8
|
VCR::VersionChecker.new('FakeWeb', FakeWeb::VERSION, '1.3.0', '1.3').check_version!
|
8
9
|
|
@@ -10,39 +11,84 @@ module VCR
|
|
10
11
|
class LibraryHooks
|
11
12
|
module FakeWeb
|
12
13
|
class RequestHandler < ::VCR::RequestHandler
|
13
|
-
attr_reader :net_http, :request, :request_body, :
|
14
|
-
def initialize(net_http, request, request_body = nil, &
|
15
|
-
@net_http, @request, @request_body, @
|
16
|
-
net_http, request, request_body,
|
14
|
+
attr_reader :net_http, :request, :request_body, :response_block
|
15
|
+
def initialize(net_http, request, request_body = nil, &response_block)
|
16
|
+
@net_http, @request, @request_body, @response_block =
|
17
|
+
net_http, request, request_body, response_block
|
18
|
+
@vcr_response, @recursing = nil, false
|
17
19
|
end
|
18
20
|
|
19
|
-
|
21
|
+
def handle
|
22
|
+
super
|
23
|
+
ensure
|
24
|
+
invoke_after_request_hook(@vcr_response) unless @recursing
|
25
|
+
end
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
27
|
+
class << self
|
28
|
+
def already_seen_requests
|
29
|
+
@already_seen_requests ||= Set.new
|
30
|
+
end
|
31
|
+
end
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def invoke_before_request_hook
|
36
|
+
unless self.class.already_seen_requests.include?(request.object_id)
|
37
|
+
super
|
38
|
+
# we use the object_id so that if there is bug that causes
|
39
|
+
# us not to fully cleanup, we'll only be leaking the memory
|
40
|
+
# of one integer, not the whole request object.
|
41
|
+
self.class.already_seen_requests << request.object_id
|
31
42
|
end
|
32
43
|
end
|
33
|
-
alias on_recordable_request perform_and_record_request
|
34
44
|
|
35
|
-
def
|
45
|
+
def invoke_after_request_hook(vcr_response)
|
46
|
+
self.class.already_seen_requests.delete(request.object_id)
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_recordable_request
|
51
|
+
perform_request(net_http.started?, :record_interaction)
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_stubbed_request
|
36
55
|
with_exclusive_fakeweb_stub(stubbed_response) do
|
37
|
-
|
56
|
+
# force it to be considered started since it doesn't
|
57
|
+
# recurse in this case like the others.
|
58
|
+
perform_request(:started)
|
38
59
|
end
|
39
60
|
end
|
40
|
-
alias on_stubbed_request perform_stubbed_request
|
41
61
|
|
42
|
-
def
|
43
|
-
net_http.
|
62
|
+
def on_ignored_request
|
63
|
+
perform_request(net_http.started?)
|
64
|
+
end
|
65
|
+
|
66
|
+
# overriden to prevent it from invoking the after_http_request hook,
|
67
|
+
# since we invoke the hook in an ensure block above.
|
68
|
+
def on_connection_not_allowed
|
69
|
+
raise VCR::Errors::UnhandledHTTPRequestError.new(vcr_request)
|
70
|
+
end
|
71
|
+
|
72
|
+
def perform_request(started, record_interaction = false)
|
73
|
+
# Net::HTTP calls #request recursively in certain circumstances.
|
74
|
+
# We only want to record the request when the request is started, as
|
75
|
+
# that is the final time through #request.
|
76
|
+
unless started
|
77
|
+
@recursing = true
|
78
|
+
return net_http.request_without_vcr(request, request_body, &response_block)
|
79
|
+
end
|
80
|
+
|
81
|
+
net_http.request_without_vcr(request, request_body) do |response|
|
82
|
+
@vcr_response = vcr_response_from(response)
|
83
|
+
|
84
|
+
if record_interaction
|
85
|
+
VCR.record_http_interaction VCR::HTTPInteraction.new(vcr_request, @vcr_response)
|
86
|
+
end
|
87
|
+
|
88
|
+
response.extend VCR::Net::HTTPResponse # "unwind" the response
|
89
|
+
response_block.call(response) if response_block
|
90
|
+
end
|
44
91
|
end
|
45
|
-
alias on_ignored_request perform_request
|
46
92
|
|
47
93
|
def uri
|
48
94
|
@uri ||= ::FakeWeb::Utility.request_uri_as_string(net_http, request)
|
@@ -91,9 +137,13 @@ module Net
|
|
91
137
|
class HTTP
|
92
138
|
unless method_defined?(:request_with_vcr)
|
93
139
|
def request_with_vcr(*args, &block)
|
94
|
-
VCR
|
95
|
-
|
96
|
-
|
140
|
+
if VCR.turned_on?
|
141
|
+
VCR::LibraryHooks::FakeWeb::RequestHandler.new(
|
142
|
+
self, *args, &block
|
143
|
+
).handle
|
144
|
+
else
|
145
|
+
request_without_vcr(*args, &block)
|
146
|
+
end
|
97
147
|
end
|
98
148
|
|
99
149
|
alias request_without_vcr request
|
@@ -102,6 +152,17 @@ module Net
|
|
102
152
|
end
|
103
153
|
end
|
104
154
|
|
155
|
+
class << FakeWeb
|
156
|
+
# ensure HTTP requests are always allowed; VCR takes care of disallowing
|
157
|
+
# them at the appropriate times in its hook
|
158
|
+
def allow_net_connect_with_vcr?(*args)
|
159
|
+
VCR.turned_on? ? true : allow_net_connect_without_vcr?
|
160
|
+
end
|
161
|
+
|
162
|
+
alias allow_net_connect_without_vcr? allow_net_connect?
|
163
|
+
alias allow_net_connect? allow_net_connect_with_vcr?
|
164
|
+
end unless FakeWeb.respond_to?(:allow_net_connect_with_vcr?)
|
165
|
+
|
105
166
|
VCR.configuration.after_library_hooks_loaded do
|
106
167
|
if defined?(WebMock)
|
107
168
|
raise ArgumentError.new("You have configured VCR to hook into both :fakeweb and :webmock. You cannot use both.")
|