webmock 3.16.2 → 3.18.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 +45 -5
- data/README.md +5 -1
- data/lib/webmock/http_lib_adapters/net_http.rb +37 -144
- data/lib/webmock/request_pattern.rb +23 -7
- data/lib/webmock/request_signature.rb +2 -2
- data/lib/webmock/response.rb +8 -8
- data/lib/webmock/version.rb +1 -1
- data/spec/acceptance/net_http/net_http_spec.rb +22 -23
- data/spec/acceptance/patron/patron_spec.rb +19 -21
- data/spec/unit/request_pattern_spec.rb +12 -0
- data/spec/unit/response_spec.rb +28 -0
- data/webmock.gemspec +2 -2
- metadata +8 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70c0ad15601d48c3f413012ced7fde245d03fcc5d5bb7b609fd2ce89084b2589
|
|
4
|
+
data.tar.gz: 4575309d868350685b573d8929ce1836eb044b00fb862c1b9b266a73a1992e9f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: acba1ac0ec3d97c5eb244a84d1b8e895f13e9b3cfb1ca5ac4c0d5109eb7fcc508a3d1e51faa426bd31cb2509d61effed7c134119b5c05d128b3466ec3ee397c7
|
|
7
|
+
data.tar.gz: e8eb5385dd3d4fc9f02c541fbec1bc2c825e07445046b3bde50c471925728c08b1bb9aaf963d61fb44f5a38041f54964ab9fa89caef4cd16fd06fe6bb1ceca44
|
data/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
# 3.
|
|
3
|
+
# 3.18.0
|
|
4
|
+
|
|
5
|
+
* Net::BufferedIO is not replaced anymore.
|
|
6
|
+
|
|
7
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
|
8
|
+
|
|
9
|
+
* Simplified connection handing in Net::HTTP adapter.
|
|
10
|
+
|
|
11
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
|
4
12
|
|
|
5
|
-
|
|
13
|
+
# 3.17.1
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
* Fixed Syntax Error
|
|
16
|
+
|
|
17
|
+
Thanks to [Mark Spangler](https://github.com/mspangler)
|
|
18
|
+
|
|
19
|
+
# 3.17.0
|
|
8
20
|
|
|
9
21
|
* Minimum required Ruby version is 2.3
|
|
10
22
|
|
|
11
|
-
|
|
23
|
+
Thanks to [Go Sueyoshi](https://github.com/sue445)
|
|
24
|
+
|
|
25
|
+
* When using Net::HTTP, stubbed socket StubSocket#close and StubSocket#closed? behave more like the real sockets.
|
|
26
|
+
|
|
27
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
|
28
|
+
|
|
29
|
+
* Added `peeraddr`, `ssl_version` and `cipher` methods to stubbed sockets used by Net::HTTP.
|
|
30
|
+
|
|
31
|
+
Thanks to [Ray Zane](https://github.com/rzane)
|
|
32
|
+
|
|
33
|
+
* Added support for matching top-level array in JSON request body.
|
|
34
|
+
|
|
35
|
+
E.g.
|
|
36
|
+
|
|
37
|
+
````
|
|
38
|
+
stub_request(:post, 'www.example.com').with(body: [{a: 1}])
|
|
39
|
+
````
|
|
40
|
+
|
|
41
|
+
Thanks to [Cedric Sohrauer](https://github.com/cedrics)
|
|
42
|
+
|
|
43
|
+
# 3.16.2
|
|
44
|
+
|
|
45
|
+
* Minimum required Ruby version is 2.0.
|
|
46
|
+
|
|
47
|
+
# 3.16.0 (yanked)
|
|
12
48
|
|
|
13
49
|
* Fix leaky file descriptors and reuse socket for persistent connections.
|
|
14
50
|
|
|
@@ -18,7 +54,11 @@
|
|
|
18
54
|
|
|
19
55
|
Thanks to [Ray Zane](https://github.com/rzane)
|
|
20
56
|
|
|
21
|
-
# 3.15.
|
|
57
|
+
# 3.15.2
|
|
58
|
+
|
|
59
|
+
* Minimum required Ruby version is 2.0.
|
|
60
|
+
|
|
61
|
+
# 3.15.0 (yanked)
|
|
22
62
|
|
|
23
63
|
* fixed async-http adapter on Windows
|
|
24
64
|
|
data/README.md
CHANGED
|
@@ -1166,13 +1166,17 @@ People who submitted patches and new features or suggested improvements. Many th
|
|
|
1166
1166
|
* Timmitry
|
|
1167
1167
|
* Michael Fairley
|
|
1168
1168
|
* Ray Zane
|
|
1169
|
+
* Go Sueyoshi
|
|
1170
|
+
* Cedric Sohrauer
|
|
1171
|
+
* Akira Matsuda
|
|
1172
|
+
* Mark Spangler
|
|
1169
1173
|
|
|
1170
1174
|
For a full list of contributors you can visit the
|
|
1171
1175
|
[contributors](https://github.com/bblimke/webmock/contributors) page.
|
|
1172
1176
|
|
|
1173
1177
|
## Background
|
|
1174
1178
|
|
|
1175
|
-
Thank you Fakeweb! This library was inspired by [FakeWeb](
|
|
1179
|
+
Thank you Fakeweb! This library was inspired by [FakeWeb](https://github.com/chrisk/fakeweb).
|
|
1176
1180
|
I imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.
|
|
1177
1181
|
Fakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.
|
|
1178
1182
|
I also preferred some things to work differently i.e request stub precedence.
|
|
@@ -10,24 +10,19 @@ module WebMock
|
|
|
10
10
|
adapter_for :net_http
|
|
11
11
|
|
|
12
12
|
OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
|
|
13
|
-
OriginalNetBufferedIO = Net::BufferedIO unless const_defined?(:OriginalNetBufferedIO)
|
|
14
13
|
|
|
15
14
|
def self.enable!
|
|
16
|
-
Net.send(:remove_const, :BufferedIO)
|
|
17
15
|
Net.send(:remove_const, :HTTP)
|
|
18
16
|
Net.send(:remove_const, :HTTPSession)
|
|
19
17
|
Net.send(:const_set, :HTTP, @webMockNetHTTP)
|
|
20
18
|
Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
|
|
21
|
-
Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
def self.disable!
|
|
25
|
-
Net.send(:remove_const, :BufferedIO)
|
|
26
22
|
Net.send(:remove_const, :HTTP)
|
|
27
23
|
Net.send(:remove_const, :HTTPSession)
|
|
28
24
|
Net.send(:const_set, :HTTP, OriginalNetHTTP)
|
|
29
25
|
Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
|
|
30
|
-
Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
|
|
31
26
|
|
|
32
27
|
#copy all constants from @webMockNetHTTP to original Net::HTTP
|
|
33
28
|
#in case any constants were added to @webMockNetHTTP instead of Net::HTTP
|
|
@@ -72,74 +67,57 @@ module WebMock
|
|
|
72
67
|
end
|
|
73
68
|
|
|
74
69
|
def request(request, body = nil, &block)
|
|
70
|
+
return super unless started?
|
|
71
|
+
|
|
75
72
|
request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
|
|
76
73
|
|
|
77
74
|
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
78
75
|
|
|
79
76
|
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
80
|
-
@socket = Net::HTTP.socket_type.new
|
|
81
77
|
WebMock::CallbackRegistry.invoke_callbacks(
|
|
82
78
|
{lib: :net_http}, request_signature, webmock_response)
|
|
83
79
|
build_net_http_response(webmock_response, &block)
|
|
84
80
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
85
81
|
check_right_http_connection
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
super_with_after_request = lambda {
|
|
97
|
-
response = super(request, nil, &nil)
|
|
98
|
-
after_request.call(response)
|
|
99
|
-
}
|
|
100
|
-
if started?
|
|
101
|
-
ensure_actual_connection
|
|
102
|
-
super_with_after_request.call
|
|
103
|
-
else
|
|
104
|
-
start_with_connect {
|
|
105
|
-
super_with_after_request.call
|
|
106
|
-
}
|
|
82
|
+
ensure_actually_connected
|
|
83
|
+
|
|
84
|
+
response = super(request, nil, &nil)
|
|
85
|
+
|
|
86
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
87
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
88
|
+
{lib: :net_http, real_request: true},
|
|
89
|
+
request_signature,
|
|
90
|
+
build_webmock_response(response)
|
|
91
|
+
)
|
|
107
92
|
end
|
|
93
|
+
|
|
94
|
+
response.extend Net::WebMockHTTPResponse
|
|
95
|
+
block.call response if block
|
|
96
|
+
response
|
|
108
97
|
else
|
|
109
98
|
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
110
99
|
end
|
|
111
100
|
end
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
raise IOError, 'HTTP session already opened' if @started
|
|
115
|
-
if block_given?
|
|
116
|
-
begin
|
|
117
|
-
@socket = Net::HTTP.socket_type.new
|
|
118
|
-
@started = true
|
|
119
|
-
return yield(self)
|
|
120
|
-
ensure
|
|
121
|
-
do_finish
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
@socket = Net::HTTP.socket_type.new
|
|
125
|
-
@started = true
|
|
126
|
-
self
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def ensure_actual_connection
|
|
131
|
-
do_start if @socket.is_a?(StubSocket)
|
|
132
|
-
end
|
|
102
|
+
private
|
|
133
103
|
|
|
134
|
-
alias_method :
|
|
104
|
+
alias_method :actually_connect, :connect
|
|
135
105
|
|
|
136
|
-
def
|
|
106
|
+
def connect
|
|
137
107
|
uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
|
|
138
108
|
|
|
139
109
|
if WebMock.net_http_connect_on_start?(uri)
|
|
140
|
-
super
|
|
110
|
+
super
|
|
141
111
|
else
|
|
142
|
-
|
|
112
|
+
@socket = StubSocket.new
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def ensure_actually_connected
|
|
117
|
+
if @socket.is_a?(StubSocket)
|
|
118
|
+
@socket&.close
|
|
119
|
+
@socket = nil
|
|
120
|
+
actually_connect
|
|
143
121
|
end
|
|
144
122
|
end
|
|
145
123
|
|
|
@@ -161,7 +139,7 @@ module WebMock
|
|
|
161
139
|
response.extend Net::WebMockHTTPResponse
|
|
162
140
|
|
|
163
141
|
if webmock_response.should_timeout
|
|
164
|
-
raise
|
|
142
|
+
raise Net::OpenTimeout, "execution expired"
|
|
165
143
|
end
|
|
166
144
|
|
|
167
145
|
webmock_response.raise_error_if_any
|
|
@@ -171,16 +149,6 @@ module WebMock
|
|
|
171
149
|
response
|
|
172
150
|
end
|
|
173
151
|
|
|
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
152
|
def build_webmock_response(net_http_response)
|
|
185
153
|
webmock_response = WebMock::Response.new
|
|
186
154
|
webmock_response.status = [
|
|
@@ -214,31 +182,21 @@ module WebMock
|
|
|
214
182
|
end
|
|
215
183
|
end
|
|
216
184
|
|
|
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
185
|
class StubSocket #:nodoc:
|
|
231
186
|
|
|
232
187
|
attr_accessor :read_timeout, :continue_timeout, :write_timeout
|
|
233
188
|
|
|
234
189
|
def initialize(*args)
|
|
190
|
+
@closed = false
|
|
235
191
|
end
|
|
236
192
|
|
|
237
193
|
def closed?
|
|
238
|
-
@closed
|
|
194
|
+
@closed
|
|
239
195
|
end
|
|
240
196
|
|
|
241
197
|
def close
|
|
198
|
+
@closed = true
|
|
199
|
+
nil
|
|
242
200
|
end
|
|
243
201
|
|
|
244
202
|
def readuntil(*args)
|
|
@@ -251,57 +209,12 @@ class StubSocket #:nodoc:
|
|
|
251
209
|
class StubIO
|
|
252
210
|
def setsockopt(*args); end
|
|
253
211
|
def peer_cert; end
|
|
212
|
+
def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
|
|
213
|
+
def ssl_version; "TLSv1.3" end
|
|
214
|
+
def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
|
|
254
215
|
end
|
|
255
216
|
end
|
|
256
217
|
|
|
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
218
|
module WebMock
|
|
306
219
|
module NetHTTPUtility
|
|
307
220
|
|
|
@@ -318,7 +231,6 @@ module WebMock
|
|
|
318
231
|
method = request.method.downcase.to_sym
|
|
319
232
|
|
|
320
233
|
headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
|
|
321
|
-
validate_headers(headers)
|
|
322
234
|
|
|
323
235
|
if request.body_stream
|
|
324
236
|
body = request.body_stream.read
|
|
@@ -343,25 +255,6 @@ module WebMock
|
|
|
343
255
|
"#{protocol}://#{hostname}:#{net_http.port}#{path}"
|
|
344
256
|
end
|
|
345
257
|
|
|
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
258
|
def self.check_right_http_connection
|
|
366
259
|
@was_right_http_connection_loaded = defined?(RightHttpConnection)
|
|
367
260
|
end
|
|
@@ -281,6 +281,8 @@ module WebMock
|
|
|
281
281
|
if (@pattern).is_a?(Hash)
|
|
282
282
|
return true if @pattern.empty?
|
|
283
283
|
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
|
|
284
|
+
elsif (@pattern).is_a?(Array)
|
|
285
|
+
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
|
|
284
286
|
elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)
|
|
285
287
|
@pattern == body_as_hash(body, content_type)
|
|
286
288
|
else
|
|
@@ -344,19 +346,33 @@ module WebMock
|
|
|
344
346
|
def matching_body_hashes?(query_parameters, pattern, content_type)
|
|
345
347
|
return false unless query_parameters.is_a?(Hash)
|
|
346
348
|
return false unless query_parameters.keys.sort == pattern.keys.sort
|
|
347
|
-
|
|
349
|
+
|
|
350
|
+
query_parameters.all? do |key, actual|
|
|
348
351
|
expected = pattern[key]
|
|
352
|
+
matching_values(actual, expected, content_type)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
349
355
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
+
def matching_body_array?(query_parameters, pattern, content_type)
|
|
357
|
+
return false unless query_parameters.is_a?(Array)
|
|
358
|
+
return false unless query_parameters.length == pattern.length
|
|
359
|
+
|
|
360
|
+
query_parameters.each_with_index do |actual, index|
|
|
361
|
+
expected = pattern[index]
|
|
362
|
+
return false unless matching_values(actual, expected, content_type)
|
|
356
363
|
end
|
|
364
|
+
|
|
357
365
|
true
|
|
358
366
|
end
|
|
359
367
|
|
|
368
|
+
def matching_values(actual, expected, content_type)
|
|
369
|
+
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
|
|
370
|
+
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
|
|
371
|
+
|
|
372
|
+
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
|
|
373
|
+
expected === actual
|
|
374
|
+
end
|
|
375
|
+
|
|
360
376
|
def empty_string?(string)
|
|
361
377
|
string.nil? || string == ""
|
|
362
378
|
end
|
|
@@ -35,11 +35,11 @@ module WebMock
|
|
|
35
35
|
alias == eql?
|
|
36
36
|
|
|
37
37
|
def url_encoded?
|
|
38
|
-
!!(headers
|
|
38
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def json_headers?
|
|
42
|
-
!!(headers
|
|
42
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
private
|
data/lib/webmock/response.rb
CHANGED
|
@@ -14,8 +14,11 @@ module WebMock
|
|
|
14
14
|
|
|
15
15
|
class Response
|
|
16
16
|
def initialize(options = {})
|
|
17
|
-
|
|
17
|
+
case options
|
|
18
|
+
when IO, StringIO
|
|
18
19
|
self.options = read_raw_response(options)
|
|
20
|
+
when String
|
|
21
|
+
self.options = read_raw_response(StringIO.new(options))
|
|
19
22
|
else
|
|
20
23
|
self.options = options
|
|
21
24
|
end
|
|
@@ -120,13 +123,8 @@ module WebMock
|
|
|
120
123
|
end
|
|
121
124
|
end
|
|
122
125
|
|
|
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)
|
|
126
|
+
def read_raw_response(io)
|
|
127
|
+
socket = ::Net::BufferedIO.new(io)
|
|
130
128
|
response = ::Net::HTTPResponse.read_new(socket)
|
|
131
129
|
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
|
|
132
130
|
response.reading_body(socket, true) {}
|
|
@@ -138,6 +136,8 @@ module WebMock
|
|
|
138
136
|
options[:body] = response.read_body
|
|
139
137
|
options[:status] = [response.code.to_i, response.message]
|
|
140
138
|
options
|
|
139
|
+
ensure
|
|
140
|
+
socket.close
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
InvalidBody = Class.new(StandardError)
|
data/lib/webmock/version.rb
CHANGED
|
@@ -115,33 +115,16 @@ describe "Net:HTTP" do
|
|
|
115
115
|
expect(Net::HTTP.start("www.example.com") { |http| http.request(req)}.body).to eq("abc")
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
it "raises an ArgumentError if passed headers as symbols
|
|
118
|
+
it "raises an ArgumentError if passed headers as symbols" do
|
|
119
119
|
uri = URI.parse("http://google.com/")
|
|
120
120
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
121
121
|
request = Net::HTTP::Get.new(uri.request_uri)
|
|
122
|
+
request[:InvalidHeaderSinceItsASymbol] = "this will not be valid"
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if :symbol.respond_to?(:downcase)
|
|
128
|
-
request[:InvalidHeaderSinceItsASymbol] = "this will not be valid"
|
|
129
|
-
else
|
|
130
|
-
request.instance_eval do
|
|
131
|
-
@header = request.to_hash.merge({InvalidHeaderSinceItsASymbol: "this will not be valid"})
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
|
|
136
|
-
expect do
|
|
137
|
-
http.request(request)
|
|
138
|
-
end.to raise_error ArgumentError, "Net:HTTP does not accept headers as symbols"
|
|
139
|
-
else
|
|
140
|
-
stub_http_request(:get, "google.com").with(headers: { InvalidHeaderSinceItsASymbol: "this will not be valid" })
|
|
141
|
-
expect do
|
|
142
|
-
http.request(request)
|
|
143
|
-
end.not_to raise_error
|
|
144
|
-
end
|
|
124
|
+
stub_http_request(:get, "google.com").with(headers: { InvalidHeaderSinceItsASymbol: "this will not be valid" })
|
|
125
|
+
expect do
|
|
126
|
+
http.request(request)
|
|
127
|
+
end.not_to raise_error
|
|
145
128
|
end
|
|
146
129
|
|
|
147
130
|
it "should handle multiple values for the same response header" do
|
|
@@ -213,6 +196,22 @@ describe "Net:HTTP" do
|
|
|
213
196
|
end
|
|
214
197
|
end
|
|
215
198
|
|
|
199
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
|
|
200
|
+
it "uses the StubSocket to provide IP address" do
|
|
201
|
+
Net::HTTP.start("example.com") do |http|
|
|
202
|
+
expect(http.ipaddr).to eq("127.0.0.1")
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "defines common socket methods" do
|
|
208
|
+
Net::HTTP.start("example.com") do |http|
|
|
209
|
+
socket = http.instance_variable_get(:@socket)
|
|
210
|
+
expect(socket.io.ssl_version).to eq("TLSv1.3")
|
|
211
|
+
expect(socket.io.cipher).to eq(["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128])
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
216
215
|
describe "connecting on Net::HTTP.start" do
|
|
217
216
|
before(:each) do
|
|
218
217
|
@http = Net::HTTP.new('www.google.com', 443)
|
|
@@ -93,31 +93,29 @@ unless RUBY_PLATFORM =~ /java/
|
|
|
93
93
|
@sess.copy("/abc", "/def")
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
end
|
|
96
|
+
describe "handling encoding same way as patron" do
|
|
97
|
+
around(:each) do |example|
|
|
98
|
+
@encoding = Encoding.default_internal
|
|
99
|
+
Encoding.default_internal = "UTF-8"
|
|
100
|
+
example.run
|
|
101
|
+
Encoding.default_internal = @encoding
|
|
102
|
+
end
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
it "should not encode body with default encoding" do
|
|
105
|
+
stub_request(:get, "www.example.com").
|
|
106
|
+
to_return(body: "Øl")
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
expect(@sess.get("").body.encoding).to eq(Encoding::ASCII_8BIT)
|
|
109
|
+
expect(@sess.get("").inspectable_body.encoding).to eq(Encoding::UTF_8)
|
|
110
|
+
end
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
it "should not encode body to default internal" do
|
|
113
|
+
stub_request(:get, "www.example.com").
|
|
114
|
+
to_return(headers: {'Content-Type' => 'text/html; charset=iso-8859-1'},
|
|
115
|
+
body: "Øl".encode("iso-8859-1"))
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
end
|
|
117
|
+
expect(@sess.get("").body.encoding).to eq(Encoding::ASCII_8BIT)
|
|
118
|
+
expect(@sess.get("").decoded_body.encoding).to eq(Encoding.default_internal)
|
|
121
119
|
end
|
|
122
120
|
end
|
|
123
121
|
end
|
|
@@ -547,6 +547,18 @@ describe WebMock::RequestPattern do
|
|
|
547
547
|
body: "{\"a\":\"1\",\"b\":\"five\",\"c\":{\"d\":[\"e\",\"f\"]}}"))
|
|
548
548
|
end
|
|
549
549
|
|
|
550
|
+
it "should match if the request body has a top level array" do
|
|
551
|
+
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: [{a: 1}])).
|
|
552
|
+
to match(WebMock::RequestSignature.new(:post, "www.example.com",
|
|
553
|
+
headers: {content_type: content_type}, body: "[{\"a\":1}]"))
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
it "should not match if the request body has a different top level array" do
|
|
557
|
+
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: ["a", "b"])).
|
|
558
|
+
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
|
|
559
|
+
headers: {content_type: content_type}, body: "[\"a\", \"c\"]"))
|
|
560
|
+
end
|
|
561
|
+
|
|
550
562
|
it "should not match when body is not json" do
|
|
551
563
|
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
|
|
552
564
|
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
|
data/spec/unit/response_spec.rb
CHANGED
|
@@ -142,6 +142,34 @@ describe WebMock::Response do
|
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
describe "from raw response" do
|
|
145
|
+
describe "when input is a StringIO" do
|
|
146
|
+
before(:each) do
|
|
147
|
+
@io = StringIO.new(File.read(CURL_EXAMPLE_OUTPUT_PATH))
|
|
148
|
+
@response = WebMock::Response.new(@io)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "should read status" do
|
|
152
|
+
expect(@response.status).to eq([202, "OK"])
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should read headers" do
|
|
156
|
+
expect(@response.headers).to eq(
|
|
157
|
+
"Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
|
|
158
|
+
"Content-Type"=>"text/html; charset=UTF-8",
|
|
159
|
+
"Content-Length"=>"419",
|
|
160
|
+
"Connection"=>"Keep-Alive",
|
|
161
|
+
"Accept"=>"image/jpeg, image/png"
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "should read body" do
|
|
166
|
+
expect(@response.body.size).to eq(419)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "should close IO" do
|
|
170
|
+
expect(@io).to be_closed
|
|
171
|
+
end
|
|
172
|
+
end
|
|
145
173
|
|
|
146
174
|
describe "when input is IO" do
|
|
147
175
|
before(:each) do
|
data/webmock.gemspec
CHANGED
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
|
9
9
|
s.authors = ['Bartosz Blimke']
|
|
10
10
|
s.email = ['bartosz.blimke@gmail.com']
|
|
11
|
-
s.homepage = '
|
|
11
|
+
s.homepage = 'https://github.com/bblimke/webmock'
|
|
12
12
|
s.summary = %q{Library for stubbing HTTP requests in Ruby.}
|
|
13
13
|
s.description = %q{WebMock allows stubbing HTTP requests and setting expectations on HTTP requests.}
|
|
14
14
|
s.license = "MIT"
|
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
|
21
21
|
'wiki_uri' => 'https://github.com/bblimke/webmock/wiki'
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
s.required_ruby_version = '>= 2.
|
|
24
|
+
s.required_ruby_version = '>= 2.3'
|
|
25
25
|
|
|
26
26
|
s.add_dependency 'addressable', '>= 2.8.0'
|
|
27
27
|
s.add_dependency 'crack', '>= 0.3.2'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: webmock
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.18.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bartosz Blimke
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-08-
|
|
11
|
+
date: 2022-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -416,14 +416,14 @@ files:
|
|
|
416
416
|
- test/test_helper.rb
|
|
417
417
|
- test/test_webmock.rb
|
|
418
418
|
- webmock.gemspec
|
|
419
|
-
homepage:
|
|
419
|
+
homepage: https://github.com/bblimke/webmock
|
|
420
420
|
licenses:
|
|
421
421
|
- MIT
|
|
422
422
|
metadata:
|
|
423
423
|
bug_tracker_uri: https://github.com/bblimke/webmock/issues
|
|
424
|
-
changelog_uri: https://github.com/bblimke/webmock/blob/v3.
|
|
425
|
-
documentation_uri: https://www.rubydoc.info/gems/webmock/3.
|
|
426
|
-
source_code_uri: https://github.com/bblimke/webmock/tree/v3.
|
|
424
|
+
changelog_uri: https://github.com/bblimke/webmock/blob/v3.18.0/CHANGELOG.md
|
|
425
|
+
documentation_uri: https://www.rubydoc.info/gems/webmock/3.18.0
|
|
426
|
+
source_code_uri: https://github.com/bblimke/webmock/tree/v3.18.0
|
|
427
427
|
wiki_uri: https://github.com/bblimke/webmock/wiki
|
|
428
428
|
post_install_message:
|
|
429
429
|
rdoc_options: []
|
|
@@ -433,14 +433,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
433
433
|
requirements:
|
|
434
434
|
- - ">="
|
|
435
435
|
- !ruby/object:Gem::Version
|
|
436
|
-
version: '2.
|
|
436
|
+
version: '2.3'
|
|
437
437
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
438
438
|
requirements:
|
|
439
439
|
- - ">="
|
|
440
440
|
- !ruby/object:Gem::Version
|
|
441
441
|
version: '0'
|
|
442
442
|
requirements: []
|
|
443
|
-
rubygems_version: 3.
|
|
443
|
+
rubygems_version: 3.0.3
|
|
444
444
|
signing_key:
|
|
445
445
|
specification_version: 4
|
|
446
446
|
summary: Library for stubbing HTTP requests in Ruby.
|