-
-
Notifications
You must be signed in to change notification settings - Fork 508
/
Copy pathwebmock.rb
172 lines (141 loc) · 4.97 KB
/
webmock.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
require 'vcr/util/version_checker'
require 'vcr/request_handler'
require 'webmock'
VCR::VersionChecker.new('WebMock', WebMock.version, '1.8.0').check_version!
WebMock.enable!
module VCR
class LibraryHooks
# @private
module WebMock
extend self
def with_global_hook_disabled(request)
global_hook_disabled_requests << request
begin
yield
ensure
global_hook_disabled_requests.delete(request)
end
end
def global_hook_disabled?(request)
requests = Thread.current[:_vcr_webmock_disabled_requests]
requests && requests.include?(request)
end
def global_hook_disabled_requests
Thread.current[:_vcr_webmock_disabled_requests] ||= []
end
# @private
module Helpers
def vcr_request_for(webmock_request)
VCR::Request.new \
webmock_request.method,
webmock_request.uri.to_s,
webmock_request.body,
request_headers_for(webmock_request)
end
# @private
def vcr_response_for(webmock_response)
VCR::Response.new \
VCR::ResponseStatus.new(*webmock_response.status),
webmock_response.headers,
webmock_response.body,
nil
end
if defined?(::Excon)
# @private
def request_headers_for(webmock_request)
return nil unless webmock_request.headers
# WebMock hooks deeply into a Excon at a place where it manually adds a "Host"
# header, but this isn't a header we actually care to store...
webmock_request.headers.dup.tap do |headers|
headers.delete("Host")
end
end
else
# @private
def request_headers_for(webmock_request)
webmock_request.headers
end
end
def typed_request_for(webmock_request, remove = false)
if webmock_request.instance_variables.find { |v| v.to_sym == :@__typed_vcr_request }
meth = remove ? :remove_instance_variable : :instance_variable_get
return webmock_request.send(meth, :@__typed_vcr_request)
end
warn <<-EOS.gsub(/^\s+\|/, '')
|WARNING: There appears to be a bug in WebMock's after_request hook
| and VCR is attempting to work around it. Some VCR features
| may not work properly.
EOS
Request::Typed.new(vcr_request_for(webmock_request), :unknown)
end
end
class RequestHandler < ::VCR::RequestHandler
include Helpers
attr_reader :request
def initialize(request)
@request = request
end
private
def externally_stubbed?
# prevent infinite recursion...
VCR::LibraryHooks::WebMock.with_global_hook_disabled(request) do
::WebMock.registered_request?(request)
end
end
def set_typed_request_for_after_hook(*args)
super
request.instance_variable_set(:@__typed_vcr_request, @after_hook_typed_request)
end
def vcr_request
@vcr_request ||= vcr_request_for(request)
end
def on_externally_stubbed_request
# nil allows WebMock to handle the request
nil
end
def on_unhandled_request
invoke_after_request_hook(nil)
super
end
def on_stubbed_by_vcr_request
{
:body => stubbed_response.body.dup, # Excon mutates the body, so we must dup it :-(
:status => [stubbed_response.status.code.to_i, stubbed_response.status.message],
:headers => stubbed_response.headers
}
end
end
extend Helpers
::WebMock.globally_stub_request do |req|
global_hook_disabled?(req) ? nil : RequestHandler.new(req).handle
end
::WebMock.after_request(:real_requests_only => true) do |request, response|
unless VCR.library_hooks.disabled?(:webmock)
http_interaction = VCR::HTTPInteraction.new \
typed_request_for(request), vcr_response_for(response)
VCR.record_http_interaction(http_interaction)
end
end
::WebMock.after_request do |request, response|
unless VCR.library_hooks.disabled?(:webmock)
VCR.configuration.invoke_hook \
:after_http_request,
typed_request_for(request, :remove),
vcr_response_for(response)
end
end
end
end
end
# @private
module WebMock
class << self
# ensure HTTP requests are always allowed; VCR takes care of disallowing
# them at the appropriate times in its hook
def net_connect_allowed_with_vcr?(*args)
VCR.turned_on? ? true : net_connect_allowed_without_vcr?(*args)
end
alias net_connect_allowed_without_vcr? net_connect_allowed?
alias net_connect_allowed? net_connect_allowed_with_vcr?
end unless respond_to?(:net_connect_allowed_with_vcr?)
end