forked from vcr/vcr
-
Notifications
You must be signed in to change notification settings - Fork 15
/
fakeweb.rb
195 lines (163 loc) · 5.88 KB
/
fakeweb.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
require 'vcr/util/version_checker'
require 'fakeweb'
require 'net/http'
require 'vcr/extensions/net_http_response'
require 'vcr/request_handler'
require 'set'
VCR::VersionChecker.new('FakeWeb', FakeWeb::VERSION, '1.3.0', '1.3').check_version!
module VCR
class LibraryHooks
# @private
module FakeWeb
# @private
class RequestHandler < ::VCR::RequestHandler
attr_reader :net_http, :request, :request_body, :response_block
def initialize(net_http, request, request_body = nil, &response_block)
@net_http, @request, @request_body, @response_block =
net_http, request, request_body, response_block
@stubbed_response, @vcr_response, @recursing = nil, nil, false
end
def handle
super
ensure
invoke_after_request_hook(@vcr_response) unless @recursing
end
private
def externally_stubbed?
::FakeWeb.registered_uri?(request_method, uri)
end
def on_externally_stubbed_request
# just perform the request--FakeWeb will handle it
perform_request(:started)
end
def on_recordable_request
perform_request(net_http.started?, :record_interaction)
end
def on_stubbed_by_vcr_request
with_exclusive_fakeweb_stub(stubbed_response) do
# force it to be considered started since it doesn't
# recurse in this case like the others.
perform_request(:started)
end
end
def on_ignored_request
perform_request(net_http.started?)
end
def perform_request(started, record_interaction = false)
# Net::HTTP calls #request recursively in certain circumstances.
# We only want to record the request when the request is started, as
# that is the final time through #request.
unless started
@recursing = true
request.instance_variable_set(:@__vcr_request_handler, recursive_request_handler)
return net_http.request_without_vcr(request, request_body, &response_block)
end
net_http.request_without_vcr(request, request_body) do |response|
@vcr_response = vcr_response_from(response)
if record_interaction
VCR.record_http_interaction VCR::HTTPInteraction.new(vcr_request, @vcr_response)
end
response.extend VCR::Net::HTTPResponse # "unwind" the response
response_block.call(response) if response_block
end
end
def uri
@uri ||= ::FakeWeb::Utility.request_uri_as_string(net_http, request)
end
def response_hash(response)
(response.headers || {}).merge(
:body => response.body,
:status => [response.status.code.to_s, response.status.message]
)
end
def with_exclusive_fakeweb_stub(response)
original_map = ::FakeWeb::Registry.instance.uri_map.dup
::FakeWeb.clean_registry
::FakeWeb.register_uri(:any, /.*/, response_hash(response))
begin
return yield
ensure
::FakeWeb::Registry.instance.uri_map = original_map
end
end
def request_method
request.method.downcase.to_sym
end
def vcr_request
@vcr_request ||= VCR::Request.new \
request_method,
uri,
(request_body || request.body),
request.to_hash
end
def vcr_response_from(response)
VCR::Response.new \
VCR::ResponseStatus.new(response.code.to_i, response.message),
response.to_hash,
response.body,
response.http_version
end
def recursive_request_handler
@recursive_request_handler ||= RecursiveRequestHandler.new(
@after_hook_typed_request.type, @stubbed_response, @vcr_request,
@net_http, @request, @request_body, &@response_block
)
end
end
class RecursiveRequestHandler < RequestHandler
attr_reader :stubbed_response
def initialize(request_type, stubbed_response, vcr_request, *args, &response_block)
@request_type, @stubbed_response, @vcr_request =
request_type, stubbed_response, vcr_request
super(*args)
end
def handle
set_typed_request_for_after_hook(@request_type)
send "on_#{@request_type}_request"
ensure
invoke_after_request_hook(@vcr_response)
end
def request_type(*args)
@request_type
end
end
end
end
end
# @private
module Net
# @private
class HTTP
unless method_defined?(:request_with_vcr)
def request_with_vcr(request, *args, &block)
if VCR.turned_on?
handler = request.instance_eval do
remove_instance_variable(:@__vcr_request_handler) if defined?(@__vcr_request_handler)
end || VCR::LibraryHooks::FakeWeb::RequestHandler.new(self, request, *args, &block)
handler.handle
else
request_without_vcr(request, *args, &block)
end
end
alias request_without_vcr request
alias request request_with_vcr
end
end
end
# @private
module FakeWeb
class << self
# ensure HTTP requests are always allowed; VCR takes care of disallowing
# them at the appropriate times in its hook
def allow_net_connect_with_vcr?(*args)
VCR.turned_on? ? true : allow_net_connect_without_vcr?(*args)
end
alias allow_net_connect_without_vcr? allow_net_connect?
alias allow_net_connect? allow_net_connect_with_vcr?
end unless respond_to?(:allow_net_connect_with_vcr?)
end
VCR.configuration.after_library_hooks_loaded do
if defined?(WebMock)
raise ArgumentError.new("You have configured VCR to hook into both :fakeweb and :webmock. You cannot use both.")
end
end