webmock 1.8.6 → 3.14.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 +7 -0
- data/.github/workflows/CI.yml +37 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +1198 -0
- data/Gemfile +3 -15
- data/README.md +761 -305
- data/Rakefile +13 -40
- data/lib/webmock/api.rb +63 -17
- data/lib/webmock/callback_registry.rb +1 -1
- data/lib/webmock/config.rb +8 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/errors.rb +8 -24
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
- data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
- data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
- data/lib/webmock/minitest.rb +29 -3
- data/lib/webmock/rack_response.rb +14 -7
- data/lib/webmock/request_body_diff.rb +64 -0
- data/lib/webmock/request_execution_verifier.rb +38 -17
- data/lib/webmock/request_pattern.rb +158 -38
- data/lib/webmock/request_registry.rb +3 -3
- data/lib/webmock/request_signature.rb +7 -3
- data/lib/webmock/request_signature_snippet.rb +61 -0
- data/lib/webmock/request_stub.rb +9 -6
- data/lib/webmock/response.rb +30 -15
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
- data/lib/webmock/rspec/matchers.rb +0 -1
- data/lib/webmock/rspec.rb +11 -2
- data/lib/webmock/stub_registry.rb +31 -10
- data/lib/webmock/stub_request_snippet.rb +14 -6
- data/lib/webmock/test_unit.rb +4 -4
- data/lib/webmock/util/hash_counter.rb +20 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
- data/lib/webmock/util/hash_validator.rb +17 -0
- data/lib/webmock/util/headers.rb +23 -2
- data/lib/webmock/util/json.rb +20 -7
- data/lib/webmock/util/query_mapper.rb +281 -0
- data/lib/webmock/util/uri.rb +29 -19
- data/lib/webmock/util/values_stringifier.rb +20 -0
- data/lib/webmock/util/version_checker.rb +40 -2
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +56 -17
- data/lib/webmock.rb +56 -46
- data/minitest/test_helper.rb +8 -3
- data/minitest/test_webmock.rb +4 -1
- data/minitest/webmock_spec.rb +16 -6
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
- data/spec/acceptance/curb/curb_spec.rb +227 -68
- data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
- data/spec/acceptance/excon/excon_spec.rb +66 -4
- data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
- data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
- data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
- data/spec/acceptance/manticore/manticore_spec.rb +107 -0
- data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
- data/spec/acceptance/net_http/net_http_shared.rb +52 -24
- data/spec/acceptance/net_http/net_http_spec.rb +164 -50
- data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
- data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
- data/spec/acceptance/patron/patron_spec.rb +29 -40
- data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
- data/spec/acceptance/shared/callbacks.rb +32 -30
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
- data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
- data/spec/acceptance/shared/request_expectations.rb +560 -296
- data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
- data/spec/acceptance/shared/stubbing_requests.rb +385 -154
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
- data/spec/acceptance/webmock_shared.rb +2 -2
- data/spec/fixtures/test.txt +1 -0
- data/spec/quality_spec.rb +27 -3
- data/spec/spec_helper.rb +11 -20
- data/spec/support/failures.rb +9 -0
- data/spec/support/my_rack_app.rb +8 -3
- data/spec/support/network_connection.rb +7 -13
- data/spec/support/webmock_server.rb +8 -3
- data/spec/unit/api_spec.rb +175 -0
- data/spec/unit/errors_spec.rb +116 -19
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
- data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
- data/spec/unit/rack_response_spec.rb +54 -16
- data/spec/unit/request_body_diff_spec.rb +90 -0
- data/spec/unit/request_execution_verifier_spec.rb +147 -39
- data/spec/unit/request_pattern_spec.rb +462 -198
- data/spec/unit/request_registry_spec.rb +29 -9
- data/spec/unit/request_signature_snippet_spec.rb +89 -0
- data/spec/unit/request_signature_spec.rb +91 -49
- data/spec/unit/request_stub_spec.rb +71 -70
- data/spec/unit/response_spec.rb +100 -81
- data/spec/unit/stub_registry_spec.rb +37 -20
- data/spec/unit/stub_request_snippet_spec.rb +51 -31
- data/spec/unit/util/hash_counter_spec.rb +6 -6
- data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
- data/spec/unit/util/headers_spec.rb +4 -4
- data/spec/unit/util/json_spec.rb +29 -3
- data/spec/unit/util/query_mapper_spec.rb +157 -0
- data/spec/unit/util/uri_spec.rb +150 -36
- data/spec/unit/util/version_checker_spec.rb +15 -9
- data/spec/unit/webmock_spec.rb +57 -4
- data/test/http_request.rb +3 -3
- data/test/shared_test.rb +45 -13
- data/test/test_helper.rb +1 -1
- data/test/test_webmock.rb +6 -0
- data/webmock.gemspec +30 -11
- metadata +308 -199
- data/.rvmrc +0 -1
- data/.travis.yml +0 -11
- data/Guardfile +0 -24
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +0 -210
@@ -28,15 +28,23 @@ module WebMock
|
|
28
28
|
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
29
29
|
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
30
30
|
Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
|
31
|
+
|
32
|
+
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
33
|
+
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
34
|
+
#after WebMock was enabled.
|
35
|
+
#i.e Net::HTTP::DigestAuth
|
36
|
+
@webMockNetHTTP.constants.each do |constant|
|
37
|
+
if !OriginalNetHTTP.constants.map(&:to_s).include?(constant.to_s)
|
38
|
+
OriginalNetHTTP.send(:const_set, constant, @webMockNetHTTP.const_get(constant))
|
39
|
+
end
|
40
|
+
end
|
31
41
|
end
|
32
42
|
|
33
43
|
@webMockNetHTTP = Class.new(Net::HTTP) do
|
34
44
|
class << self
|
35
|
-
def
|
45
|
+
def socket_type
|
36
46
|
StubSocket
|
37
47
|
end
|
38
|
-
alias_method :socket_type_without_webmock, :socket_type
|
39
|
-
alias_method :socket_type, :socket_type_with_webmock
|
40
48
|
|
41
49
|
if Module.method(:const_defined?).arity == 1
|
42
50
|
def const_defined?(name)
|
@@ -58,12 +66,12 @@ module WebMock
|
|
58
66
|
|
59
67
|
if Module.method(:constants).arity != 0
|
60
68
|
def constants(inherit=true)
|
61
|
-
super + self.superclass.constants(inherit)
|
69
|
+
(super + self.superclass.constants(inherit)).uniq
|
62
70
|
end
|
63
71
|
end
|
64
72
|
end
|
65
73
|
|
66
|
-
def
|
74
|
+
def request(request, body = nil, &block)
|
67
75
|
request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
|
68
76
|
|
69
77
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
@@ -71,7 +79,7 @@ module WebMock
|
|
71
79
|
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
72
80
|
@socket = Net::HTTP.socket_type.new
|
73
81
|
WebMock::CallbackRegistry.invoke_callbacks(
|
74
|
-
{:
|
82
|
+
{lib: :net_http}, request_signature, webmock_response)
|
75
83
|
build_net_http_response(webmock_response, &block)
|
76
84
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
77
85
|
check_right_http_connection
|
@@ -79,28 +87,33 @@ module WebMock
|
|
79
87
|
if WebMock::CallbackRegistry.any_callbacks?
|
80
88
|
webmock_response = build_webmock_response(response)
|
81
89
|
WebMock::CallbackRegistry.invoke_callbacks(
|
82
|
-
{:
|
90
|
+
{lib: :net_http, real_request: true}, request_signature, webmock_response)
|
83
91
|
end
|
84
92
|
response.extend Net::WebMockHTTPResponse
|
85
93
|
block.call response if block
|
86
94
|
response
|
87
95
|
end
|
88
|
-
|
89
|
-
|
96
|
+
super_with_after_request = lambda {
|
97
|
+
response = super(request, nil, &nil)
|
98
|
+
after_request.call(response)
|
99
|
+
}
|
100
|
+
if started?
|
101
|
+
if WebMock::Config.instance.net_http_connect_on_start
|
102
|
+
super_with_after_request.call
|
103
|
+
else
|
104
|
+
start_with_connect_without_finish {
|
105
|
+
super_with_after_request.call
|
106
|
+
}
|
107
|
+
end
|
108
|
+
else
|
90
109
|
start_with_connect {
|
91
|
-
|
92
|
-
after_request.call(response)
|
110
|
+
super_with_after_request.call
|
93
111
|
}
|
94
|
-
else
|
95
|
-
response = request_without_webmock(request, nil)
|
96
|
-
after_request.call(response)
|
97
112
|
end
|
98
113
|
else
|
99
114
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
100
115
|
end
|
101
116
|
end
|
102
|
-
alias_method :request_without_webmock, :request
|
103
|
-
alias_method :request, :request_with_webmock
|
104
117
|
|
105
118
|
def start_without_connect
|
106
119
|
raise IOError, 'HTTP session already opened' if @started
|
@@ -116,19 +129,34 @@ module WebMock
|
|
116
129
|
self
|
117
130
|
end
|
118
131
|
|
119
|
-
|
132
|
+
|
133
|
+
def start_with_connect_without_finish # :yield: http
|
134
|
+
if block_given?
|
135
|
+
begin
|
136
|
+
do_start
|
137
|
+
return yield(self)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
do_start
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
alias_method :start_with_connect, :start
|
145
|
+
|
146
|
+
def start(&block)
|
120
147
|
if WebMock::Config.instance.net_http_connect_on_start
|
121
|
-
|
148
|
+
super(&block)
|
122
149
|
else
|
123
150
|
start_without_connect(&block)
|
124
151
|
end
|
125
152
|
end
|
126
|
-
alias_method :start_with_connect, :start
|
127
|
-
alias_method :start, :start_with_conditional_connect
|
128
153
|
|
129
154
|
def build_net_http_response(webmock_response, &block)
|
130
155
|
response = Net::HTTPResponse.send(:response_class, webmock_response.status[0].to_s).new("1.0", webmock_response.status[0].to_s, webmock_response.status[1])
|
131
|
-
|
156
|
+
body = webmock_response.body
|
157
|
+
body = nil if webmock_response.status[0].to_s == '204'
|
158
|
+
|
159
|
+
response.instance_variable_set(:@body, body)
|
132
160
|
webmock_response.headers.to_a.each do |name, values|
|
133
161
|
values = [values] unless values.is_a?(Array)
|
134
162
|
values.each do |value|
|
@@ -140,7 +168,9 @@ module WebMock
|
|
140
168
|
|
141
169
|
response.extend Net::WebMockHTTPResponse
|
142
170
|
|
143
|
-
|
171
|
+
if webmock_response.should_timeout
|
172
|
+
raise timeout_exception, "execution expired"
|
173
|
+
end
|
144
174
|
|
145
175
|
webmock_response.raise_error_if_any
|
146
176
|
|
@@ -149,6 +179,16 @@ module WebMock
|
|
149
179
|
response
|
150
180
|
end
|
151
181
|
|
182
|
+
def timeout_exception
|
183
|
+
if defined?(Net::OpenTimeout)
|
184
|
+
# Ruby 2.x
|
185
|
+
Net::OpenTimeout
|
186
|
+
else
|
187
|
+
# Fallback, if things change
|
188
|
+
Timeout::Error
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
152
192
|
def build_webmock_response(net_http_response)
|
153
193
|
webmock_response = WebMock::Response.new
|
154
194
|
webmock_response.status = [
|
@@ -182,9 +222,22 @@ module WebMock
|
|
182
222
|
end
|
183
223
|
end
|
184
224
|
|
225
|
+
# patch for StringIO behavior in Ruby 2.2.3
|
226
|
+
# https://github.com/bblimke/webmock/issues/558
|
227
|
+
class PatchedStringIO < StringIO #:nodoc:
|
228
|
+
|
229
|
+
alias_method :orig_read_nonblock, :read_nonblock
|
230
|
+
|
231
|
+
def read_nonblock(size, *args, **kwargs)
|
232
|
+
args.reject! {|arg| !arg.is_a?(Hash)}
|
233
|
+
orig_read_nonblock(size, *args, **kwargs)
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
185
238
|
class StubSocket #:nodoc:
|
186
239
|
|
187
|
-
attr_accessor :read_timeout
|
240
|
+
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
188
241
|
|
189
242
|
def initialize(*args)
|
190
243
|
end
|
@@ -193,29 +246,64 @@ class StubSocket #:nodoc:
|
|
193
246
|
@closed ||= true
|
194
247
|
end
|
195
248
|
|
249
|
+
def close
|
250
|
+
end
|
251
|
+
|
196
252
|
def readuntil(*args)
|
197
253
|
end
|
198
254
|
|
255
|
+
def io
|
256
|
+
@io ||= StubIO.new
|
257
|
+
end
|
258
|
+
|
259
|
+
class StubIO
|
260
|
+
def setsockopt(*args); end
|
261
|
+
end
|
199
262
|
end
|
200
263
|
|
201
264
|
module Net #:nodoc: all
|
202
265
|
|
203
266
|
class WebMockNetBufferedIO < BufferedIO
|
204
|
-
def
|
205
|
-
|
206
|
-
@rbuf = ''
|
207
|
-
@debug_output = debug_output
|
208
|
-
|
209
|
-
@io = case io
|
267
|
+
def initialize(io, *args, **kwargs)
|
268
|
+
io = case io
|
210
269
|
when Socket, OpenSSL::SSL::SSLSocket, IO
|
211
270
|
io
|
271
|
+
when StringIO
|
272
|
+
PatchedStringIO.new(io.string)
|
212
273
|
when String
|
213
|
-
|
274
|
+
PatchedStringIO.new(io)
|
275
|
+
end
|
276
|
+
raise "Unable to create local socket" unless io
|
277
|
+
|
278
|
+
# Prior to 2.4.0 `BufferedIO` only takes a single argument (`io`) with no
|
279
|
+
# options. Here we pass through our full set of arguments only if we're
|
280
|
+
# on 2.4.0 or later, and use a simplified invocation otherwise.
|
281
|
+
if RUBY_VERSION >= '2.4.0'
|
282
|
+
super
|
283
|
+
else
|
284
|
+
super(io)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
if RUBY_VERSION >= '2.6.0'
|
289
|
+
# https://github.com/ruby/ruby/blob/7d02441f0d6e5c9d0a73a024519eba4f69e36dce/lib/net/protocol.rb#L208
|
290
|
+
# Modified version of method from ruby, so that nil is always passed into orig_read_nonblock to avoid timeout
|
291
|
+
def rbuf_fill
|
292
|
+
case rv = @io.read_nonblock(BUFSIZE, nil, exception: false)
|
293
|
+
when String
|
294
|
+
return if rv.nil?
|
295
|
+
@rbuf << rv
|
296
|
+
rv.clear
|
297
|
+
return
|
298
|
+
when :wait_readable
|
299
|
+
@io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
|
300
|
+
when :wait_writable
|
301
|
+
@io.to_io.wait_writable(@read_timeout) or raise Net::ReadTimeout
|
302
|
+
when nil
|
303
|
+
raise EOFError, 'end of file reached'
|
304
|
+
end while true
|
214
305
|
end
|
215
|
-
raise "Unable to create local socket" unless @io
|
216
306
|
end
|
217
|
-
alias_method :initialize_without_webmock, :initialize
|
218
|
-
alias_method :initialize, :initialize_with_webmock
|
219
307
|
end
|
220
308
|
|
221
309
|
end
|
@@ -225,25 +313,19 @@ module WebMock
|
|
225
313
|
module NetHTTPUtility
|
226
314
|
|
227
315
|
def self.request_signature_from_request(net_http, request, body = nil)
|
228
|
-
protocol = net_http.use_ssl? ? "https" : "http"
|
229
|
-
|
230
316
|
path = request.path
|
231
|
-
path = WebMock::Util::URI.heuristic_parse(request.path).request_uri if request.path =~ /^http/
|
232
317
|
|
233
|
-
if
|
234
|
-
|
235
|
-
userinfo = WebMock::Util::URI.encode_unsafe_chars_in_userinfo(userinfo) + "@"
|
236
|
-
else
|
237
|
-
userinfo = ""
|
318
|
+
if path.respond_to?(:request_uri) #https://github.com/bblimke/webmock/issues/288
|
319
|
+
path = path.request_uri
|
238
320
|
end
|
239
321
|
|
240
|
-
|
322
|
+
path = WebMock::Util::URI.heuristic_parse(path).request_uri if path =~ /^http/
|
323
|
+
|
324
|
+
uri = get_uri(net_http, path)
|
241
325
|
method = request.method.downcase.to_sym
|
242
326
|
|
243
327
|
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
244
|
-
|
245
|
-
headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v.first =~ /^Basic / } #we added it to url userinfo
|
246
|
-
|
328
|
+
validate_headers(headers)
|
247
329
|
|
248
330
|
if request.body_stream
|
249
331
|
body = request.body_stream.read
|
@@ -256,9 +338,36 @@ module WebMock
|
|
256
338
|
request.set_body_internal body
|
257
339
|
end
|
258
340
|
|
259
|
-
WebMock::RequestSignature.new(method, uri, :
|
341
|
+
WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.get_uri(net_http, path)
|
345
|
+
protocol = net_http.use_ssl? ? "https" : "http"
|
346
|
+
|
347
|
+
hostname = net_http.address
|
348
|
+
hostname = "[#{hostname}]" if /\A\[.*\]\z/ !~ hostname && /:/ =~ hostname
|
349
|
+
|
350
|
+
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
260
351
|
end
|
261
352
|
|
353
|
+
def self.validate_headers(headers)
|
354
|
+
# For Ruby versions < 2.3.0, if you make a request with headers that are symbols
|
355
|
+
# Net::HTTP raises a NoMethodError
|
356
|
+
#
|
357
|
+
# WebMock normalizes headers when creating a RequestSignature,
|
358
|
+
# and will update all headers from symbols to strings.
|
359
|
+
#
|
360
|
+
# This could create a false positive in a test suite with WebMock.
|
361
|
+
#
|
362
|
+
# So before this point, WebMock raises an ArgumentError if any of the headers are symbols
|
363
|
+
# instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
|
364
|
+
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
|
365
|
+
header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
|
366
|
+
if header_as_symbol
|
367
|
+
raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
262
371
|
|
263
372
|
def self.check_right_http_connection
|
264
373
|
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
@@ -13,7 +13,7 @@ if defined?(::Patron)
|
|
13
13
|
OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
|
14
14
|
|
15
15
|
class WebMockPatronSession < ::Patron::Session
|
16
|
-
def
|
16
|
+
def handle_request(req)
|
17
17
|
request_signature =
|
18
18
|
WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
|
19
19
|
|
@@ -25,15 +25,15 @@ if defined?(::Patron)
|
|
25
25
|
res = WebMock::HttpLibAdapters::PatronAdapter.
|
26
26
|
build_patron_response(webmock_response, default_response_charset)
|
27
27
|
WebMock::CallbackRegistry.invoke_callbacks(
|
28
|
-
{:
|
28
|
+
{lib: :patron}, request_signature, webmock_response)
|
29
29
|
res
|
30
30
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
31
|
-
res =
|
31
|
+
res = super
|
32
32
|
if WebMock::CallbackRegistry.any_callbacks?
|
33
33
|
webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
|
34
34
|
build_webmock_response(res)
|
35
35
|
WebMock::CallbackRegistry.invoke_callbacks(
|
36
|
-
{:
|
36
|
+
{lib: :patron, real_request: true}, request_signature,
|
37
37
|
webmock_response)
|
38
38
|
end
|
39
39
|
res
|
@@ -41,9 +41,6 @@ if defined?(::Patron)
|
|
41
41
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
alias_method :handle_request_without_webmock, :handle_request
|
46
|
-
alias_method :handle_request, :handle_request_with_webmock
|
47
44
|
end
|
48
45
|
|
49
46
|
def self.enable!
|
@@ -71,10 +68,8 @@ if defined?(::Patron)
|
|
71
68
|
def self.build_request_signature(req)
|
72
69
|
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
73
70
|
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
74
|
-
uri.user = req.username
|
75
|
-
uri.password = req.password
|
76
71
|
|
77
|
-
if [:put, :post].include?(req.action)
|
72
|
+
if [:put, :post, :patch].include?(req.action)
|
78
73
|
if req.file_name
|
79
74
|
if !File.exist?(req.file_name) || !File.readable?(req.file_name)
|
80
75
|
raise ArgumentError.new("Unable to open specified file.")
|
@@ -87,11 +82,17 @@ if defined?(::Patron)
|
|
87
82
|
end
|
88
83
|
end
|
89
84
|
|
85
|
+
headers = req.headers
|
86
|
+
|
87
|
+
if req.credentials
|
88
|
+
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.credentials)
|
89
|
+
end
|
90
|
+
|
90
91
|
request_signature = WebMock::RequestSignature.new(
|
91
92
|
req.action,
|
92
93
|
uri.to_s,
|
93
|
-
:
|
94
|
-
:
|
94
|
+
body: request_body,
|
95
|
+
headers: headers
|
95
96
|
)
|
96
97
|
request_signature
|
97
98
|
end
|
@@ -105,11 +106,11 @@ if defined?(::Patron)
|
|
105
106
|
header_data = ([status_line] + header_fields).join("\r\n")
|
106
107
|
|
107
108
|
::Patron::Response.new(
|
108
|
-
"",
|
109
|
+
"".dup,
|
109
110
|
webmock_response.status[0],
|
110
111
|
0,
|
111
112
|
header_data,
|
112
|
-
webmock_response.body,
|
113
|
+
webmock_response.body.dup,
|
113
114
|
default_response_charset
|
114
115
|
)
|
115
116
|
end
|
@@ -117,7 +118,7 @@ if defined?(::Patron)
|
|
117
118
|
def self.build_webmock_response(patron_response)
|
118
119
|
webmock_response = WebMock::Response.new
|
119
120
|
reason = patron_response.status_line.
|
120
|
-
scan(%r(\AHTTP/(\d
|
121
|
+
scan(%r(\AHTTP/(\d+(?:\.\d+)?)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
|
121
122
|
webmock_response.status = [patron_response.status, reason]
|
122
123
|
webmock_response.body = patron_response.body
|
123
124
|
webmock_response.headers = patron_response.headers
|
@@ -14,53 +14,63 @@ if defined?(Typhoeus)
|
|
14
14
|
|
15
15
|
def self.enable!
|
16
16
|
@disabled = false
|
17
|
+
add_before_callback
|
17
18
|
add_after_request_callback
|
18
|
-
::Typhoeus::
|
19
|
+
::Typhoeus::Config.block_connection = true
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.disable!
|
22
23
|
@disabled = true
|
23
24
|
remove_after_request_callback
|
24
|
-
|
25
|
+
remove_before_callback
|
26
|
+
::Typhoeus::Config.block_connection = false
|
25
27
|
end
|
26
28
|
|
27
29
|
def self.disabled?
|
28
30
|
!!@disabled
|
29
31
|
end
|
30
32
|
|
33
|
+
def self.add_before_callback
|
34
|
+
unless Typhoeus.before.include?(BEFORE_CALLBACK)
|
35
|
+
Typhoeus.before << BEFORE_CALLBACK
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.remove_before_callback
|
40
|
+
Typhoeus.before.delete_if {|v| v == BEFORE_CALLBACK }
|
41
|
+
end
|
42
|
+
|
31
43
|
def self.add_after_request_callback
|
32
|
-
unless Typhoeus
|
33
|
-
|
34
|
-
include?(AFTER_REQUEST_CALLBACK)
|
35
|
-
Typhoeus::Hydra.
|
36
|
-
global_hooks[:after_request_before_on_complete] << AFTER_REQUEST_CALLBACK
|
44
|
+
unless Typhoeus.on_complete.include?(AFTER_REQUEST_CALLBACK)
|
45
|
+
Typhoeus.on_complete << AFTER_REQUEST_CALLBACK
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
40
49
|
def self.remove_after_request_callback
|
41
|
-
Typhoeus
|
42
|
-
delete_if {|v| v == AFTER_REQUEST_CALLBACK }
|
50
|
+
Typhoeus.on_complete.delete_if {|v| v == AFTER_REQUEST_CALLBACK }
|
43
51
|
end
|
44
52
|
|
45
53
|
def self.build_request_signature(req)
|
46
54
|
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
47
55
|
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
48
|
-
|
49
|
-
|
50
|
-
|
56
|
+
|
57
|
+
headers = req.options[:headers]
|
58
|
+
|
59
|
+
if req.options[:userpwd]
|
60
|
+
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.options[:userpwd])
|
51
61
|
end
|
52
62
|
|
53
|
-
body = req.body
|
63
|
+
body = req.options[:body]
|
54
64
|
|
55
|
-
if
|
56
|
-
body =
|
65
|
+
if body.is_a?(Hash)
|
66
|
+
body = WebMock::Util::QueryMapper.values_to_query(body)
|
57
67
|
end
|
58
68
|
|
59
69
|
request_signature = WebMock::RequestSignature.new(
|
60
|
-
req.method,
|
70
|
+
req.options[:method] || :get,
|
61
71
|
uri.to_s,
|
62
|
-
:
|
63
|
-
:
|
72
|
+
body: body,
|
73
|
+
headers: headers
|
64
74
|
)
|
65
75
|
|
66
76
|
req.instance_variable_set(:@__webmock_request_signature, request_signature)
|
@@ -68,45 +78,35 @@ if defined?(Typhoeus)
|
|
68
78
|
request_signature
|
69
79
|
end
|
70
80
|
|
71
|
-
def self.request_body_for_post_request_with_params(req)
|
72
|
-
params = req.params
|
73
|
-
form = Typhoeus::Form.new(params)
|
74
|
-
form.process!
|
75
|
-
form.to_s
|
76
|
-
end
|
77
81
|
|
78
82
|
def self.build_webmock_response(typhoeus_response)
|
79
83
|
webmock_response = WebMock::Response.new
|
80
84
|
webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message]
|
81
85
|
webmock_response.body = typhoeus_response.body
|
82
|
-
webmock_response.headers = typhoeus_response.
|
86
|
+
webmock_response.headers = typhoeus_response.headers
|
83
87
|
webmock_response
|
84
88
|
end
|
85
89
|
|
86
|
-
def self.
|
90
|
+
def self.generate_typhoeus_response(request_signature, webmock_response)
|
87
91
|
response = if webmock_response.should_timeout
|
88
92
|
::Typhoeus::Response.new(
|
89
|
-
:
|
90
|
-
:
|
91
|
-
:
|
92
|
-
:
|
93
|
-
:
|
93
|
+
code: 0,
|
94
|
+
status_message: "",
|
95
|
+
body: "",
|
96
|
+
headers: {},
|
97
|
+
return_code: :operation_timedout
|
94
98
|
)
|
95
99
|
else
|
96
100
|
::Typhoeus::Response.new(
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
100
|
-
:
|
101
|
+
code: webmock_response.status[0],
|
102
|
+
status_message: webmock_response.status[1],
|
103
|
+
body: webmock_response.body,
|
104
|
+
headers: webmock_response.headers,
|
105
|
+
effective_url: request_signature.uri
|
101
106
|
)
|
102
107
|
end
|
103
|
-
|
104
|
-
|
105
|
-
typhoeus.stub(
|
106
|
-
request_signature.method || :any,
|
107
|
-
/.*/,
|
108
|
-
:webmock_stub => true
|
109
|
-
).and_return(response)
|
108
|
+
response.mock = :webmock
|
109
|
+
response
|
110
110
|
end
|
111
111
|
|
112
112
|
def self.request_hash(request_signature)
|
@@ -118,62 +118,56 @@ if defined?(Typhoeus)
|
|
118
118
|
hash
|
119
119
|
end
|
120
120
|
|
121
|
-
AFTER_REQUEST_CALLBACK = Proc.new do |
|
121
|
+
AFTER_REQUEST_CALLBACK = Proc.new do |response|
|
122
|
+
request = response.request
|
122
123
|
request_signature = request.instance_variable_get(:@__webmock_request_signature)
|
123
124
|
webmock_response =
|
124
125
|
::WebMock::HttpLibAdapters::TyphoeusAdapter.
|
125
|
-
build_webmock_response(
|
126
|
-
if
|
126
|
+
build_webmock_response(response)
|
127
|
+
if response.mock
|
127
128
|
WebMock::CallbackRegistry.invoke_callbacks(
|
128
|
-
{:
|
129
|
+
{lib: :typhoeus},
|
129
130
|
request_signature,
|
130
131
|
webmock_response
|
131
132
|
)
|
132
133
|
else
|
133
134
|
WebMock::CallbackRegistry.invoke_callbacks(
|
134
|
-
{:
|
135
|
+
{lib: :typhoeus, real_request: true},
|
135
136
|
request_signature,
|
136
137
|
webmock_response
|
137
138
|
)
|
138
139
|
end
|
139
140
|
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
|
145
|
-
module Typhoeus
|
146
|
-
class Hydra
|
147
|
-
def queue_with_webmock(request)
|
148
|
-
self.clear_webmock_stubs
|
149
|
-
|
150
|
-
if WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
|
151
|
-
return queue_without_webmock(request)
|
152
|
-
end
|
153
|
-
|
154
|
-
request_signature =
|
155
|
-
::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
|
156
141
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
142
|
+
BEFORE_CALLBACK = Proc.new do |request|
|
143
|
+
Typhoeus::Expectation.all.delete_if {|e| e.from == :webmock }
|
144
|
+
res = true
|
145
|
+
|
146
|
+
unless WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
|
147
|
+
request_signature = ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
|
148
|
+
request.block_connection = false;
|
149
|
+
|
150
|
+
::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
151
|
+
|
152
|
+
if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
|
153
|
+
# ::WebMock::HttpLibAdapters::TyphoeusAdapter.stub_typhoeus(request_signature, webmock_response, self)
|
154
|
+
response = ::WebMock::HttpLibAdapters::TyphoeusAdapter.generate_typhoeus_response(request_signature, webmock_response)
|
155
|
+
if request.respond_to?(:on_headers)
|
156
|
+
request.execute_headers_callbacks(response)
|
157
|
+
end
|
158
|
+
if request.respond_to?(:streaming?) && request.streaming?
|
159
|
+
response.options[:response_body] = ""
|
160
|
+
request.on_body.each { |callback| callback.call(webmock_response.body, response) }
|
161
|
+
end
|
162
|
+
request.finish(response)
|
163
|
+
webmock_response.raise_error_if_any
|
164
|
+
res = false
|
165
|
+
elsif !WebMock.net_connect_allowed?(request_signature.uri)
|
166
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
res
|
165
170
|
end
|
166
|
-
queue_without_webmock(request)
|
167
|
-
end
|
168
|
-
|
169
|
-
alias_method :queue_without_webmock, :queue
|
170
|
-
alias_method :queue, :queue_with_webmock
|
171
|
-
|
172
|
-
def clear_webmock_stubs
|
173
|
-
self.stubs = [] unless self.stubs
|
174
|
-
self.stubs.delete_if {|s|
|
175
|
-
s.instance_variable_get(:@options)[:webmock_stub]
|
176
|
-
}
|
177
171
|
end
|
178
172
|
end
|
179
173
|
end
|