webmock 3.6.0 → 3.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/CHANGELOG.md +56 -0
- data/README.md +18 -0
- data/lib/webmock.rb +1 -0
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +214 -0
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +1 -1
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +2 -2
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +25 -14
- data/lib/webmock/http_lib_adapters/net_http.rb +3 -2
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +1 -1
- data/lib/webmock/request_pattern.rb +1 -2
- data/lib/webmock/util/uri.rb +8 -8
- data/lib/webmock/version.rb +1 -1
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +349 -0
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +1 -1
- data/spec/acceptance/http_rb/http_rb_spec.rb +11 -0
- data/spec/acceptance/manticore/manticore_spec.rb +19 -0
- data/spec/acceptance/shared/callbacks.rb +2 -1
- data/spec/acceptance/shared/returning_declared_responses.rb +36 -15
- data/spec/support/webmock_server.rb +1 -0
- data/spec/unit/request_pattern_spec.rb +5 -0
- data/spec/unit/util/uri_spec.rb +74 -2
- data/webmock.gemspec +8 -1
- metadata +27 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6023ac450eb0fc7d307ffd764f811e9d409e28fdfabdb215bec15d4e4ea7a363
|
4
|
+
data.tar.gz: 2417fb3aecf50a9b48dc84ee1eb55da9493cff52c68c8a292e0d9215f1c52379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a83cdbc53a9c75e6d4db3f01e727cc2cb27fb8097dfbad2cd36b39e263bfdc570f60b1c2b924845f81bff2c89dbd91758061c830293c86d0f3a2ba2bb01d619a
|
7
|
+
data.tar.gz: 07cc56e80c126f76ecd53a00b218e80c0a07760d478b1d8354d85f7057828256f4dcc2e857312c83a2bfadbdbcfda0bb20c82510949cabdb24fd3f50657fffbb
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,61 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 3.7.3
|
4
|
+
|
5
|
+
* Fix for http.rb. Allow passing an output buffer to HTTP::Response::Body#readpartial
|
6
|
+
|
7
|
+
Thanks to [George Claghorn](https://github.com/georgeclaghorn)
|
8
|
+
|
9
|
+
* Fixed Manticore adapter to invoke Manticore failure handler on stubbed timeout
|
10
|
+
|
11
|
+
Thanks to [Alex Junger](https://github.com/alexJunger)
|
12
|
+
|
13
|
+
* Added project metadata to the gemspec
|
14
|
+
|
15
|
+
Thanks to [Orien Madgwick](https://github.com/orien)
|
16
|
+
|
17
|
+
## 3.7.2
|
18
|
+
|
19
|
+
* Fixed handling of non UTF-8 encoded urls
|
20
|
+
|
21
|
+
Thanks to [Rafael França](https://github.com/rafaelfranca)
|
22
|
+
|
23
|
+
* Fixed "shadowing outer local variable" warning
|
24
|
+
|
25
|
+
Thanks to [y-yagi](https://github.com/y-yagi)
|
26
|
+
|
27
|
+
## 3.7.1
|
28
|
+
|
29
|
+
* Fixed Async::HTTP::Client adapter code to not cause Ruby warning
|
30
|
+
|
31
|
+
Thanks to [y-yagi](https://github.com/y-yagi)
|
32
|
+
|
33
|
+
## 3.7.0
|
34
|
+
|
35
|
+
* Support for Async::HTTP::Client
|
36
|
+
|
37
|
+
Thanks to [Andriy Yanko](https://github.com/ayanko)
|
38
|
+
|
39
|
+
## 3.6.2
|
40
|
+
|
41
|
+
* Fixed Patron adapter to handle HTTP/2 status line.
|
42
|
+
|
43
|
+
Thanks to [Fábio D. Batista](https://github.com/fabiob)
|
44
|
+
|
45
|
+
## 3.6.1
|
46
|
+
|
47
|
+
* Fixed issue with matching Addressable::Template without a period in the domain
|
48
|
+
|
49
|
+
Thanks to [Eike Send](https://github.com/eikes)
|
50
|
+
|
51
|
+
* Support for `write_timeout` in Net::HTTP
|
52
|
+
|
53
|
+
Thanks to [Claudio Poli](https://github.com/masterkain)
|
54
|
+
|
55
|
+
* Fixed issue with handling urls with ":80" or ":443" in the path.
|
56
|
+
|
57
|
+
Thanks to [Csaba Apagyi](https://github.com/thisismydesign) for reporting and to [Frederick Cheung](https://github.com/fcheung) for fixing the issue.
|
58
|
+
|
3
59
|
## 3.6.0
|
4
60
|
|
5
61
|
* Compatibility with the latest version of hashdiff gem, with constant changed from HashDiff to Hashdiff
|
data/README.md
CHANGED
@@ -33,6 +33,7 @@ Supported HTTP libraries
|
|
33
33
|
* Excon
|
34
34
|
* HTTP Gem
|
35
35
|
* Manticore
|
36
|
+
* Async::HTTP::Client
|
36
37
|
|
37
38
|
Supported Ruby Interpreters
|
38
39
|
---------------------------
|
@@ -878,6 +879,10 @@ end
|
|
878
879
|
|
879
880
|
Please submit them here [http://github.com/bblimke/webmock/issues](http://github.com/bblimke/webmock/issues)
|
880
881
|
|
882
|
+
## Issue triage [![Open Source Helpers](https://www.codetriage.com/bblimke/webmock/badges/users.svg)](https://www.codetriage.com/bblimke/webmock)
|
883
|
+
|
884
|
+
You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to webmock on CodeTriage](https://www.codetriage.com/bblimke/webmock).
|
885
|
+
|
881
886
|
## Suggestions
|
882
887
|
|
883
888
|
If you have any suggestions on how to improve WebMock please send an email to the mailing list [groups.google.com/group/webmock-users](http://groups.google.com/group/webmock-users)
|
@@ -1096,6 +1101,19 @@ People who submitted patches and new features or suggested improvements. Many th
|
|
1096
1101
|
* Pavel Valena
|
1097
1102
|
* Adam Sokolnicki
|
1098
1103
|
* Jeff Felchner
|
1104
|
+
* Eike Send
|
1105
|
+
* Claudio Poli
|
1106
|
+
* Csaba Apagyi
|
1107
|
+
* Frederick Cheung
|
1108
|
+
* Fábio D. Batista
|
1109
|
+
* Andriy Yanko
|
1110
|
+
* y-yagi
|
1111
|
+
* Rafael França
|
1112
|
+
* George Claghorn
|
1113
|
+
* Alex Junger
|
1114
|
+
* Orien Madgwick
|
1115
|
+
|
1116
|
+
|
1099
1117
|
|
1100
1118
|
For a full list of contributors you can visit the
|
1101
1119
|
[contributors](https://github.com/bblimke/webmock/contributors) page.
|
data/lib/webmock.rb
CHANGED
@@ -54,5 +54,6 @@ require_relative 'webmock/http_lib_adapters/em_http_request_adapter'
|
|
54
54
|
require_relative 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
|
55
55
|
require_relative 'webmock/http_lib_adapters/excon_adapter'
|
56
56
|
require_relative 'webmock/http_lib_adapters/manticore_adapter'
|
57
|
+
require_relative 'webmock/http_lib_adapters/async_http_client_adapter'
|
57
58
|
|
58
59
|
require_relative 'webmock/webmock'
|
@@ -0,0 +1,214 @@
|
|
1
|
+
begin
|
2
|
+
require 'async'
|
3
|
+
require 'async/http'
|
4
|
+
rescue LoadError
|
5
|
+
# async-http not found
|
6
|
+
end
|
7
|
+
|
8
|
+
if defined?(Async::HTTP)
|
9
|
+
module WebMock
|
10
|
+
module HttpLibAdapters
|
11
|
+
class AsyncHttpClientAdapter < HttpLibAdapter
|
12
|
+
adapter_for :async_http_client
|
13
|
+
|
14
|
+
OriginalAsyncHttpClient = Async::HTTP::Client unless const_defined?(:OriginalAsyncHttpClient)
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def enable!
|
18
|
+
Async::HTTP.send(:remove_const, :Client)
|
19
|
+
Async::HTTP.send(:const_set, :Client, Async::HTTP::WebMockClientWrapper)
|
20
|
+
end
|
21
|
+
|
22
|
+
def disable!
|
23
|
+
Async::HTTP.send(:remove_const, :Client)
|
24
|
+
Async::HTTP.send(:const_set, :Client, OriginalAsyncHttpClient)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Async
|
32
|
+
module HTTP
|
33
|
+
class WebMockClientWrapper < Client
|
34
|
+
def initialize(
|
35
|
+
endpoint,
|
36
|
+
protocol = endpoint.protocol,
|
37
|
+
scheme = endpoint.scheme,
|
38
|
+
authority = endpoint.authority,
|
39
|
+
options = {}
|
40
|
+
)
|
41
|
+
webmock_endpoint = WebMockEndpoint.new(scheme, authority, protocol)
|
42
|
+
|
43
|
+
@network_client = WebMockClient.new(endpoint, protocol, scheme, authority, options)
|
44
|
+
@webmock_client = WebMockClient.new(webmock_endpoint, protocol, scheme, authority, options)
|
45
|
+
|
46
|
+
@scheme = scheme
|
47
|
+
@authority = authority
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(request)
|
51
|
+
request.scheme ||= self.scheme
|
52
|
+
request.authority ||= self.authority
|
53
|
+
|
54
|
+
request_signature = build_request_signature(request)
|
55
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
56
|
+
webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
57
|
+
net_connect_allowed = WebMock.net_connect_allowed?(request_signature.uri)
|
58
|
+
|
59
|
+
if webmock_response
|
60
|
+
webmock_response.raise_error_if_any
|
61
|
+
raise Async::TimeoutError, 'WebMock timeout error' if webmock_response.should_timeout
|
62
|
+
WebMockApplication.add_webmock_response(request, webmock_response)
|
63
|
+
response = @webmock_client.call(request)
|
64
|
+
elsif net_connect_allowed
|
65
|
+
response = @network_client.call(request)
|
66
|
+
else
|
67
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature) unless webmock_response
|
68
|
+
end
|
69
|
+
|
70
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
71
|
+
webmock_response ||= build_webmock_response(response)
|
72
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
73
|
+
{
|
74
|
+
lib: :async_http_client,
|
75
|
+
real_request: net_connect_allowed
|
76
|
+
},
|
77
|
+
request_signature,
|
78
|
+
webmock_response
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
response
|
83
|
+
end
|
84
|
+
|
85
|
+
def close
|
86
|
+
@network_client.close
|
87
|
+
@webmock_client.close
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def build_request_signature(request)
|
93
|
+
body = request.read
|
94
|
+
request.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
|
95
|
+
WebMock::RequestSignature.new(
|
96
|
+
request.method.downcase.to_sym,
|
97
|
+
"#{request.scheme}://#{request.authority}#{request.path}",
|
98
|
+
headers: request.headers.to_h,
|
99
|
+
body: body
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_webmock_response(response)
|
104
|
+
body = response.read
|
105
|
+
response.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
|
106
|
+
|
107
|
+
webmock_response = WebMock::Response.new
|
108
|
+
webmock_response.status = [
|
109
|
+
response.status,
|
110
|
+
::Protocol::HTTP1::Reason::DESCRIPTIONS[response.status]
|
111
|
+
]
|
112
|
+
webmock_response.headers = build_webmock_response_headers(response)
|
113
|
+
webmock_response.body = body
|
114
|
+
webmock_response
|
115
|
+
end
|
116
|
+
|
117
|
+
def build_webmock_response_headers(response)
|
118
|
+
response.headers.each.each_with_object({}) do |(k, v), o|
|
119
|
+
o[k] ||= []
|
120
|
+
o[k] << v
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class WebMockClient < Client
|
126
|
+
end
|
127
|
+
|
128
|
+
class WebMockEndpoint
|
129
|
+
def initialize(scheme, authority, protocol)
|
130
|
+
@scheme = scheme
|
131
|
+
@authority = authority
|
132
|
+
@protocol = protocol
|
133
|
+
end
|
134
|
+
|
135
|
+
attr :scheme, :authority, :protocol
|
136
|
+
|
137
|
+
def connect
|
138
|
+
server_socket, client_socket = create_connected_sockets
|
139
|
+
Async do
|
140
|
+
accept_socket(server_socket)
|
141
|
+
end
|
142
|
+
client_socket
|
143
|
+
end
|
144
|
+
|
145
|
+
def inspect
|
146
|
+
"\#<#{self.class}> #{scheme}://#{authority} protocol=#{protocol}"
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def create_connected_sockets
|
152
|
+
Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM).tap do |sockets|
|
153
|
+
sockets.each do |socket|
|
154
|
+
socket.instance_variable_set :@alpn_protocol, @alpn_protocol
|
155
|
+
socket.instance_eval do
|
156
|
+
def alpn_protocol
|
157
|
+
nil # means HTTP11 will be used for HTTPS
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def accept_socket(socket)
|
165
|
+
server = Async::HTTP::Server.new(WebMockApplication, self)
|
166
|
+
server.accept(socket, socket.remote_address)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
module WebMockApplication
|
171
|
+
WEBMOCK_REQUEST_ID_HEADER = 'x-webmock-request-id'.freeze
|
172
|
+
|
173
|
+
class << self
|
174
|
+
def call(request)
|
175
|
+
request.read
|
176
|
+
webmock_response = get_webmock_response(request)
|
177
|
+
build_response(webmock_response)
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_webmock_response(request, webmock_response)
|
181
|
+
webmock_request_id = request.object_id.to_s
|
182
|
+
request.headers.add(WEBMOCK_REQUEST_ID_HEADER, webmock_request_id)
|
183
|
+
webmock_responses[webmock_request_id] = webmock_response
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_webmock_response(request)
|
187
|
+
webmock_request_id = request.headers[WEBMOCK_REQUEST_ID_HEADER][0]
|
188
|
+
webmock_responses.fetch(webmock_request_id)
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def webmock_responses
|
194
|
+
@webmock_responses ||= {}
|
195
|
+
end
|
196
|
+
|
197
|
+
def build_response(webmock_response)
|
198
|
+
headers = (webmock_response.headers || {}).each_with_object([]) do |(k, value), o|
|
199
|
+
Array(value).each do |v|
|
200
|
+
o.push [k, v]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
::Protocol::HTTP::Response[
|
205
|
+
webmock_response.status[0],
|
206
|
+
headers,
|
207
|
+
webmock_response.body
|
208
|
+
]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -107,7 +107,7 @@ if defined?(EventMachine::HttpClient)
|
|
107
107
|
@uri ||= nil
|
108
108
|
EM.next_tick {
|
109
109
|
setup(make_raw_response(stubbed_webmock_response), @uri,
|
110
|
-
stubbed_webmock_response.should_timeout ?
|
110
|
+
stubbed_webmock_response.should_timeout ? Errno::ETIMEDOUT : nil)
|
111
111
|
}
|
112
112
|
self
|
113
113
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
@@ -5,7 +5,7 @@ module HTTP
|
|
5
5
|
@io = StringIO.new str
|
6
6
|
end
|
7
7
|
|
8
|
-
def readpartial(size = nil)
|
8
|
+
def readpartial(size = nil, outbuf = nil)
|
9
9
|
unless size
|
10
10
|
if defined?(HTTP::Client::BUFFER_SIZE)
|
11
11
|
size = HTTP::Client::BUFFER_SIZE
|
@@ -14,7 +14,7 @@ module HTTP
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
@io.read size
|
17
|
+
@io.read size, outbuf
|
18
18
|
end
|
19
19
|
|
20
20
|
def close
|
@@ -24,6 +24,12 @@ if defined?(Manticore)
|
|
24
24
|
Manticore.instance_variable_set(:@manticore_facade, OriginalManticoreClient.new)
|
25
25
|
end
|
26
26
|
|
27
|
+
class StubbedTimeoutResponse < Manticore::StubbedResponse
|
28
|
+
def call
|
29
|
+
@handlers[:failure].call(Manticore::ConnectTimeout.new("Too slow (mocked timeout)"))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
27
33
|
class WebMockManticoreClient < Manticore::Client
|
28
34
|
def request(klass, url, options={}, &block)
|
29
35
|
super(klass, WebMock::Util::URI.normalize_uri(url).to_s, format_options(options))
|
@@ -50,19 +56,22 @@ if defined?(Manticore)
|
|
50
56
|
|
51
57
|
if webmock_response = registered_response_for(request_signature)
|
52
58
|
webmock_response.raise_error_if_any
|
53
|
-
manticore_response = generate_manticore_response(webmock_response)
|
54
|
-
|
59
|
+
manticore_response = generate_manticore_response(webmock_response)
|
60
|
+
manticore_response.on_success do
|
61
|
+
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: false}, request_signature, webmock_response)
|
62
|
+
end
|
55
63
|
|
56
64
|
elsif real_request_allowed?(request_signature.uri)
|
57
|
-
manticore_response = Manticore::Response.new(self, request, context, &block)
|
58
|
-
|
59
|
-
|
65
|
+
manticore_response = Manticore::Response.new(self, request, context, &block)
|
66
|
+
manticore_response.on_complete do |completed_response|
|
67
|
+
webmock_response = generate_webmock_response(completed_response)
|
68
|
+
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: true}, request_signature, webmock_response)
|
69
|
+
end
|
60
70
|
|
61
71
|
else
|
62
72
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
63
73
|
end
|
64
74
|
|
65
|
-
WebMock::CallbackRegistry.invoke_callbacks({lib: :manticore, real_request: real_request}, request_signature, webmock_response)
|
66
75
|
manticore_response
|
67
76
|
end
|
68
77
|
|
@@ -103,14 +112,16 @@ if defined?(Manticore)
|
|
103
112
|
end
|
104
113
|
|
105
114
|
def generate_manticore_response(webmock_response)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
115
|
+
if webmock_response.should_timeout
|
116
|
+
StubbedTimeoutResponse.new
|
117
|
+
else
|
118
|
+
Manticore::StubbedResponse.stub(
|
119
|
+
code: webmock_response.status[0],
|
120
|
+
body: webmock_response.body,
|
121
|
+
headers: webmock_response.headers,
|
122
|
+
cookies: {}
|
123
|
+
)
|
124
|
+
end
|
114
125
|
end
|
115
126
|
|
116
127
|
def generate_webmock_response(manticore_response)
|
@@ -229,14 +229,15 @@ class PatchedStringIO < StringIO #:nodoc:
|
|
229
229
|
alias_method :orig_read_nonblock, :read_nonblock
|
230
230
|
|
231
231
|
def read_nonblock(size, *args)
|
232
|
-
|
232
|
+
args.reject! {|arg| !arg.is_a?(Hash)}
|
233
|
+
orig_read_nonblock(size, *args)
|
233
234
|
end
|
234
235
|
|
235
236
|
end
|
236
237
|
|
237
238
|
class StubSocket #:nodoc:
|
238
239
|
|
239
|
-
attr_accessor :read_timeout, :continue_timeout
|
240
|
+
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
240
241
|
|
241
242
|
def initialize(*args)
|
242
243
|
end
|