webmock 3.0.1 → 3.20.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 +5 -5
- data/CHANGELOG.md +558 -2
- data/README.md +200 -42
- data/lib/webmock/api.rb +14 -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 +223 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +21 -5
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +20 -9
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +7 -2
- 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 +4 -1
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +19 -1
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +29 -3
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +11 -3
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +9 -3
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +30 -9
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +35 -15
- data/lib/webmock/http_lib_adapters/net_http.rb +38 -89
- data/lib/webmock/http_lib_adapters/net_http_response.rb +3 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +6 -4
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
- data/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +6 -23
- data/lib/webmock/minitest.rb +2 -0
- data/lib/webmock/rack_response.rb +3 -1
- data/lib/webmock/request_body_diff.rb +3 -1
- data/lib/webmock/request_execution_verifier.rb +4 -3
- data/lib/webmock/request_pattern.rb +132 -52
- data/lib/webmock/request_registry.rb +3 -1
- data/lib/webmock/request_signature.rb +5 -3
- data/lib/webmock/request_signature_snippet.rb +6 -4
- data/lib/webmock/request_stub.rb +34 -0
- data/lib/webmock/response.rb +22 -14
- 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 +12 -3
- data/lib/webmock/stub_registry.rb +28 -11
- data/lib/webmock/stub_request_snippet.rb +12 -6
- data/lib/webmock/test_unit.rb +3 -3
- data/lib/webmock/util/hash_counter.rb +15 -9
- 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 +39 -11
- data/lib/webmock/util/json.rb +3 -2
- data/lib/webmock/util/query_mapper.rb +11 -7
- data/lib/webmock/util/uri.rb +13 -11
- data/lib/webmock/util/values_stringifier.rb +22 -0
- data/lib/webmock/util/version_checker.rb +7 -5
- data/lib/webmock/version.rb +3 -1
- data/lib/webmock/webmock.rb +22 -3
- data/lib/webmock.rb +55 -48
- metadata +106 -175
- data/.gemtest +0 -0
- data/.gitignore +0 -34
- data/.rspec-tm +0 -2
- data/.travis.yml +0 -20
- data/Gemfile +0 -9
- data/Rakefile +0 -30
- data/minitest/test_helper.rb +0 -34
- data/minitest/test_webmock.rb +0 -9
- data/minitest/webmock_spec.rb +0 -60
- data/spec/acceptance/curb/curb_spec.rb +0 -466
- data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -406
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
- data/spec/acceptance/excon/excon_spec.rb +0 -75
- data/spec/acceptance/excon/excon_spec_helper.rb +0 -50
- data/spec/acceptance/http_rb/http_rb_spec.rb +0 -73
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -51
- data/spec/acceptance/httpclient/httpclient_spec.rb +0 -210
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
- data/spec/acceptance/manticore/manticore_spec.rb +0 -56
- data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
- data/spec/acceptance/net_http/net_http_shared.rb +0 -153
- data/spec/acceptance/net_http/net_http_spec.rb +0 -317
- 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 -118
- 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 -147
- 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 -916
- data/spec/acceptance/shared/returning_declared_responses.rb +0 -388
- data/spec/acceptance/shared/stubbing_requests.rb +0 -583
- 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 -69
- data/spec/unit/api_spec.rb +0 -75
- 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_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 -590
- 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 -155
- data/spec/unit/request_stub_spec.rb +0 -199
- data/spec/unit/response_spec.rb +0 -282
- data/spec/unit/stub_registry_spec.rb +0 -103
- data/spec/unit/stub_request_snippet_spec.rb +0 -95
- 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 -144
- data/spec/unit/util/uri_spec.rb +0 -299
- data/spec/unit/util/version_checker_spec.rb +0 -65
- data/spec/unit/webmock_spec.rb +0 -11
- data/test/http_request.rb +0 -24
- data/test/shared_test.rb +0 -95
- data/test/test_helper.rb +0 -23
- data/test/test_webmock.rb +0 -6
- data/webmock.gemspec +0 -46
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'curb'
|
|
3
5
|
rescue LoadError
|
|
@@ -5,7 +7,7 @@ rescue LoadError
|
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
if defined?(Curl)
|
|
8
|
-
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '0.
|
|
10
|
+
WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '1.0.1', ['0.8.7']).check_version!
|
|
9
11
|
|
|
10
12
|
module WebMock
|
|
11
13
|
module HttpLibAdapters
|
|
@@ -54,7 +56,6 @@ if defined?(Curl)
|
|
|
54
56
|
|
|
55
57
|
module Curl
|
|
56
58
|
class WebMockCurlEasy < Curl::Easy
|
|
57
|
-
|
|
58
59
|
def curb_or_webmock
|
|
59
60
|
request_signature = build_request_signature
|
|
60
61
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
@@ -129,7 +130,7 @@ if defined?(Curl)
|
|
|
129
130
|
def headers_as_hash(headers)
|
|
130
131
|
if headers.is_a?(Array)
|
|
131
132
|
headers.inject({}) {|hash, header|
|
|
132
|
-
name, value = header.split(":").map(&:strip)
|
|
133
|
+
name, value = header.split(":", 2).map(&:strip)
|
|
133
134
|
hash[name] = value
|
|
134
135
|
hash
|
|
135
136
|
}
|
|
@@ -153,7 +154,7 @@ if defined?(Curl)
|
|
|
153
154
|
@body_str = webmock_response.body
|
|
154
155
|
@response_code = webmock_response.status[0]
|
|
155
156
|
|
|
156
|
-
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n"
|
|
157
|
+
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n".dup
|
|
157
158
|
|
|
158
159
|
@on_debug.call(@header_str, 1) if defined?( @on_debug )
|
|
159
160
|
|
|
@@ -183,7 +184,7 @@ if defined?(Curl)
|
|
|
183
184
|
self.url = location
|
|
184
185
|
|
|
185
186
|
curb_or_webmock do
|
|
186
|
-
send(
|
|
187
|
+
send( :http, {'method' => @webmock_method} )
|
|
187
188
|
end
|
|
188
189
|
|
|
189
190
|
self.url = first_url
|
|
@@ -271,6 +272,8 @@ if defined?(Curl)
|
|
|
271
272
|
def perform
|
|
272
273
|
@webmock_method ||= :get
|
|
273
274
|
curb_or_webmock { super }
|
|
275
|
+
ensure
|
|
276
|
+
reset_webmock_method
|
|
274
277
|
end
|
|
275
278
|
|
|
276
279
|
def put_data= data
|
|
@@ -332,6 +335,19 @@ if defined?(Curl)
|
|
|
332
335
|
end
|
|
333
336
|
METHOD
|
|
334
337
|
end
|
|
338
|
+
|
|
339
|
+
def reset_webmock_method
|
|
340
|
+
@webmock_method = :get
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def reset
|
|
344
|
+
instance_variable_set(:@body_str, nil)
|
|
345
|
+
instance_variable_set(:@content_type, nil)
|
|
346
|
+
instance_variable_set(:@header_str, nil)
|
|
347
|
+
instance_variable_set(:@last_effective_url, nil)
|
|
348
|
+
instance_variable_set(:@response_code, nil)
|
|
349
|
+
super
|
|
350
|
+
end
|
|
335
351
|
end
|
|
336
352
|
end
|
|
337
353
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'em-http-request'
|
|
3
5
|
rescue LoadError
|
|
@@ -99,6 +101,11 @@ if defined?(EventMachine::HttpClient)
|
|
|
99
101
|
end
|
|
100
102
|
end
|
|
101
103
|
|
|
104
|
+
def connection_completed
|
|
105
|
+
@state = :response_header
|
|
106
|
+
send_request(*headers_and_body_processed_by_middleware)
|
|
107
|
+
end
|
|
108
|
+
|
|
102
109
|
def send_request(head, body)
|
|
103
110
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
104
111
|
|
|
@@ -107,7 +114,7 @@ if defined?(EventMachine::HttpClient)
|
|
|
107
114
|
@uri ||= nil
|
|
108
115
|
EM.next_tick {
|
|
109
116
|
setup(make_raw_response(stubbed_webmock_response), @uri,
|
|
110
|
-
stubbed_webmock_response.should_timeout ?
|
|
117
|
+
stubbed_webmock_response.should_timeout ? Errno::ETIMEDOUT : nil)
|
|
111
118
|
}
|
|
112
119
|
self
|
|
113
120
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
@@ -149,7 +156,7 @@ if defined?(EventMachine::HttpClient)
|
|
|
149
156
|
raw_cookie = response_header.cookie
|
|
150
157
|
raw_cookie = [raw_cookie] if raw_cookie.is_a? String
|
|
151
158
|
|
|
152
|
-
cookie = raw_cookie.
|
|
159
|
+
cookie = raw_cookie.detect { |c| c.start_with? name }
|
|
153
160
|
cookie and cookie.split('=', 2)[1]
|
|
154
161
|
end
|
|
155
162
|
|
|
@@ -163,12 +170,18 @@ if defined?(EventMachine::HttpClient)
|
|
|
163
170
|
webmock_response
|
|
164
171
|
end
|
|
165
172
|
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
def headers_and_body_processed_by_middleware
|
|
174
|
+
@headers_and_body_processed_by_middleware ||= begin
|
|
175
|
+
head, body = build_request, @req.body
|
|
176
|
+
@conn.middleware.each do |m|
|
|
177
|
+
head, body = m.request(self, head, body) if m.respond_to?(:request)
|
|
178
|
+
end
|
|
179
|
+
[head, body]
|
|
171
180
|
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def build_request_signature
|
|
184
|
+
headers, body = headers_and_body_processed_by_middleware
|
|
172
185
|
|
|
173
186
|
method = @req.method
|
|
174
187
|
uri = @req.uri.clone
|
|
@@ -178,8 +191,6 @@ if defined?(EventMachine::HttpClient)
|
|
|
178
191
|
|
|
179
192
|
body = form_encode_body(body) if body.is_a?(Hash)
|
|
180
193
|
|
|
181
|
-
headers = @req.headers
|
|
182
|
-
|
|
183
194
|
if headers['authorization'] && headers['authorization'].is_a?(Array)
|
|
184
195
|
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(headers.delete('authorization'))
|
|
185
196
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'excon'
|
|
3
5
|
rescue LoadError
|
|
@@ -92,7 +94,7 @@ if defined?(Excon)
|
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
def self.to_query(hash)
|
|
95
|
-
string = ""
|
|
97
|
+
string = "".dup
|
|
96
98
|
for key, values in hash
|
|
97
99
|
if values.nil?
|
|
98
100
|
string << key.to_s << '&'
|
|
@@ -152,11 +154,14 @@ if defined?(Excon)
|
|
|
152
154
|
end
|
|
153
155
|
|
|
154
156
|
Excon::Connection.class_eval do
|
|
155
|
-
def self.new(args)
|
|
157
|
+
def self.new(args = {})
|
|
156
158
|
args.delete(:__construction_args)
|
|
157
159
|
super(args).tap do |instance|
|
|
158
160
|
instance.data[:__construction_args] = args
|
|
159
161
|
end
|
|
160
162
|
end
|
|
161
163
|
end
|
|
164
|
+
|
|
165
|
+
# Suppresses Excon connection argument validation warning
|
|
166
|
+
Excon::VALID_CONNECTION_KEYS << :__construction_args
|
|
162
167
|
end
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTTP
|
|
2
4
|
class Client
|
|
3
5
|
alias_method :__perform__, :perform
|
|
4
6
|
|
|
5
7
|
def perform(request, options)
|
|
6
8
|
return __perform__(request, options) unless webmock_enabled?
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
WebMockPerform.new(request, options) { __perform__(request, options) }.exec
|
|
8
11
|
end
|
|
9
12
|
|
|
10
13
|
def webmock_enabled?
|
|
@@ -1,9 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTTP
|
|
2
4
|
class Request
|
|
3
5
|
def webmock_signature
|
|
6
|
+
request_body = nil
|
|
7
|
+
|
|
8
|
+
if defined?(HTTP::Request::Body)
|
|
9
|
+
request_body = String.new
|
|
10
|
+
first_chunk_encoding = nil
|
|
11
|
+
body.each do |part|
|
|
12
|
+
request_body << part
|
|
13
|
+
first_chunk_encoding ||= part.encoding
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
request_body.force_encoding(first_chunk_encoding) if first_chunk_encoding
|
|
17
|
+
request_body
|
|
18
|
+
else
|
|
19
|
+
request_body = body
|
|
20
|
+
end
|
|
21
|
+
|
|
4
22
|
::WebMock::RequestSignature.new(verb, uri.to_s, {
|
|
5
23
|
headers: headers.to_h,
|
|
6
|
-
body:
|
|
24
|
+
body: request_body
|
|
7
25
|
})
|
|
8
26
|
end
|
|
9
27
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTTP
|
|
2
4
|
class Response
|
|
3
5
|
def to_webmock
|
|
@@ -11,20 +13,44 @@ module HTTP
|
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
class << self
|
|
14
|
-
def from_webmock(webmock_response, request_signature = nil)
|
|
16
|
+
def from_webmock(request, webmock_response, request_signature = nil)
|
|
15
17
|
status = Status.new(webmock_response.status.first)
|
|
16
18
|
headers = webmock_response.headers || {}
|
|
17
|
-
body = Body.new Streamer.new webmock_response.body
|
|
18
19
|
uri = normalize_uri(request_signature && request_signature.uri)
|
|
19
20
|
|
|
21
|
+
# HTTP.rb 3.0+ uses a keyword argument to pass the encoding, but 1.x
|
|
22
|
+
# and 2.x use a positional argument, and 0.x don't support supplying
|
|
23
|
+
# the encoding.
|
|
24
|
+
body = if HTTP::VERSION < "1.0.0"
|
|
25
|
+
Body.new(Streamer.new(webmock_response.body))
|
|
26
|
+
elsif HTTP::VERSION < "3.0.0"
|
|
27
|
+
Body.new(Streamer.new(webmock_response.body), webmock_response.body.encoding)
|
|
28
|
+
else
|
|
29
|
+
Body.new(
|
|
30
|
+
Streamer.new(webmock_response.body, encoding: webmock_response.body.encoding),
|
|
31
|
+
encoding: webmock_response.body.encoding
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
20
35
|
return new(status, "1.1", headers, body, uri) if HTTP::VERSION < "1.0.0"
|
|
21
36
|
|
|
37
|
+
# 5.0.0 had a breaking change to require request instead of uri.
|
|
38
|
+
if HTTP::VERSION < '5.0.0'
|
|
39
|
+
return new({
|
|
40
|
+
status: status,
|
|
41
|
+
version: "1.1",
|
|
42
|
+
headers: headers,
|
|
43
|
+
body: body,
|
|
44
|
+
uri: uri
|
|
45
|
+
})
|
|
46
|
+
end
|
|
47
|
+
|
|
22
48
|
new({
|
|
23
49
|
status: status,
|
|
24
50
|
version: "1.1",
|
|
25
51
|
headers: headers,
|
|
26
52
|
body: body,
|
|
27
|
-
|
|
53
|
+
request: request,
|
|
28
54
|
})
|
|
29
55
|
end
|
|
30
56
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTTP
|
|
2
4
|
class Response
|
|
3
5
|
class Streamer
|
|
4
|
-
def initialize(str)
|
|
6
|
+
def initialize(str, encoding: Encoding::BINARY)
|
|
5
7
|
@io = StringIO.new str
|
|
8
|
+
@encoding = encoding
|
|
6
9
|
end
|
|
7
10
|
|
|
8
|
-
def readpartial(size = nil)
|
|
11
|
+
def readpartial(size = nil, outbuf = nil)
|
|
9
12
|
unless size
|
|
10
13
|
if defined?(HTTP::Client::BUFFER_SIZE)
|
|
11
14
|
size = HTTP::Client::BUFFER_SIZE
|
|
@@ -14,7 +17,12 @@ module HTTP
|
|
|
14
17
|
end
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
@io.read size
|
|
20
|
+
chunk = @io.read size, outbuf
|
|
21
|
+
chunk.force_encoding(@encoding) if chunk
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def close
|
|
25
|
+
@io.close
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def sequence_id
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module HTTP
|
|
2
4
|
class WebMockPerform
|
|
3
|
-
def initialize(request, &perform)
|
|
5
|
+
def initialize(request, options, &perform)
|
|
4
6
|
@request = request
|
|
7
|
+
@options = options
|
|
5
8
|
@perform = perform
|
|
6
9
|
@request_signature = nil
|
|
7
10
|
end
|
|
@@ -38,12 +41,15 @@ module HTTP
|
|
|
38
41
|
webmock_response.raise_error_if_any
|
|
39
42
|
|
|
40
43
|
invoke_callbacks(webmock_response, real_request: false)
|
|
41
|
-
::HTTP::Response.from_webmock webmock_response, request_signature
|
|
44
|
+
response = ::HTTP::Response.from_webmock @request, webmock_response, request_signature
|
|
45
|
+
|
|
46
|
+
@options.features.each { |_name, feature| response = feature.wrap_response(response) }
|
|
47
|
+
response
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def raise_timeout_error
|
|
45
51
|
raise Errno::ETIMEDOUT if HTTP::VERSION < "1.0.0"
|
|
46
|
-
raise HTTP::
|
|
52
|
+
raise HTTP::TimeoutError, "connection error: #{Errno::ETIMEDOUT.new}"
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
def perform
|
|
@@ -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,9 @@ if defined?(::HTTPClient)
|
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
module WebMockHTTPClients
|
|
48
|
+
|
|
49
|
+
REQUEST_RESPONSE_LOCK = Mutex.new
|
|
50
|
+
|
|
46
51
|
def do_get_block(req, proxy, conn, &block)
|
|
47
52
|
do_get(req, proxy, conn, false, &block)
|
|
48
53
|
end
|
|
@@ -57,7 +62,7 @@ if defined?(::HTTPClient)
|
|
|
57
62
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
58
63
|
|
|
59
64
|
if webmock_responses[request_signature]
|
|
60
|
-
webmock_response = webmock_responses.delete(request_signature)
|
|
65
|
+
webmock_response = synchronize_request_response { webmock_responses.delete(request_signature) }
|
|
61
66
|
response = build_httpclient_response(webmock_response, stream, req.header, &block)
|
|
62
67
|
@request_filter.each do |filter|
|
|
63
68
|
filter.filter_response(req, response)
|
|
@@ -68,15 +73,17 @@ if defined?(::HTTPClient)
|
|
|
68
73
|
res
|
|
69
74
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
70
75
|
# in case there is a nil entry in the hash...
|
|
71
|
-
webmock_responses.delete(request_signature)
|
|
76
|
+
synchronize_request_response { webmock_responses.delete(request_signature) }
|
|
72
77
|
|
|
73
78
|
res = if stream
|
|
74
79
|
do_get_stream_without_webmock(req, proxy, conn, &block)
|
|
75
80
|
elsif block
|
|
76
81
|
body = ''
|
|
77
82
|
do_get_block_without_webmock(req, proxy, conn) do |http_res, chunk|
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
if chunk && chunk.bytesize > 0
|
|
84
|
+
body += chunk
|
|
85
|
+
block.call(http_res, chunk)
|
|
86
|
+
end
|
|
80
87
|
end
|
|
81
88
|
else
|
|
82
89
|
do_get_block_without_webmock(req, proxy, conn)
|
|
@@ -98,7 +105,7 @@ if defined?(::HTTPClient)
|
|
|
98
105
|
def do_request_async(method, uri, query, body, extheader)
|
|
99
106
|
req = create_request(method, uri, query, body, extheader)
|
|
100
107
|
request_signature = build_request_signature(req)
|
|
101
|
-
webmock_request_signatures << request_signature
|
|
108
|
+
synchronize_request_response { webmock_request_signatures << request_signature }
|
|
102
109
|
|
|
103
110
|
if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
|
|
104
111
|
super
|
|
@@ -117,7 +124,7 @@ if defined?(::HTTPClient)
|
|
|
117
124
|
raise HTTPClient::TimeoutError if webmock_response.should_timeout
|
|
118
125
|
webmock_response.raise_error_if_any
|
|
119
126
|
|
|
120
|
-
block.call(response, body) if block
|
|
127
|
+
block.call(response, body) if block && body && body.bytesize > 0
|
|
121
128
|
|
|
122
129
|
response
|
|
123
130
|
end
|
|
@@ -182,7 +189,9 @@ if defined?(::HTTPClient)
|
|
|
182
189
|
|
|
183
190
|
def webmock_responses
|
|
184
191
|
@webmock_responses ||= Hash.new do |hash, request_signature|
|
|
185
|
-
|
|
192
|
+
synchronize_request_response do
|
|
193
|
+
hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
194
|
+
end
|
|
186
195
|
end
|
|
187
196
|
end
|
|
188
197
|
|
|
@@ -191,8 +200,10 @@ if defined?(::HTTPClient)
|
|
|
191
200
|
end
|
|
192
201
|
|
|
193
202
|
def previous_signature_for(signature)
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
synchronize_request_response do
|
|
204
|
+
return nil unless index = webmock_request_signatures.index(signature)
|
|
205
|
+
webmock_request_signatures.delete_at(index)
|
|
206
|
+
end
|
|
196
207
|
end
|
|
197
208
|
|
|
198
209
|
private
|
|
@@ -207,6 +218,16 @@ if defined?(::HTTPClient)
|
|
|
207
218
|
hdrs
|
|
208
219
|
end
|
|
209
220
|
end
|
|
221
|
+
|
|
222
|
+
def synchronize_request_response
|
|
223
|
+
if REQUEST_RESPONSE_LOCK.owned?
|
|
224
|
+
yield
|
|
225
|
+
else
|
|
226
|
+
REQUEST_RESPONSE_LOCK.synchronize do
|
|
227
|
+
yield
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
210
231
|
end
|
|
211
232
|
|
|
212
233
|
class WebMockHTTPClient < HTTPClient
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
begin
|
|
2
4
|
require 'manticore'
|
|
3
5
|
rescue LoadError
|
|
@@ -24,6 +26,12 @@ if defined?(Manticore)
|
|
|
24
26
|
Manticore.instance_variable_set(:@manticore_facade, OriginalManticoreClient.new)
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
class StubbedTimeoutResponse < Manticore::StubbedResponse
|
|
30
|
+
def call
|
|
31
|
+
@handlers[:failure].call(Manticore::ConnectTimeout.new("Too slow (mocked timeout)"))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
class WebMockManticoreClient < Manticore::Client
|
|
28
36
|
def request(klass, url, options={}, &block)
|
|
29
37
|
super(klass, WebMock::Util::URI.normalize_uri(url).to_s, format_options(options))
|
|
@@ -50,19 +58,22 @@ if defined?(Manticore)
|
|
|
50
58
|
|
|
51
59
|
if webmock_response = registered_response_for(request_signature)
|
|
52
60
|
webmock_response.raise_error_if_any
|
|
53
|
-
manticore_response = generate_manticore_response(webmock_response)
|
|
54
|
-
|
|
61
|
+
manticore_response = generate_manticore_response(webmock_response)
|
|
62
|
+
manticore_response.on_success do
|
|
63
|
+
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: false}, request_signature, webmock_response)
|
|
64
|
+
end
|
|
55
65
|
|
|
56
66
|
elsif real_request_allowed?(request_signature.uri)
|
|
57
|
-
manticore_response = Manticore::Response.new(self, request, context, &block)
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
manticore_response = Manticore::Response.new(self, request, context, &block)
|
|
68
|
+
manticore_response.on_complete do |completed_response|
|
|
69
|
+
webmock_response = generate_webmock_response(completed_response)
|
|
70
|
+
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: true}, request_signature, webmock_response)
|
|
71
|
+
end
|
|
60
72
|
|
|
61
73
|
else
|
|
62
74
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
63
75
|
end
|
|
64
76
|
|
|
65
|
-
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: real_request}, request_signature, webmock_response)
|
|
66
77
|
manticore_response
|
|
67
78
|
end
|
|
68
79
|
|
|
@@ -103,21 +114,30 @@ if defined?(Manticore)
|
|
|
103
114
|
end
|
|
104
115
|
|
|
105
116
|
def generate_manticore_response(webmock_response)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
if webmock_response.should_timeout
|
|
118
|
+
StubbedTimeoutResponse.new
|
|
119
|
+
else
|
|
120
|
+
Manticore::StubbedResponse.stub(
|
|
121
|
+
code: webmock_response.status[0],
|
|
122
|
+
body: webmock_response.body,
|
|
123
|
+
headers: webmock_response.headers,
|
|
124
|
+
cookies: {}
|
|
125
|
+
)
|
|
126
|
+
end
|
|
114
127
|
end
|
|
115
128
|
|
|
116
129
|
def generate_webmock_response(manticore_response)
|
|
117
130
|
webmock_response = WebMock::Response.new
|
|
118
131
|
webmock_response.status = [manticore_response.code, manticore_response.message]
|
|
119
|
-
webmock_response.body = manticore_response.body
|
|
120
132
|
webmock_response.headers = manticore_response.headers
|
|
133
|
+
|
|
134
|
+
# The attempt to read the body could fail if manticore is used in a streaming mode
|
|
135
|
+
webmock_response.body = begin
|
|
136
|
+
manticore_response.body
|
|
137
|
+
rescue ::Manticore::StreamClosedException
|
|
138
|
+
nil
|
|
139
|
+
end
|
|
140
|
+
|
|
121
141
|
webmock_response
|
|
122
142
|
end
|
|
123
143
|
end
|