ultra-pure-gem 0.0.1
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/ultra-pure-gem.gemspec +12 -0
- data/webmock-3.26.2/CHANGELOG.md +2148 -0
- data/webmock-3.26.2/LICENSE +20 -0
- data/webmock-3.26.2/README.md +1229 -0
- data/webmock-3.26.2/lib/webmock/api.rb +111 -0
- data/webmock-3.26.2/lib/webmock/assertion_failure.rb +13 -0
- data/webmock-3.26.2/lib/webmock/callback_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/config.rb +20 -0
- data/webmock-3.26.2/lib/webmock/cucumber.rb +12 -0
- data/webmock-3.26.2/lib/webmock/deprecation.rb +11 -0
- data/webmock-3.26.2/lib/webmock/errors.rb +19 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +228 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/curb_adapter.rb +354 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +239 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/excon_adapter.rb +167 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter.rb +9 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +21 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/request.rb +28 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/response.rb +95 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/streamer.rb +44 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/webmock.rb +77 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb_adapter.rb +39 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/httpclient_adapter.rb +260 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/manticore_adapter.rb +147 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http.rb +310 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http_response.rb +36 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/patron_adapter.rb +132 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +190 -0
- data/webmock-3.26.2/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_including_matcher.rb +19 -0
- data/webmock-3.26.2/lib/webmock/minitest.rb +43 -0
- data/webmock-3.26.2/lib/webmock/rack_response.rb +73 -0
- data/webmock-3.26.2/lib/webmock/request_body_diff.rb +66 -0
- data/webmock-3.26.2/lib/webmock/request_execution_verifier.rb +79 -0
- data/webmock-3.26.2/lib/webmock/request_pattern.rb +428 -0
- data/webmock-3.26.2/lib/webmock/request_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/request_signature.rb +56 -0
- data/webmock-3.26.2/lib/webmock/request_signature_snippet.rb +63 -0
- data/webmock-3.26.2/lib/webmock/request_stub.rb +134 -0
- data/webmock-3.26.2/lib/webmock/response.rb +161 -0
- data/webmock-3.26.2/lib/webmock/responses_sequence.rb +42 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/request_pattern_matcher.rb +80 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/webmock_matcher.rb +69 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers.rb +29 -0
- data/webmock-3.26.2/lib/webmock/rspec.rb +44 -0
- data/webmock-3.26.2/lib/webmock/stub_registry.rb +84 -0
- data/webmock-3.26.2/lib/webmock/stub_request_snippet.rb +40 -0
- data/webmock-3.26.2/lib/webmock/test_unit.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/hash_counter.rb +45 -0
- data/webmock-3.26.2/lib/webmock/util/hash_keys_stringifier.rb +27 -0
- data/webmock-3.26.2/lib/webmock/util/hash_validator.rb +19 -0
- data/webmock-3.26.2/lib/webmock/util/headers.rb +77 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/json.rb +72 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/parse_error.rb +7 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/xml.rb +16 -0
- data/webmock-3.26.2/lib/webmock/util/query_mapper.rb +283 -0
- data/webmock-3.26.2/lib/webmock/util/uri.rb +113 -0
- data/webmock-3.26.2/lib/webmock/util/values_stringifier.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/version_checker.rb +113 -0
- data/webmock-3.26.2/lib/webmock/version.rb +5 -0
- data/webmock-3.26.2/lib/webmock/webmock.rb +175 -0
- data/webmock-3.26.2/lib/webmock.rb +61 -0
- metadata +106 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'net/https'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require File.join(File.dirname(__FILE__), 'net_http_response')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module WebMock
|
|
10
|
+
module HttpLibAdapters
|
|
11
|
+
class NetHttpAdapter < HttpLibAdapter
|
|
12
|
+
adapter_for :net_http
|
|
13
|
+
|
|
14
|
+
OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
|
|
15
|
+
# This will be removed in Ruby 3.5. In Ruby 3.4, const_remove will warn.
|
|
16
|
+
HAS_LEGACY_CONSTANT = Net.const_defined?(:HTTPSession)
|
|
17
|
+
|
|
18
|
+
def self.enable!
|
|
19
|
+
Net.send(:remove_const, :HTTP)
|
|
20
|
+
Net.send(:const_set, :HTTP, @webMockNetHTTP)
|
|
21
|
+
if HAS_LEGACY_CONSTANT
|
|
22
|
+
remove_silently(Net, :HTTPSession)
|
|
23
|
+
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.disable!
|
|
28
|
+
Net.send(:remove_const, :HTTP)
|
|
29
|
+
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
|
30
|
+
if HAS_LEGACY_CONSTANT
|
|
31
|
+
remove_silently(Net, :HTTPSession)
|
|
32
|
+
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
|
36
|
+
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
|
37
|
+
#after WebMock was enabled.
|
|
38
|
+
#i.e Net::HTTP::DigestAuth
|
|
39
|
+
@webMockNetHTTP.constants.each do |constant|
|
|
40
|
+
if !OriginalNetHTTP.constants.map(&:to_s).include?(constant.to_s)
|
|
41
|
+
OriginalNetHTTP.send(:const_set, constant, @webMockNetHTTP.const_get(constant))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.remove_silently(mod, const) #:nodoc:
|
|
47
|
+
# Don't warn on removing the deprecated constant
|
|
48
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
|
49
|
+
mod.send(:remove_const, const)
|
|
50
|
+
ensure
|
|
51
|
+
$VERBOSE = verbose
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
@webMockNetHTTP = Class.new(Net::HTTP) do
|
|
55
|
+
class << self
|
|
56
|
+
def socket_type
|
|
57
|
+
StubSocket
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if Module.method(:const_defined?).arity == 1
|
|
61
|
+
def const_defined?(name)
|
|
62
|
+
super || self.superclass.const_defined?(name)
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
def const_defined?(name, inherit=true)
|
|
66
|
+
super || self.superclass.const_defined?(name, inherit)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if Module.method(:const_get).arity != 1
|
|
71
|
+
def const_get(name, inherit=true)
|
|
72
|
+
super
|
|
73
|
+
rescue NameError
|
|
74
|
+
self.superclass.const_get(name, inherit)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if Module.method(:constants).arity != 0
|
|
79
|
+
def constants(inherit=true)
|
|
80
|
+
(super + self.superclass.constants(inherit)).uniq
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def request(request, body = nil, &block)
|
|
86
|
+
request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
|
|
87
|
+
|
|
88
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
89
|
+
|
|
90
|
+
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
91
|
+
@socket = Net::HTTP.socket_type.new
|
|
92
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
93
|
+
{lib: :net_http}, request_signature, webmock_response)
|
|
94
|
+
build_net_http_response(webmock_response, request.uri, &block)
|
|
95
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
96
|
+
check_right_http_connection
|
|
97
|
+
after_request = lambda do |response|
|
|
98
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
99
|
+
webmock_response = build_webmock_response(response)
|
|
100
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
101
|
+
{lib: :net_http, real_request: true}, request_signature, webmock_response)
|
|
102
|
+
end
|
|
103
|
+
response.extend Net::WebMockHTTPResponse
|
|
104
|
+
block.call response if block
|
|
105
|
+
response
|
|
106
|
+
end
|
|
107
|
+
super_with_after_request = lambda {
|
|
108
|
+
response = super(request, nil, &nil)
|
|
109
|
+
after_request.call(response)
|
|
110
|
+
}
|
|
111
|
+
if started?
|
|
112
|
+
ensure_actual_connection
|
|
113
|
+
super_with_after_request.call
|
|
114
|
+
else
|
|
115
|
+
start_with_connect {
|
|
116
|
+
super_with_after_request.call
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def start_without_connect
|
|
125
|
+
raise IOError, 'HTTP session already opened' if @started
|
|
126
|
+
if block_given?
|
|
127
|
+
begin
|
|
128
|
+
@socket = Net::HTTP.socket_type.new
|
|
129
|
+
@started = true
|
|
130
|
+
return yield(self)
|
|
131
|
+
ensure
|
|
132
|
+
do_finish
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
@socket = Net::HTTP.socket_type.new
|
|
136
|
+
@started = true
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def ensure_actual_connection
|
|
142
|
+
if @socket.is_a?(StubSocket)
|
|
143
|
+
@socket&.close
|
|
144
|
+
@socket = nil
|
|
145
|
+
do_start
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
alias_method :start_with_connect, :start
|
|
150
|
+
|
|
151
|
+
def start(&block)
|
|
152
|
+
uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
|
|
153
|
+
|
|
154
|
+
if WebMock.net_http_connect_on_start?(uri)
|
|
155
|
+
super(&block)
|
|
156
|
+
else
|
|
157
|
+
start_without_connect(&block)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def build_net_http_response(webmock_response, request_uri, &block)
|
|
162
|
+
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])
|
|
163
|
+
body = webmock_response.body
|
|
164
|
+
body = nil if webmock_response.status[0].to_s == '204'
|
|
165
|
+
|
|
166
|
+
response.instance_variable_set(:@body, body)
|
|
167
|
+
webmock_response.headers.to_a.each do |name, values|
|
|
168
|
+
values = [values] unless values.is_a?(Array)
|
|
169
|
+
values.each do |value|
|
|
170
|
+
response.add_field(name, value)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
response.instance_variable_set(:@read, true)
|
|
175
|
+
|
|
176
|
+
response.uri = request_uri
|
|
177
|
+
|
|
178
|
+
response.extend Net::WebMockHTTPResponse
|
|
179
|
+
|
|
180
|
+
if webmock_response.should_timeout
|
|
181
|
+
raise Net::OpenTimeout, "execution expired"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
webmock_response.raise_error_if_any
|
|
185
|
+
|
|
186
|
+
yield response if block_given?
|
|
187
|
+
|
|
188
|
+
response
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def build_webmock_response(net_http_response)
|
|
192
|
+
webmock_response = WebMock::Response.new
|
|
193
|
+
webmock_response.status = [
|
|
194
|
+
net_http_response.code.to_i,
|
|
195
|
+
net_http_response.message]
|
|
196
|
+
webmock_response.headers = net_http_response.to_hash
|
|
197
|
+
webmock_response.body = net_http_response.body
|
|
198
|
+
webmock_response
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def check_right_http_connection
|
|
203
|
+
unless @@already_checked_for_right_http_connection ||= false
|
|
204
|
+
WebMock::NetHTTPUtility.puts_warning_for_right_http_if_needed
|
|
205
|
+
@@already_checked_for_right_http_connection = true
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
@webMockNetHTTP.version_1_2
|
|
210
|
+
[
|
|
211
|
+
[:Get, Net::HTTP::Get],
|
|
212
|
+
[:Post, Net::HTTP::Post],
|
|
213
|
+
[:Put, Net::HTTP::Put],
|
|
214
|
+
[:Delete, Net::HTTP::Delete],
|
|
215
|
+
[:Head, Net::HTTP::Head],
|
|
216
|
+
[:Options, Net::HTTP::Options]
|
|
217
|
+
].each do |c|
|
|
218
|
+
@webMockNetHTTP.const_set(c[0], c[1])
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class StubSocket #:nodoc:
|
|
225
|
+
|
|
226
|
+
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
|
227
|
+
|
|
228
|
+
def initialize(*args)
|
|
229
|
+
@closed = false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def closed?
|
|
233
|
+
@closed
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def close
|
|
237
|
+
@closed = true
|
|
238
|
+
nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def readuntil(*args)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def io
|
|
245
|
+
@io ||= StubIO.new
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
class StubIO
|
|
249
|
+
def setsockopt(*args); end
|
|
250
|
+
def peer_cert; end
|
|
251
|
+
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
|
|
252
|
+
def ssl_version; "TLSv1.3" end
|
|
253
|
+
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
module WebMock
|
|
258
|
+
module NetHTTPUtility
|
|
259
|
+
|
|
260
|
+
def self.request_signature_from_request(net_http, request, body = nil)
|
|
261
|
+
path = request.path
|
|
262
|
+
|
|
263
|
+
if path.respond_to?(:request_uri) #https://github.com/bblimke/webmock/issues/288
|
|
264
|
+
path = path.request_uri
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
path = WebMock::Util::URI.heuristic_parse(path).request_uri if path =~ /^http/
|
|
268
|
+
|
|
269
|
+
uri = get_uri(net_http, path)
|
|
270
|
+
method = request.method.downcase.to_sym
|
|
271
|
+
|
|
272
|
+
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
|
273
|
+
|
|
274
|
+
if request.body_stream
|
|
275
|
+
body = request.body_stream.read
|
|
276
|
+
request.body_stream = nil
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
if body != nil && body.respond_to?(:read)
|
|
280
|
+
request.set_body_internal body.read
|
|
281
|
+
else
|
|
282
|
+
request.set_body_internal body
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def self.get_uri(net_http, path = nil)
|
|
289
|
+
protocol = net_http.use_ssl? ? "https" : "http"
|
|
290
|
+
|
|
291
|
+
hostname = net_http.address
|
|
292
|
+
hostname = "[#{hostname}]" if /\A\[.*\]\z/ !~ hostname && /:/ =~ hostname
|
|
293
|
+
|
|
294
|
+
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def self.check_right_http_connection
|
|
298
|
+
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def self.puts_warning_for_right_http_if_needed
|
|
302
|
+
if !@was_right_http_connection_loaded && defined?(RightHttpConnection)
|
|
303
|
+
$stderr.puts "\nWarning: RightHttpConnection has to be required before WebMock is required !!!\n"
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
WebMock::NetHTTPUtility.check_right_http_connection
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
|
|
4
|
+
|
|
5
|
+
# A Net::HTTP response that has already been read raises an IOError when #read_body
|
|
6
|
+
# is called with a destination string or block.
|
|
7
|
+
#
|
|
8
|
+
# This causes a problem when VCR records a response--it reads the body before yielding
|
|
9
|
+
# the response, and if the code that is consuming the HTTP requests uses #read_body, it
|
|
10
|
+
# can cause an error.
|
|
11
|
+
#
|
|
12
|
+
# This is a bit of a hack, but it allows a Net::HTTP response to be "re-read"
|
|
13
|
+
# after it has aleady been read. This attemps to preserve the behavior of
|
|
14
|
+
# #read_body, acting just as if it had never been read.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
module Net
|
|
18
|
+
module WebMockHTTPResponse
|
|
19
|
+
def read_body(dest = nil, &block)
|
|
20
|
+
if !(defined?(@__read_body_previously_called).nil?) && @__read_body_previously_called
|
|
21
|
+
return super
|
|
22
|
+
end
|
|
23
|
+
return @body if dest.nil? && block.nil?
|
|
24
|
+
raise ArgumentError.new("both arg and block given for HTTP method") if dest && block
|
|
25
|
+
return nil if @body.nil?
|
|
26
|
+
|
|
27
|
+
dest ||= ::Net::ReadAdapter.new(block)
|
|
28
|
+
dest << @body.dup
|
|
29
|
+
@body = dest
|
|
30
|
+
ensure
|
|
31
|
+
# allow subsequent calls to #read_body to proceed as normal, without our hack...
|
|
32
|
+
@__read_body_previously_called = true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'patron'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
# patron not found
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
if defined?(::Patron::Session)
|
|
10
|
+
module WebMock
|
|
11
|
+
module HttpLibAdapters
|
|
12
|
+
class PatronAdapter < ::WebMock::HttpLibAdapter
|
|
13
|
+
adapter_for :patron
|
|
14
|
+
|
|
15
|
+
OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
|
|
16
|
+
|
|
17
|
+
class WebMockPatronSession < ::Patron::Session
|
|
18
|
+
def handle_request(req)
|
|
19
|
+
request_signature =
|
|
20
|
+
WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
|
|
21
|
+
|
|
22
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
23
|
+
|
|
24
|
+
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
25
|
+
WebMock::HttpLibAdapters::PatronAdapter.
|
|
26
|
+
handle_file_name(req, webmock_response)
|
|
27
|
+
res = WebMock::HttpLibAdapters::PatronAdapter.
|
|
28
|
+
build_patron_response(webmock_response, default_response_charset)
|
|
29
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
30
|
+
{lib: :patron}, request_signature, webmock_response)
|
|
31
|
+
res
|
|
32
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
33
|
+
res = super
|
|
34
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
35
|
+
webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
|
|
36
|
+
build_webmock_response(res)
|
|
37
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
38
|
+
{lib: :patron, real_request: true}, request_signature,
|
|
39
|
+
webmock_response)
|
|
40
|
+
end
|
|
41
|
+
res
|
|
42
|
+
else
|
|
43
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.enable!
|
|
49
|
+
Patron.send(:remove_const, :Session)
|
|
50
|
+
Patron.send(:const_set, :Session, WebMockPatronSession)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.disable!
|
|
54
|
+
Patron.send(:remove_const, :Session)
|
|
55
|
+
Patron.send(:const_set, :Session, OriginalPatronSession)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.handle_file_name(req, webmock_response)
|
|
59
|
+
if req.action == :get && req.file_name
|
|
60
|
+
begin
|
|
61
|
+
File.open(req.file_name, "w") do |f|
|
|
62
|
+
f.write webmock_response.body
|
|
63
|
+
end
|
|
64
|
+
rescue Errno::EACCES
|
|
65
|
+
raise ArgumentError.new("Unable to open specified file.")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.build_request_signature(req)
|
|
71
|
+
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
|
72
|
+
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
|
73
|
+
|
|
74
|
+
if [:put, :post, :patch].include?(req.action)
|
|
75
|
+
if req.file_name
|
|
76
|
+
if !File.exist?(req.file_name) || !File.readable?(req.file_name)
|
|
77
|
+
raise ArgumentError.new("Unable to open specified file.")
|
|
78
|
+
end
|
|
79
|
+
request_body = File.read(req.file_name)
|
|
80
|
+
elsif req.upload_data
|
|
81
|
+
request_body = req.upload_data
|
|
82
|
+
else
|
|
83
|
+
raise ArgumentError.new("Must provide either data or a filename when doing a PUT or POST")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
headers = req.headers
|
|
88
|
+
|
|
89
|
+
if req.credentials
|
|
90
|
+
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.credentials)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
request_signature = WebMock::RequestSignature.new(
|
|
94
|
+
req.action,
|
|
95
|
+
uri.to_s,
|
|
96
|
+
body: request_body,
|
|
97
|
+
headers: headers
|
|
98
|
+
)
|
|
99
|
+
request_signature
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.build_patron_response(webmock_response, default_response_charset)
|
|
103
|
+
raise ::Patron::TimeoutError if webmock_response.should_timeout
|
|
104
|
+
webmock_response.raise_error_if_any
|
|
105
|
+
|
|
106
|
+
header_fields = (webmock_response.headers || []).map { |(k, vs)| Array(vs).map { |v| "#{k}: #{v}" } }.flatten
|
|
107
|
+
status_line = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}"
|
|
108
|
+
header_data = ([status_line] + header_fields).join("\r\n")
|
|
109
|
+
|
|
110
|
+
::Patron::Response.new(
|
|
111
|
+
"".dup,
|
|
112
|
+
webmock_response.status[0],
|
|
113
|
+
0,
|
|
114
|
+
header_data,
|
|
115
|
+
webmock_response.body.dup,
|
|
116
|
+
default_response_charset
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.build_webmock_response(patron_response)
|
|
121
|
+
webmock_response = WebMock::Response.new
|
|
122
|
+
reason = patron_response.status_line.
|
|
123
|
+
scan(%r(\AHTTP/(\d+(?:\.\d+)?)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
|
|
124
|
+
webmock_response.status = [patron_response.status, reason]
|
|
125
|
+
webmock_response.body = patron_response.body
|
|
126
|
+
webmock_response.headers = patron_response.headers
|
|
127
|
+
webmock_response
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'typhoeus'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
# typhoeus not found
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
if defined?(Typhoeus)
|
|
10
|
+
WebMock::VersionChecker.new('Typhoeus', Typhoeus::VERSION, '0.3.2').check_version!
|
|
11
|
+
|
|
12
|
+
module WebMock
|
|
13
|
+
module HttpLibAdapters
|
|
14
|
+
class TyphoeusAdapter < HttpLibAdapter
|
|
15
|
+
adapter_for :typhoeus
|
|
16
|
+
|
|
17
|
+
def self.enable!
|
|
18
|
+
@disabled = false
|
|
19
|
+
add_before_callback
|
|
20
|
+
add_after_request_callback
|
|
21
|
+
::Typhoeus::Config.block_connection = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.disable!
|
|
25
|
+
@disabled = true
|
|
26
|
+
remove_after_request_callback
|
|
27
|
+
remove_before_callback
|
|
28
|
+
::Typhoeus::Config.block_connection = false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.disabled?
|
|
32
|
+
!!@disabled
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.add_before_callback
|
|
36
|
+
unless Typhoeus.before.include?(BEFORE_CALLBACK)
|
|
37
|
+
Typhoeus.before << BEFORE_CALLBACK
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.remove_before_callback
|
|
42
|
+
Typhoeus.before.delete_if {|v| v == BEFORE_CALLBACK }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.add_after_request_callback
|
|
46
|
+
unless Typhoeus.on_complete.include?(AFTER_REQUEST_CALLBACK)
|
|
47
|
+
Typhoeus.on_complete << AFTER_REQUEST_CALLBACK
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.remove_after_request_callback
|
|
52
|
+
Typhoeus.on_complete.delete_if {|v| v == AFTER_REQUEST_CALLBACK }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.build_request_signature(req)
|
|
56
|
+
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
|
57
|
+
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
|
58
|
+
|
|
59
|
+
headers = req.options[:headers]
|
|
60
|
+
|
|
61
|
+
if req.options[:userpwd]
|
|
62
|
+
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.options[:userpwd])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
body = req.options[:body]
|
|
66
|
+
|
|
67
|
+
if body.is_a?(Hash)
|
|
68
|
+
body = WebMock::Util::QueryMapper.values_to_query(body)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
request_signature = WebMock::RequestSignature.new(
|
|
72
|
+
req.options[:method] || :get,
|
|
73
|
+
uri.to_s,
|
|
74
|
+
body: body,
|
|
75
|
+
headers: headers
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
req.instance_variable_set(:@__webmock_request_signature, request_signature)
|
|
79
|
+
|
|
80
|
+
request_signature
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def self.build_webmock_response(typhoeus_response)
|
|
85
|
+
webmock_response = WebMock::Response.new
|
|
86
|
+
webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message]
|
|
87
|
+
webmock_response.body = typhoeus_response.body
|
|
88
|
+
webmock_response.headers = typhoeus_response.headers
|
|
89
|
+
webmock_response
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.generate_typhoeus_response(request_signature, webmock_response)
|
|
93
|
+
response = if webmock_response.should_timeout
|
|
94
|
+
::Typhoeus::Response.new(
|
|
95
|
+
code: 0,
|
|
96
|
+
status_message: "",
|
|
97
|
+
body: "",
|
|
98
|
+
headers: {},
|
|
99
|
+
return_code: :operation_timedout,
|
|
100
|
+
total_time: 0.0,
|
|
101
|
+
starttransfer_time: 0.0,
|
|
102
|
+
appconnect_time: 0.0,
|
|
103
|
+
pretransfer_time: 0.0,
|
|
104
|
+
connect_time: 0.0,
|
|
105
|
+
namelookup_time: 0.0,
|
|
106
|
+
redirect_time: 0.0
|
|
107
|
+
)
|
|
108
|
+
else
|
|
109
|
+
::Typhoeus::Response.new(
|
|
110
|
+
code: webmock_response.status[0],
|
|
111
|
+
status_message: webmock_response.status[1],
|
|
112
|
+
body: webmock_response.body,
|
|
113
|
+
headers: webmock_response.headers,
|
|
114
|
+
effective_url: request_signature.uri,
|
|
115
|
+
total_time: 0.0,
|
|
116
|
+
starttransfer_time: 0.0,
|
|
117
|
+
appconnect_time: 0.0,
|
|
118
|
+
pretransfer_time: 0.0,
|
|
119
|
+
connect_time: 0.0,
|
|
120
|
+
namelookup_time: 0.0,
|
|
121
|
+
redirect_time: 0.0
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
response.mock = :webmock
|
|
125
|
+
response
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.request_hash(request_signature)
|
|
129
|
+
hash = {}
|
|
130
|
+
|
|
131
|
+
hash[:body] = request_signature.body
|
|
132
|
+
hash[:headers] = request_signature.headers
|
|
133
|
+
|
|
134
|
+
hash
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
AFTER_REQUEST_CALLBACK = Proc.new do |response|
|
|
138
|
+
request = response.request
|
|
139
|
+
request_signature = request.instance_variable_get(:@__webmock_request_signature)
|
|
140
|
+
webmock_response =
|
|
141
|
+
::WebMock::HttpLibAdapters::TyphoeusAdapter.
|
|
142
|
+
build_webmock_response(response)
|
|
143
|
+
if response.mock
|
|
144
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
145
|
+
{lib: :typhoeus},
|
|
146
|
+
request_signature,
|
|
147
|
+
webmock_response
|
|
148
|
+
)
|
|
149
|
+
else
|
|
150
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
151
|
+
{lib: :typhoeus, real_request: true},
|
|
152
|
+
request_signature,
|
|
153
|
+
webmock_response
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
BEFORE_CALLBACK = Proc.new do |request|
|
|
159
|
+
Typhoeus::Expectation.all.delete_if {|e| e.from == :webmock }
|
|
160
|
+
res = true
|
|
161
|
+
|
|
162
|
+
unless WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
|
|
163
|
+
request_signature = ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
|
|
164
|
+
request.block_connection = false;
|
|
165
|
+
|
|
166
|
+
::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
167
|
+
|
|
168
|
+
if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
169
|
+
# ::WebMock::HttpLibAdapters::TyphoeusAdapter.stub_typhoeus(request_signature, webmock_response, self)
|
|
170
|
+
response = ::WebMock::HttpLibAdapters::TyphoeusAdapter.generate_typhoeus_response(request_signature, webmock_response)
|
|
171
|
+
if request.respond_to?(:on_headers)
|
|
172
|
+
request.execute_headers_callbacks(response)
|
|
173
|
+
end
|
|
174
|
+
if request.respond_to?(:streaming?) && request.streaming?
|
|
175
|
+
response.options[:response_body] = "".dup
|
|
176
|
+
request.on_body.each { |callback| callback.call(webmock_response.body, response) }
|
|
177
|
+
end
|
|
178
|
+
request.finish(response)
|
|
179
|
+
webmock_response.raise_error_if_any
|
|
180
|
+
res = false
|
|
181
|
+
elsif !WebMock.net_connect_allowed?(request_signature.uri)
|
|
182
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
res
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
module Matchers
|
|
5
|
+
# Base class for Hash matchers
|
|
6
|
+
# https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/argument_matchers.rb
|
|
7
|
+
class HashArgumentMatcher
|
|
8
|
+
def initialize(expected)
|
|
9
|
+
@expected = Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(expected, deep: true).sort]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ==(_actual, &block)
|
|
13
|
+
@expected.all?(&block)
|
|
14
|
+
rescue NoMethodError
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.from_rspec_matcher(matcher)
|
|
19
|
+
new(matcher.instance_variable_get(:@expected))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|