webmock 3.16.2 → 3.23.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 +4 -4
- data/CHANGELOG.md +144 -6
- data/README.md +54 -18
- data/lib/webmock/api.rb +2 -0
- data/lib/webmock/assertion_failure.rb +2 -0
- data/lib/webmock/callback_registry.rb +2 -0
- data/lib/webmock/config.rb +2 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/deprecation.rb +2 -0
- data/lib/webmock/errors.rb +2 -0
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +15 -7
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +17 -5
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +32 -12
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +7 -5
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +26 -25
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +19 -101
- data/lib/webmock/http_lib_adapters/net_http_response.rb +2 -0
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
- data/lib/webmock/matchers/any_arg_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +2 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +2 -0
- data/lib/webmock/minitest.rb +2 -0
- data/lib/webmock/rack_response.rb +5 -1
- data/lib/webmock/request_body_diff.rb +2 -0
- data/lib/webmock/request_execution_verifier.rb +2 -0
- data/lib/webmock/request_pattern.rb +26 -8
- data/lib/webmock/request_registry.rb +2 -0
- data/lib/webmock/request_signature.rb +4 -2
- data/lib/webmock/request_signature_snippet.rb +2 -0
- data/lib/webmock/request_stub.rb +20 -1
- data/lib/webmock/response.rb +15 -13
- data/lib/webmock/responses_sequence.rb +2 -0
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers.rb +2 -0
- data/lib/webmock/rspec.rb +2 -0
- data/lib/webmock/stub_registry.rb +2 -0
- data/lib/webmock/stub_request_snippet.rb +2 -0
- data/lib/webmock/test_unit.rb +2 -0
- data/lib/webmock/util/hash_counter.rb +12 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
- data/lib/webmock/util/hash_validator.rb +2 -0
- data/lib/webmock/util/headers.rb +23 -10
- data/lib/webmock/util/json.rb +2 -0
- data/lib/webmock/util/query_mapper.rb +2 -0
- data/lib/webmock/util/uri.rb +3 -1
- data/lib/webmock/util/values_stringifier.rb +2 -0
- data/lib/webmock/util/version_checker.rb +7 -5
- data/lib/webmock/version.rb +3 -1
- data/lib/webmock/webmock.rb +2 -0
- data/lib/webmock.rb +2 -0
- metadata +43 -161
- data/.gemtest +0 -0
- data/.github/workflows/CI.yml +0 -38
- data/.gitignore +0 -34
- data/.rspec-tm +0 -2
- data/Gemfile +0 -9
- data/Rakefile +0 -38
- data/minitest/test_helper.rb +0 -34
- data/minitest/test_webmock.rb +0 -9
- data/minitest/webmock_spec.rb +0 -60
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +0 -375
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +0 -73
- data/spec/acceptance/curb/curb_spec.rb +0 -510
- data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -462
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
- data/spec/acceptance/excon/excon_spec.rb +0 -77
- data/spec/acceptance/excon/excon_spec_helper.rb +0 -52
- data/spec/acceptance/http_rb/http_rb_spec.rb +0 -93
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -54
- data/spec/acceptance/httpclient/httpclient_spec.rb +0 -217
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
- data/spec/acceptance/manticore/manticore_spec.rb +0 -107
- data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
- data/spec/acceptance/net_http/net_http_shared.rb +0 -190
- data/spec/acceptance/net_http/net_http_spec.rb +0 -396
- data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
- data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
- data/spec/acceptance/patron/patron_spec.rb +0 -125
- data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
- data/spec/acceptance/shared/callbacks.rb +0 -148
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
- data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
- data/spec/acceptance/shared/request_expectations.rb +0 -930
- data/spec/acceptance/shared/returning_declared_responses.rb +0 -409
- data/spec/acceptance/shared/stubbing_requests.rb +0 -678
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
- data/spec/acceptance/webmock_shared.rb +0 -41
- data/spec/fixtures/test.txt +0 -1
- data/spec/quality_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -48
- data/spec/support/example_curl_output.txt +0 -22
- data/spec/support/failures.rb +0 -9
- data/spec/support/my_rack_app.rb +0 -53
- data/spec/support/network_connection.rb +0 -19
- data/spec/support/webmock_server.rb +0 -70
- data/spec/unit/api_spec.rb +0 -175
- data/spec/unit/errors_spec.rb +0 -129
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +0 -61
- data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
- data/spec/unit/rack_response_spec.rb +0 -112
- data/spec/unit/request_body_diff_spec.rb +0 -90
- data/spec/unit/request_execution_verifier_spec.rb +0 -208
- data/spec/unit/request_pattern_spec.rb +0 -736
- data/spec/unit/request_registry_spec.rb +0 -95
- data/spec/unit/request_signature_snippet_spec.rb +0 -89
- data/spec/unit/request_signature_spec.rb +0 -175
- data/spec/unit/request_stub_spec.rb +0 -234
- data/spec/unit/response_spec.rb +0 -286
- data/spec/unit/stub_registry_spec.rb +0 -103
- data/spec/unit/stub_request_snippet_spec.rb +0 -115
- data/spec/unit/util/hash_counter_spec.rb +0 -39
- data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
- data/spec/unit/util/headers_spec.rb +0 -28
- data/spec/unit/util/json_spec.rb +0 -33
- data/spec/unit/util/query_mapper_spec.rb +0 -157
- data/spec/unit/util/uri_spec.rb +0 -371
- data/spec/unit/util/version_checker_spec.rb +0 -65
- data/spec/unit/webmock_spec.rb +0 -114
- data/test/http_request.rb +0 -24
- data/test/shared_test.rb +0 -108
- data/test/test_helper.rb +0 -23
- data/test/test_webmock.rb +0 -12
- data/webmock.gemspec +0 -54
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'httpclient'
|
|
3
5
|
require 'jsonclient' # defined in 'httpclient' gem as well
|
|
@@ -43,6 +45,8 @@ if defined?(::HTTPClient)
|
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
module WebMockHTTPClients
|
|
48
|
+
WEBMOCK_HTTPCLIENT_RESPONSES = :webmock_httpclient_responses
|
|
49
|
+
WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES = :webmock_httpclient_request_signatures
|
|
46
50
|
|
|
47
51
|
REQUEST_RESPONSE_LOCK = Mutex.new
|
|
48
52
|
|
|
@@ -55,12 +59,14 @@ if defined?(::HTTPClient)
|
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
def do_get(req, proxy, conn, stream = false, &block)
|
|
62
|
+
clear_thread_variables unless conn.async_thread
|
|
63
|
+
|
|
58
64
|
request_signature = build_request_signature(req, :reuse_existing)
|
|
59
65
|
|
|
60
66
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
61
67
|
|
|
62
68
|
if webmock_responses[request_signature]
|
|
63
|
-
webmock_response =
|
|
69
|
+
webmock_response = webmock_responses.delete(request_signature)
|
|
64
70
|
response = build_httpclient_response(webmock_response, stream, req.header, &block)
|
|
65
71
|
@request_filter.each do |filter|
|
|
66
72
|
filter.filter_response(req, response)
|
|
@@ -71,7 +77,7 @@ if defined?(::HTTPClient)
|
|
|
71
77
|
res
|
|
72
78
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
73
79
|
# in case there is a nil entry in the hash...
|
|
74
|
-
|
|
80
|
+
webmock_responses.delete(request_signature)
|
|
75
81
|
|
|
76
82
|
res = if stream
|
|
77
83
|
do_get_stream_without_webmock(req, proxy, conn, &block)
|
|
@@ -101,12 +107,16 @@ if defined?(::HTTPClient)
|
|
|
101
107
|
end
|
|
102
108
|
|
|
103
109
|
def do_request_async(method, uri, query, body, extheader)
|
|
110
|
+
clear_thread_variables
|
|
104
111
|
req = create_request(method, uri, query, body, extheader)
|
|
105
112
|
request_signature = build_request_signature(req)
|
|
106
|
-
|
|
113
|
+
webmock_request_signatures << request_signature
|
|
107
114
|
|
|
108
115
|
if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
|
|
109
|
-
super
|
|
116
|
+
conn = super
|
|
117
|
+
conn.async_thread[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES]
|
|
118
|
+
conn.async_thread[WEBMOCK_HTTPCLIENT_RESPONSES] = Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES]
|
|
119
|
+
conn
|
|
110
120
|
else
|
|
111
121
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
112
122
|
end
|
|
@@ -155,14 +165,14 @@ if defined?(::HTTPClient)
|
|
|
155
165
|
end
|
|
156
166
|
|
|
157
167
|
def build_request_signature(req, reuse_existing = false)
|
|
158
|
-
uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
|
|
159
|
-
uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
|
|
160
|
-
uri.port = req.header.request_uri.port
|
|
161
|
-
|
|
162
168
|
@request_filter.each do |filter|
|
|
163
169
|
filter.filter_request(req)
|
|
164
170
|
end
|
|
165
171
|
|
|
172
|
+
uri = WebMock::Util::URI.heuristic_parse(req.header.request_uri.to_s)
|
|
173
|
+
uri.query = WebMock::Util::QueryMapper.values_to_query(req.header.request_query, notation: WebMock::Config.instance.query_values_notation) if req.header.request_query
|
|
174
|
+
uri.port = req.header.request_uri.port
|
|
175
|
+
|
|
166
176
|
headers = req.header.all.inject({}) do |hdrs, header|
|
|
167
177
|
hdrs[header[0]] ||= []
|
|
168
178
|
hdrs[header[0]] << header[1]
|
|
@@ -186,22 +196,18 @@ if defined?(::HTTPClient)
|
|
|
186
196
|
end
|
|
187
197
|
|
|
188
198
|
def webmock_responses
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
192
|
-
end
|
|
199
|
+
Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] ||= Hash.new do |hash, request_signature|
|
|
200
|
+
hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
193
201
|
end
|
|
194
202
|
end
|
|
195
203
|
|
|
196
204
|
def webmock_request_signatures
|
|
197
|
-
|
|
205
|
+
Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
|
|
198
206
|
end
|
|
199
207
|
|
|
200
208
|
def previous_signature_for(signature)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
webmock_request_signatures.delete_at(index)
|
|
204
|
-
end
|
|
209
|
+
return nil unless index = webmock_request_signatures.index(signature)
|
|
210
|
+
webmock_request_signatures.delete_at(index)
|
|
205
211
|
end
|
|
206
212
|
|
|
207
213
|
private
|
|
@@ -217,14 +223,9 @@ if defined?(::HTTPClient)
|
|
|
217
223
|
end
|
|
218
224
|
end
|
|
219
225
|
|
|
220
|
-
def
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
else
|
|
224
|
-
REQUEST_RESPONSE_LOCK.synchronize do
|
|
225
|
-
yield
|
|
226
|
-
end
|
|
227
|
-
end
|
|
226
|
+
def clear_thread_variables
|
|
227
|
+
Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] = nil
|
|
228
|
+
Thread.current[WEBMOCK_HTTPCLIENT_RESPONSES] = nil
|
|
228
229
|
end
|
|
229
230
|
end
|
|
230
231
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'net/http'
|
|
2
4
|
require 'net/https'
|
|
3
5
|
require 'stringio'
|
|
@@ -10,24 +12,19 @@ module WebMock
|
|
|
10
12
|
adapter_for :net_http
|
|
11
13
|
|
|
12
14
|
OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
|
|
13
|
-
OriginalNetBufferedIO = Net::BufferedIO unless const_defined?(:OriginalNetBufferedIO)
|
|
14
15
|
|
|
15
16
|
def self.enable!
|
|
16
|
-
Net.send(:remove_const, :BufferedIO)
|
|
17
17
|
Net.send(:remove_const, :HTTP)
|
|
18
18
|
Net.send(:remove_const, :HTTPSession)
|
|
19
19
|
Net.send(:const_set, :HTTP, @webMockNetHTTP)
|
|
20
20
|
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
|
|
21
|
-
Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
def self.disable!
|
|
25
|
-
Net.send(:remove_const, :BufferedIO)
|
|
26
24
|
Net.send(:remove_const, :HTTP)
|
|
27
25
|
Net.send(:remove_const, :HTTPSession)
|
|
28
26
|
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
|
29
27
|
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
|
30
|
-
Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
|
|
31
28
|
|
|
32
29
|
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
|
33
30
|
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
|
@@ -80,7 +77,7 @@ module WebMock
|
|
|
80
77
|
@socket = Net::HTTP.socket_type.new
|
|
81
78
|
WebMock::CallbackRegistry.invoke_callbacks(
|
|
82
79
|
{lib: :net_http}, request_signature, webmock_response)
|
|
83
|
-
build_net_http_response(webmock_response, &block)
|
|
80
|
+
build_net_http_response(webmock_response, request.uri, &block)
|
|
84
81
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
85
82
|
check_right_http_connection
|
|
86
83
|
after_request = lambda do |response|
|
|
@@ -128,7 +125,11 @@ module WebMock
|
|
|
128
125
|
|
|
129
126
|
|
|
130
127
|
def ensure_actual_connection
|
|
131
|
-
|
|
128
|
+
if @socket.is_a?(StubSocket)
|
|
129
|
+
@socket&.close
|
|
130
|
+
@socket = nil
|
|
131
|
+
do_start
|
|
132
|
+
end
|
|
132
133
|
end
|
|
133
134
|
|
|
134
135
|
alias_method :start_with_connect, :start
|
|
@@ -143,7 +144,7 @@ module WebMock
|
|
|
143
144
|
end
|
|
144
145
|
end
|
|
145
146
|
|
|
146
|
-
def build_net_http_response(webmock_response, &block)
|
|
147
|
+
def build_net_http_response(webmock_response, request_uri, &block)
|
|
147
148
|
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])
|
|
148
149
|
body = webmock_response.body
|
|
149
150
|
body = nil if webmock_response.status[0].to_s == '204'
|
|
@@ -158,10 +159,12 @@ module WebMock
|
|
|
158
159
|
|
|
159
160
|
response.instance_variable_set(:@read, true)
|
|
160
161
|
|
|
162
|
+
response.uri = request_uri
|
|
163
|
+
|
|
161
164
|
response.extend Net::WebMockHTTPResponse
|
|
162
165
|
|
|
163
166
|
if webmock_response.should_timeout
|
|
164
|
-
raise
|
|
167
|
+
raise Net::OpenTimeout, "execution expired"
|
|
165
168
|
end
|
|
166
169
|
|
|
167
170
|
webmock_response.raise_error_if_any
|
|
@@ -171,16 +174,6 @@ module WebMock
|
|
|
171
174
|
response
|
|
172
175
|
end
|
|
173
176
|
|
|
174
|
-
def timeout_exception
|
|
175
|
-
if defined?(Net::OpenTimeout)
|
|
176
|
-
# Ruby 2.x
|
|
177
|
-
Net::OpenTimeout
|
|
178
|
-
else
|
|
179
|
-
# Fallback, if things change
|
|
180
|
-
Timeout::Error
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
177
|
def build_webmock_response(net_http_response)
|
|
185
178
|
webmock_response = WebMock::Response.new
|
|
186
179
|
webmock_response.status = [
|
|
@@ -214,31 +207,21 @@ module WebMock
|
|
|
214
207
|
end
|
|
215
208
|
end
|
|
216
209
|
|
|
217
|
-
# patch for StringIO behavior in Ruby 2.2.3
|
|
218
|
-
# https://github.com/bblimke/webmock/issues/558
|
|
219
|
-
class PatchedStringIO < StringIO #:nodoc:
|
|
220
|
-
|
|
221
|
-
alias_method :orig_read_nonblock, :read_nonblock
|
|
222
|
-
|
|
223
|
-
def read_nonblock(size, *args, **kwargs)
|
|
224
|
-
args.reject! {|arg| !arg.is_a?(Hash)}
|
|
225
|
-
orig_read_nonblock(size, *args, **kwargs)
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
end
|
|
229
|
-
|
|
230
210
|
class StubSocket #:nodoc:
|
|
231
211
|
|
|
232
212
|
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
|
233
213
|
|
|
234
214
|
def initialize(*args)
|
|
215
|
+
@closed = false
|
|
235
216
|
end
|
|
236
217
|
|
|
237
218
|
def closed?
|
|
238
|
-
@closed
|
|
219
|
+
@closed
|
|
239
220
|
end
|
|
240
221
|
|
|
241
222
|
def close
|
|
223
|
+
@closed = true
|
|
224
|
+
nil
|
|
242
225
|
end
|
|
243
226
|
|
|
244
227
|
def readuntil(*args)
|
|
@@ -251,57 +234,12 @@ class StubSocket #:nodoc:
|
|
|
251
234
|
class StubIO
|
|
252
235
|
def setsockopt(*args); end
|
|
253
236
|
def peer_cert; end
|
|
237
|
+
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
|
|
238
|
+
def ssl_version; "TLSv1.3" end
|
|
239
|
+
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
|
|
254
240
|
end
|
|
255
241
|
end
|
|
256
242
|
|
|
257
|
-
module Net #:nodoc: all
|
|
258
|
-
|
|
259
|
-
class WebMockNetBufferedIO < BufferedIO
|
|
260
|
-
def initialize(io, *args, **kwargs)
|
|
261
|
-
io = case io
|
|
262
|
-
when Socket, OpenSSL::SSL::SSLSocket, IO
|
|
263
|
-
io
|
|
264
|
-
when StringIO
|
|
265
|
-
PatchedStringIO.new(io.string)
|
|
266
|
-
when String
|
|
267
|
-
PatchedStringIO.new(io)
|
|
268
|
-
end
|
|
269
|
-
raise "Unable to create local socket" unless io
|
|
270
|
-
|
|
271
|
-
# Prior to 2.4.0 `BufferedIO` only takes a single argument (`io`) with no
|
|
272
|
-
# options. Here we pass through our full set of arguments only if we're
|
|
273
|
-
# on 2.4.0 or later, and use a simplified invocation otherwise.
|
|
274
|
-
if RUBY_VERSION >= '2.4.0'
|
|
275
|
-
super
|
|
276
|
-
else
|
|
277
|
-
super(io)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
if RUBY_VERSION >= '2.6.0'
|
|
282
|
-
# https://github.com/ruby/ruby/blob/7d02441f0d6e5c9d0a73a024519eba4f69e36dce/lib/net/protocol.rb#L208
|
|
283
|
-
# Modified version of method from ruby, so that nil is always passed into orig_read_nonblock to avoid timeout
|
|
284
|
-
def rbuf_fill
|
|
285
|
-
case rv = @io.read_nonblock(BUFSIZE, nil, exception: false)
|
|
286
|
-
when String
|
|
287
|
-
return if rv.nil?
|
|
288
|
-
@rbuf << rv
|
|
289
|
-
rv.clear
|
|
290
|
-
return
|
|
291
|
-
when :wait_readable
|
|
292
|
-
@io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
|
|
293
|
-
when :wait_writable
|
|
294
|
-
@io.to_io.wait_writable(@read_timeout) or raise Net::ReadTimeout
|
|
295
|
-
when nil
|
|
296
|
-
raise EOFError, 'end of file reached'
|
|
297
|
-
end while true
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
|
|
305
243
|
module WebMock
|
|
306
244
|
module NetHTTPUtility
|
|
307
245
|
|
|
@@ -318,7 +256,6 @@ module WebMock
|
|
|
318
256
|
method = request.method.downcase.to_sym
|
|
319
257
|
|
|
320
258
|
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
|
321
|
-
validate_headers(headers)
|
|
322
259
|
|
|
323
260
|
if request.body_stream
|
|
324
261
|
body = request.body_stream.read
|
|
@@ -343,25 +280,6 @@ module WebMock
|
|
|
343
280
|
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
|
344
281
|
end
|
|
345
282
|
|
|
346
|
-
def self.validate_headers(headers)
|
|
347
|
-
# For Ruby versions < 2.3.0, if you make a request with headers that are symbols
|
|
348
|
-
# Net::HTTP raises a NoMethodError
|
|
349
|
-
#
|
|
350
|
-
# WebMock normalizes headers when creating a RequestSignature,
|
|
351
|
-
# and will update all headers from symbols to strings.
|
|
352
|
-
#
|
|
353
|
-
# This could create a false positive in a test suite with WebMock.
|
|
354
|
-
#
|
|
355
|
-
# So before this point, WebMock raises an ArgumentError if any of the headers are symbols
|
|
356
|
-
# instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
|
|
357
|
-
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
|
|
358
|
-
header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
|
|
359
|
-
if header_as_symbol
|
|
360
|
-
raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
283
|
def self.check_right_http_connection
|
|
366
284
|
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
|
367
285
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'typhoeus'
|
|
3
5
|
rescue LoadError
|
|
@@ -94,7 +96,14 @@ if defined?(Typhoeus)
|
|
|
94
96
|
status_message: "",
|
|
95
97
|
body: "",
|
|
96
98
|
headers: {},
|
|
97
|
-
return_code: :operation_timedout
|
|
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
|
|
98
107
|
)
|
|
99
108
|
else
|
|
100
109
|
::Typhoeus::Response.new(
|
|
@@ -102,7 +111,14 @@ if defined?(Typhoeus)
|
|
|
102
111
|
status_message: webmock_response.status[1],
|
|
103
112
|
body: webmock_response.body,
|
|
104
113
|
headers: webmock_response.headers,
|
|
105
|
-
effective_url: request_signature.uri
|
|
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
|
|
106
122
|
)
|
|
107
123
|
end
|
|
108
124
|
response.mock = :webmock
|
data/lib/webmock/minitest.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
class RackResponse < Response
|
|
3
5
|
def initialize(app)
|
|
@@ -45,7 +47,9 @@ module WebMock
|
|
|
45
47
|
# Rack-specific variables
|
|
46
48
|
env['rack.input'] = StringIO.new(body)
|
|
47
49
|
env['rack.errors'] = $stderr
|
|
48
|
-
|
|
50
|
+
if !Rack.const_defined?(:RELEASE) || Rack::RELEASE < "3"
|
|
51
|
+
env['rack.version'] = Rack::VERSION
|
|
52
|
+
end
|
|
49
53
|
env['rack.url_scheme'] = uri.scheme
|
|
50
54
|
env['rack.run_once'] = true
|
|
51
55
|
env['rack.session'] = session
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
module RSpecMatcherDetector
|
|
@@ -281,7 +283,9 @@ module WebMock
|
|
|
281
283
|
if (@pattern).is_a?(Hash)
|
|
282
284
|
return true if @pattern.empty?
|
|
283
285
|
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
|
|
284
|
-
elsif (@pattern).is_a?(
|
|
286
|
+
elsif (@pattern).is_a?(Array)
|
|
287
|
+
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
|
|
288
|
+
elsif (@pattern).is_a?(WebMock::Matchers::HashArgumentMatcher)
|
|
285
289
|
@pattern == body_as_hash(body, content_type)
|
|
286
290
|
else
|
|
287
291
|
empty_string?(@pattern) && empty_string?(body) ||
|
|
@@ -344,19 +348,33 @@ module WebMock
|
|
|
344
348
|
def matching_body_hashes?(query_parameters, pattern, content_type)
|
|
345
349
|
return false unless query_parameters.is_a?(Hash)
|
|
346
350
|
return false unless query_parameters.keys.sort == pattern.keys.sort
|
|
347
|
-
|
|
351
|
+
|
|
352
|
+
query_parameters.all? do |key, actual|
|
|
348
353
|
expected = pattern[key]
|
|
354
|
+
matching_values(actual, expected, content_type)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
349
357
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
358
|
+
def matching_body_array?(query_parameters, pattern, content_type)
|
|
359
|
+
return false unless query_parameters.is_a?(Array)
|
|
360
|
+
return false unless query_parameters.length == pattern.length
|
|
361
|
+
|
|
362
|
+
query_parameters.each_with_index do |actual, index|
|
|
363
|
+
expected = pattern[index]
|
|
364
|
+
return false unless matching_values(actual, expected, content_type)
|
|
356
365
|
end
|
|
366
|
+
|
|
357
367
|
true
|
|
358
368
|
end
|
|
359
369
|
|
|
370
|
+
def matching_values(actual, expected, content_type)
|
|
371
|
+
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
|
|
372
|
+
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
|
|
373
|
+
|
|
374
|
+
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
|
|
375
|
+
expected === actual
|
|
376
|
+
end
|
|
377
|
+
|
|
360
378
|
def empty_string?(string)
|
|
361
379
|
string.nil? || string == ""
|
|
362
380
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
class RequestSignature
|
|
@@ -35,11 +37,11 @@ module WebMock
|
|
|
35
37
|
alias == eql?
|
|
36
38
|
|
|
37
39
|
def url_encoded?
|
|
38
|
-
!!(headers
|
|
40
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def json_headers?
|
|
42
|
-
!!(headers
|
|
44
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
private
|
data/lib/webmock/request_stub.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
class RequestStub
|
|
3
5
|
|
|
@@ -29,9 +31,26 @@ module WebMock
|
|
|
29
31
|
|
|
30
32
|
json_response_hashes = [*response_hashes].flatten.map do |resp_h|
|
|
31
33
|
headers, body = resp_h.values_at(:headers, :body)
|
|
34
|
+
|
|
35
|
+
json_body = if body.respond_to?(:call)
|
|
36
|
+
->(request_signature) {
|
|
37
|
+
b = if body.respond_to?(:arity) && body.arity == 1
|
|
38
|
+
body.call(request_signature)
|
|
39
|
+
else
|
|
40
|
+
body.call
|
|
41
|
+
end
|
|
42
|
+
b = b.to_json unless b.is_a?(String)
|
|
43
|
+
b
|
|
44
|
+
}
|
|
45
|
+
elsif !body.is_a?(String)
|
|
46
|
+
body.to_json
|
|
47
|
+
else
|
|
48
|
+
body
|
|
49
|
+
end
|
|
50
|
+
|
|
32
51
|
resp_h.merge(
|
|
33
52
|
headers: {content_type: 'application/json'}.merge(headers.to_h),
|
|
34
|
-
body:
|
|
53
|
+
body: json_body
|
|
35
54
|
)
|
|
36
55
|
end
|
|
37
56
|
|
data/lib/webmock/response.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "pathname"
|
|
2
4
|
|
|
3
5
|
module WebMock
|
|
@@ -14,8 +16,11 @@ module WebMock
|
|
|
14
16
|
|
|
15
17
|
class Response
|
|
16
18
|
def initialize(options = {})
|
|
17
|
-
|
|
19
|
+
case options
|
|
20
|
+
when IO, StringIO
|
|
18
21
|
self.options = read_raw_response(options)
|
|
22
|
+
when String
|
|
23
|
+
self.options = read_raw_response(StringIO.new(options))
|
|
19
24
|
else
|
|
20
25
|
self.options = options
|
|
21
26
|
end
|
|
@@ -33,7 +38,7 @@ module WebMock
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def body
|
|
36
|
-
@body ||
|
|
41
|
+
@body || String.new("")
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def body=(body)
|
|
@@ -112,21 +117,16 @@ module WebMock
|
|
|
112
117
|
return if @body.nil?
|
|
113
118
|
return if valid_types.any? { |c| @body.is_a?(c) }
|
|
114
119
|
|
|
115
|
-
if @body.
|
|
116
|
-
raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}
|
|
117
|
-
"
|
|
120
|
+
if @body.is_a?(Hash)
|
|
121
|
+
raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}. " \
|
|
122
|
+
"Please convert it by calling .to_json .to_xml, or otherwise convert it to a string."
|
|
118
123
|
else
|
|
119
|
-
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
|
|
124
|
+
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given."
|
|
120
125
|
end
|
|
121
126
|
end
|
|
122
127
|
|
|
123
|
-
def read_raw_response(
|
|
124
|
-
|
|
125
|
-
string = raw_response.read
|
|
126
|
-
raw_response.close
|
|
127
|
-
raw_response = string
|
|
128
|
-
end
|
|
129
|
-
socket = ::Net::BufferedIO.new(raw_response)
|
|
128
|
+
def read_raw_response(io)
|
|
129
|
+
socket = ::Net::BufferedIO.new(io)
|
|
130
130
|
response = ::Net::HTTPResponse.read_new(socket)
|
|
131
131
|
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
|
|
132
132
|
response.reading_body(socket, true) {}
|
|
@@ -138,6 +138,8 @@ module WebMock
|
|
|
138
138
|
options[:body] = response.read_body
|
|
139
139
|
options[:status] = [response.code.to_i, response.message]
|
|
140
140
|
options
|
|
141
|
+
ensure
|
|
142
|
+
socket.close
|
|
141
143
|
end
|
|
142
144
|
|
|
143
145
|
InvalidBody = Class.new(StandardError)
|