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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +144 -6
  3. data/README.md +54 -18
  4. data/lib/webmock/api.rb +2 -0
  5. data/lib/webmock/assertion_failure.rb +2 -0
  6. data/lib/webmock/callback_registry.rb +2 -0
  7. data/lib/webmock/config.rb +2 -0
  8. data/lib/webmock/cucumber.rb +2 -0
  9. data/lib/webmock/deprecation.rb +2 -0
  10. data/lib/webmock/errors.rb +2 -0
  11. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +2 -0
  12. data/lib/webmock/http_lib_adapters/curb_adapter.rb +2 -0
  13. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +15 -7
  14. data/lib/webmock/http_lib_adapters/excon_adapter.rb +2 -0
  15. data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
  16. data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
  17. data/lib/webmock/http_lib_adapters/http_rb/client.rb +2 -0
  18. data/lib/webmock/http_lib_adapters/http_rb/request.rb +17 -5
  19. data/lib/webmock/http_lib_adapters/http_rb/response.rb +32 -12
  20. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +2 -0
  21. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +2 -0
  22. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +7 -5
  23. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +26 -25
  24. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +2 -0
  25. data/lib/webmock/http_lib_adapters/net_http.rb +19 -101
  26. data/lib/webmock/http_lib_adapters/net_http_response.rb +2 -0
  27. data/lib/webmock/http_lib_adapters/patron_adapter.rb +2 -0
  28. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
  29. data/lib/webmock/matchers/any_arg_matcher.rb +2 -0
  30. data/lib/webmock/matchers/hash_argument_matcher.rb +2 -0
  31. data/lib/webmock/matchers/hash_excluding_matcher.rb +2 -0
  32. data/lib/webmock/matchers/hash_including_matcher.rb +2 -0
  33. data/lib/webmock/minitest.rb +2 -0
  34. data/lib/webmock/rack_response.rb +5 -1
  35. data/lib/webmock/request_body_diff.rb +2 -0
  36. data/lib/webmock/request_execution_verifier.rb +2 -0
  37. data/lib/webmock/request_pattern.rb +26 -8
  38. data/lib/webmock/request_registry.rb +2 -0
  39. data/lib/webmock/request_signature.rb +4 -2
  40. data/lib/webmock/request_signature_snippet.rb +2 -0
  41. data/lib/webmock/request_stub.rb +20 -1
  42. data/lib/webmock/response.rb +15 -13
  43. data/lib/webmock/responses_sequence.rb +2 -0
  44. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
  45. data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
  46. data/lib/webmock/rspec/matchers.rb +2 -0
  47. data/lib/webmock/rspec.rb +2 -0
  48. data/lib/webmock/stub_registry.rb +2 -0
  49. data/lib/webmock/stub_request_snippet.rb +2 -0
  50. data/lib/webmock/test_unit.rb +2 -0
  51. data/lib/webmock/util/hash_counter.rb +12 -6
  52. data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
  53. data/lib/webmock/util/hash_validator.rb +2 -0
  54. data/lib/webmock/util/headers.rb +23 -10
  55. data/lib/webmock/util/json.rb +2 -0
  56. data/lib/webmock/util/query_mapper.rb +2 -0
  57. data/lib/webmock/util/uri.rb +3 -1
  58. data/lib/webmock/util/values_stringifier.rb +2 -0
  59. data/lib/webmock/util/version_checker.rb +7 -5
  60. data/lib/webmock/version.rb +3 -1
  61. data/lib/webmock/webmock.rb +2 -0
  62. data/lib/webmock.rb +2 -0
  63. metadata +43 -161
  64. data/.gemtest +0 -0
  65. data/.github/workflows/CI.yml +0 -38
  66. data/.gitignore +0 -34
  67. data/.rspec-tm +0 -2
  68. data/Gemfile +0 -9
  69. data/Rakefile +0 -38
  70. data/minitest/test_helper.rb +0 -34
  71. data/minitest/test_webmock.rb +0 -9
  72. data/minitest/webmock_spec.rb +0 -60
  73. data/spec/acceptance/async_http_client/async_http_client_spec.rb +0 -375
  74. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +0 -73
  75. data/spec/acceptance/curb/curb_spec.rb +0 -510
  76. data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
  77. data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -462
  78. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
  79. data/spec/acceptance/excon/excon_spec.rb +0 -77
  80. data/spec/acceptance/excon/excon_spec_helper.rb +0 -52
  81. data/spec/acceptance/http_rb/http_rb_spec.rb +0 -93
  82. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -54
  83. data/spec/acceptance/httpclient/httpclient_spec.rb +0 -217
  84. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
  85. data/spec/acceptance/manticore/manticore_spec.rb +0 -107
  86. data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
  87. data/spec/acceptance/net_http/net_http_shared.rb +0 -190
  88. data/spec/acceptance/net_http/net_http_spec.rb +0 -396
  89. data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
  90. data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
  91. data/spec/acceptance/patron/patron_spec.rb +0 -125
  92. data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
  93. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
  94. data/spec/acceptance/shared/callbacks.rb +0 -148
  95. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
  96. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
  97. data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
  98. data/spec/acceptance/shared/request_expectations.rb +0 -930
  99. data/spec/acceptance/shared/returning_declared_responses.rb +0 -409
  100. data/spec/acceptance/shared/stubbing_requests.rb +0 -678
  101. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
  102. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
  103. data/spec/acceptance/webmock_shared.rb +0 -41
  104. data/spec/fixtures/test.txt +0 -1
  105. data/spec/quality_spec.rb +0 -84
  106. data/spec/spec_helper.rb +0 -48
  107. data/spec/support/example_curl_output.txt +0 -22
  108. data/spec/support/failures.rb +0 -9
  109. data/spec/support/my_rack_app.rb +0 -53
  110. data/spec/support/network_connection.rb +0 -19
  111. data/spec/support/webmock_server.rb +0 -70
  112. data/spec/unit/api_spec.rb +0 -175
  113. data/spec/unit/errors_spec.rb +0 -129
  114. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
  115. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
  116. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +0 -61
  117. data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
  118. data/spec/unit/rack_response_spec.rb +0 -112
  119. data/spec/unit/request_body_diff_spec.rb +0 -90
  120. data/spec/unit/request_execution_verifier_spec.rb +0 -208
  121. data/spec/unit/request_pattern_spec.rb +0 -736
  122. data/spec/unit/request_registry_spec.rb +0 -95
  123. data/spec/unit/request_signature_snippet_spec.rb +0 -89
  124. data/spec/unit/request_signature_spec.rb +0 -175
  125. data/spec/unit/request_stub_spec.rb +0 -234
  126. data/spec/unit/response_spec.rb +0 -286
  127. data/spec/unit/stub_registry_spec.rb +0 -103
  128. data/spec/unit/stub_request_snippet_spec.rb +0 -115
  129. data/spec/unit/util/hash_counter_spec.rb +0 -39
  130. data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
  131. data/spec/unit/util/headers_spec.rb +0 -28
  132. data/spec/unit/util/json_spec.rb +0 -33
  133. data/spec/unit/util/query_mapper_spec.rb +0 -157
  134. data/spec/unit/util/uri_spec.rb +0 -371
  135. data/spec/unit/util/version_checker_spec.rb +0 -65
  136. data/spec/unit/webmock_spec.rb +0 -114
  137. data/test/http_request.rb +0 -24
  138. data/test/shared_test.rb +0 -108
  139. data/test/test_helper.rb +0 -23
  140. data/test/test_webmock.rb +0 -12
  141. 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 = synchronize_request_response { webmock_responses.delete(request_signature) }
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
- synchronize_request_response { webmock_responses.delete(request_signature) }
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
- synchronize_request_response { webmock_request_signatures << request_signature }
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
- @webmock_responses ||= Hash.new do |hash, request_signature|
190
- synchronize_request_response do
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
- @webmock_request_signatures ||= []
205
+ Thread.current[WEBMOCK_HTTPCLIENT_REQUEST_SIGNATURES] ||= []
198
206
  end
199
207
 
200
208
  def previous_signature_for(signature)
201
- synchronize_request_response do
202
- return nil unless index = webmock_request_signatures.index(signature)
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 synchronize_request_response
221
- if REQUEST_RESPONSE_LOCK.owned?
222
- yield
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
  begin
2
4
  require 'manticore'
3
5
  rescue LoadError
@@ -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
- do_start if @socket.is_a?(StubSocket)
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 timeout_exception, "execution expired"
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 ||= true
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
  # This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
2
4
 
3
5
  # A Net::HTTP response that has already been read raises an IOError when #read_body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'patron'
3
5
  rescue LoadError
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::AnyArgMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # Base class for Hash matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'minitest/test'
3
5
  test_class = Minitest::Test
@@ -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
- env['rack.version'] = Rack::VERSION
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
  require "hashdiff"
2
4
  require "json"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class RequestExecutionVerifier
3
5
 
@@ -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?(WebMock::Matchers::HashIncludingMatcher)
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
- query_parameters.each do |key, actual|
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
- if actual.is_a?(Hash) && expected.is_a?(Hash)
351
- return false unless matching_body_hashes?(actual, expected, content_type)
352
- else
353
- expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
354
- return false unless expected === actual
355
- end
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 RequestRegistry
@@ -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 && headers.fetch('Content-Type', "").start_with?('application/x-www-form-urlencoded'))
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 && headers.fetch('Content-Type', "").start_with?('application/json'))
44
+ !!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
43
45
  end
44
46
 
45
47
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pp"
2
4
 
3
5
  module WebMock
@@ -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: body.is_a?(Hash) ? body.to_json : body
53
+ body: json_body
35
54
  )
36
55
  end
37
56
 
@@ -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
- if options.is_a?(IO) || options.is_a?(String)
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.class.is_a?(Hash)
116
- raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}' instead." \
117
- "\n What shall we encode it to? try calling .to_json .to_xml instead on the hash instead, or otherwise convert it to a string."
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(raw_response)
124
- if raw_response.is_a?(IO)
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)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  class ResponsesSequence
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class RequestPatternMatcher
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class WebMockMatcher
3
5