webmock 1.8.6 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/CI.yml +37 -0
  3. data/.gitignore +6 -0
  4. data/CHANGELOG.md +1198 -0
  5. data/Gemfile +3 -15
  6. data/README.md +761 -305
  7. data/Rakefile +13 -40
  8. data/lib/webmock/api.rb +63 -17
  9. data/lib/webmock/callback_registry.rb +1 -1
  10. data/lib/webmock/config.rb +8 -0
  11. data/lib/webmock/cucumber.rb +2 -0
  12. data/lib/webmock/errors.rb +8 -24
  13. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
  14. data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
  15. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
  16. data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
  17. data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
  18. data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
  19. data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
  20. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
  21. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
  22. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
  23. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
  24. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
  25. data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
  26. data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
  27. data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
  28. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
  29. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  30. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  31. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  32. data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
  33. data/lib/webmock/minitest.rb +29 -3
  34. data/lib/webmock/rack_response.rb +14 -7
  35. data/lib/webmock/request_body_diff.rb +64 -0
  36. data/lib/webmock/request_execution_verifier.rb +38 -17
  37. data/lib/webmock/request_pattern.rb +158 -38
  38. data/lib/webmock/request_registry.rb +3 -3
  39. data/lib/webmock/request_signature.rb +7 -3
  40. data/lib/webmock/request_signature_snippet.rb +61 -0
  41. data/lib/webmock/request_stub.rb +9 -6
  42. data/lib/webmock/response.rb +30 -15
  43. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
  44. data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
  45. data/lib/webmock/rspec/matchers.rb +0 -1
  46. data/lib/webmock/rspec.rb +11 -2
  47. data/lib/webmock/stub_registry.rb +31 -10
  48. data/lib/webmock/stub_request_snippet.rb +14 -6
  49. data/lib/webmock/test_unit.rb +4 -4
  50. data/lib/webmock/util/hash_counter.rb +20 -6
  51. data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
  52. data/lib/webmock/util/hash_validator.rb +17 -0
  53. data/lib/webmock/util/headers.rb +23 -2
  54. data/lib/webmock/util/json.rb +20 -7
  55. data/lib/webmock/util/query_mapper.rb +281 -0
  56. data/lib/webmock/util/uri.rb +29 -19
  57. data/lib/webmock/util/values_stringifier.rb +20 -0
  58. data/lib/webmock/util/version_checker.rb +40 -2
  59. data/lib/webmock/version.rb +1 -1
  60. data/lib/webmock/webmock.rb +56 -17
  61. data/lib/webmock.rb +56 -46
  62. data/minitest/test_helper.rb +8 -3
  63. data/minitest/test_webmock.rb +4 -1
  64. data/minitest/webmock_spec.rb +16 -6
  65. data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
  66. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  67. data/spec/acceptance/curb/curb_spec.rb +227 -68
  68. data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
  69. data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
  70. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
  71. data/spec/acceptance/excon/excon_spec.rb +66 -4
  72. data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
  73. data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
  74. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
  75. data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
  76. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
  77. data/spec/acceptance/manticore/manticore_spec.rb +107 -0
  78. data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
  79. data/spec/acceptance/net_http/net_http_shared.rb +52 -24
  80. data/spec/acceptance/net_http/net_http_spec.rb +164 -50
  81. data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
  82. data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
  83. data/spec/acceptance/patron/patron_spec.rb +29 -40
  84. data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
  85. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
  86. data/spec/acceptance/shared/callbacks.rb +32 -30
  87. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
  88. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
  89. data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
  90. data/spec/acceptance/shared/request_expectations.rb +560 -296
  91. data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
  92. data/spec/acceptance/shared/stubbing_requests.rb +385 -154
  93. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
  94. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
  95. data/spec/acceptance/webmock_shared.rb +2 -2
  96. data/spec/fixtures/test.txt +1 -0
  97. data/spec/quality_spec.rb +27 -3
  98. data/spec/spec_helper.rb +11 -20
  99. data/spec/support/failures.rb +9 -0
  100. data/spec/support/my_rack_app.rb +8 -3
  101. data/spec/support/network_connection.rb +7 -13
  102. data/spec/support/webmock_server.rb +8 -3
  103. data/spec/unit/api_spec.rb +175 -0
  104. data/spec/unit/errors_spec.rb +116 -19
  105. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
  106. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
  107. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  108. data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
  109. data/spec/unit/rack_response_spec.rb +54 -16
  110. data/spec/unit/request_body_diff_spec.rb +90 -0
  111. data/spec/unit/request_execution_verifier_spec.rb +147 -39
  112. data/spec/unit/request_pattern_spec.rb +462 -198
  113. data/spec/unit/request_registry_spec.rb +29 -9
  114. data/spec/unit/request_signature_snippet_spec.rb +89 -0
  115. data/spec/unit/request_signature_spec.rb +91 -49
  116. data/spec/unit/request_stub_spec.rb +71 -70
  117. data/spec/unit/response_spec.rb +100 -81
  118. data/spec/unit/stub_registry_spec.rb +37 -20
  119. data/spec/unit/stub_request_snippet_spec.rb +51 -31
  120. data/spec/unit/util/hash_counter_spec.rb +6 -6
  121. data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
  122. data/spec/unit/util/headers_spec.rb +4 -4
  123. data/spec/unit/util/json_spec.rb +29 -3
  124. data/spec/unit/util/query_mapper_spec.rb +157 -0
  125. data/spec/unit/util/uri_spec.rb +150 -36
  126. data/spec/unit/util/version_checker_spec.rb +15 -9
  127. data/spec/unit/webmock_spec.rb +57 -4
  128. data/test/http_request.rb +3 -3
  129. data/test/shared_test.rb +45 -13
  130. data/test/test_helper.rb +1 -1
  131. data/test/test_webmock.rb +6 -0
  132. data/webmock.gemspec +30 -11
  133. metadata +308 -199
  134. data/.rvmrc +0 -1
  135. data/.travis.yml +0 -11
  136. data/Guardfile +0 -24
  137. data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
  138. data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +0 -210
@@ -28,15 +28,23 @@ module WebMock
28
28
  Net.send(:const_set, :HTTP, OriginalNetHTTP)
29
29
  Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
30
30
  Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
31
+
32
+ #copy all constants from @webMockNetHTTP to original Net::HTTP
33
+ #in case any constants were added to @webMockNetHTTP instead of Net::HTTP
34
+ #after WebMock was enabled.
35
+ #i.e Net::HTTP::DigestAuth
36
+ @webMockNetHTTP.constants.each do |constant|
37
+ if !OriginalNetHTTP.constants.map(&:to_s).include?(constant.to_s)
38
+ OriginalNetHTTP.send(:const_set, constant, @webMockNetHTTP.const_get(constant))
39
+ end
40
+ end
31
41
  end
32
42
 
33
43
  @webMockNetHTTP = Class.new(Net::HTTP) do
34
44
  class << self
35
- def socket_type_with_webmock
45
+ def socket_type
36
46
  StubSocket
37
47
  end
38
- alias_method :socket_type_without_webmock, :socket_type
39
- alias_method :socket_type, :socket_type_with_webmock
40
48
 
41
49
  if Module.method(:const_defined?).arity == 1
42
50
  def const_defined?(name)
@@ -58,12 +66,12 @@ module WebMock
58
66
 
59
67
  if Module.method(:constants).arity != 0
60
68
  def constants(inherit=true)
61
- super + self.superclass.constants(inherit)
69
+ (super + self.superclass.constants(inherit)).uniq
62
70
  end
63
71
  end
64
72
  end
65
73
 
66
- def request_with_webmock(request, body = nil, &block)
74
+ def request(request, body = nil, &block)
67
75
  request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
68
76
 
69
77
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
@@ -71,7 +79,7 @@ module WebMock
71
79
  if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
72
80
  @socket = Net::HTTP.socket_type.new
73
81
  WebMock::CallbackRegistry.invoke_callbacks(
74
- {:lib => :net_http}, request_signature, webmock_response)
82
+ {lib: :net_http}, request_signature, webmock_response)
75
83
  build_net_http_response(webmock_response, &block)
76
84
  elsif WebMock.net_connect_allowed?(request_signature.uri)
77
85
  check_right_http_connection
@@ -79,28 +87,33 @@ module WebMock
79
87
  if WebMock::CallbackRegistry.any_callbacks?
80
88
  webmock_response = build_webmock_response(response)
81
89
  WebMock::CallbackRegistry.invoke_callbacks(
82
- {:lib => :net_http, :real_request => true}, request_signature, webmock_response)
90
+ {lib: :net_http, real_request: true}, request_signature, webmock_response)
83
91
  end
84
92
  response.extend Net::WebMockHTTPResponse
85
93
  block.call response if block
86
94
  response
87
95
  end
88
- response = if (started? && !WebMock::Config.instance.net_http_connect_on_start) || !started?
89
- @started = false #otherwise start_with_connect wouldn't execute and connect
96
+ super_with_after_request = lambda {
97
+ response = super(request, nil, &nil)
98
+ after_request.call(response)
99
+ }
100
+ if started?
101
+ if WebMock::Config.instance.net_http_connect_on_start
102
+ super_with_after_request.call
103
+ else
104
+ start_with_connect_without_finish {
105
+ super_with_after_request.call
106
+ }
107
+ end
108
+ else
90
109
  start_with_connect {
91
- response = request_without_webmock(request, nil)
92
- after_request.call(response)
110
+ super_with_after_request.call
93
111
  }
94
- else
95
- response = request_without_webmock(request, nil)
96
- after_request.call(response)
97
112
  end
98
113
  else
99
114
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
100
115
  end
101
116
  end
102
- alias_method :request_without_webmock, :request
103
- alias_method :request, :request_with_webmock
104
117
 
105
118
  def start_without_connect
106
119
  raise IOError, 'HTTP session already opened' if @started
@@ -116,19 +129,34 @@ module WebMock
116
129
  self
117
130
  end
118
131
 
119
- def start_with_conditional_connect(&block)
132
+
133
+ def start_with_connect_without_finish # :yield: http
134
+ if block_given?
135
+ begin
136
+ do_start
137
+ return yield(self)
138
+ end
139
+ end
140
+ do_start
141
+ self
142
+ end
143
+
144
+ alias_method :start_with_connect, :start
145
+
146
+ def start(&block)
120
147
  if WebMock::Config.instance.net_http_connect_on_start
121
- start_with_connect(&block)
148
+ super(&block)
122
149
  else
123
150
  start_without_connect(&block)
124
151
  end
125
152
  end
126
- alias_method :start_with_connect, :start
127
- alias_method :start, :start_with_conditional_connect
128
153
 
129
154
  def build_net_http_response(webmock_response, &block)
130
155
  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])
131
- response.instance_variable_set(:@body, webmock_response.body)
156
+ body = webmock_response.body
157
+ body = nil if webmock_response.status[0].to_s == '204'
158
+
159
+ response.instance_variable_set(:@body, body)
132
160
  webmock_response.headers.to_a.each do |name, values|
133
161
  values = [values] unless values.is_a?(Array)
134
162
  values.each do |value|
@@ -140,7 +168,9 @@ module WebMock
140
168
 
141
169
  response.extend Net::WebMockHTTPResponse
142
170
 
143
- raise Timeout::Error, "execution expired" if webmock_response.should_timeout
171
+ if webmock_response.should_timeout
172
+ raise timeout_exception, "execution expired"
173
+ end
144
174
 
145
175
  webmock_response.raise_error_if_any
146
176
 
@@ -149,6 +179,16 @@ module WebMock
149
179
  response
150
180
  end
151
181
 
182
+ def timeout_exception
183
+ if defined?(Net::OpenTimeout)
184
+ # Ruby 2.x
185
+ Net::OpenTimeout
186
+ else
187
+ # Fallback, if things change
188
+ Timeout::Error
189
+ end
190
+ end
191
+
152
192
  def build_webmock_response(net_http_response)
153
193
  webmock_response = WebMock::Response.new
154
194
  webmock_response.status = [
@@ -182,9 +222,22 @@ module WebMock
182
222
  end
183
223
  end
184
224
 
225
+ # patch for StringIO behavior in Ruby 2.2.3
226
+ # https://github.com/bblimke/webmock/issues/558
227
+ class PatchedStringIO < StringIO #:nodoc:
228
+
229
+ alias_method :orig_read_nonblock, :read_nonblock
230
+
231
+ def read_nonblock(size, *args, **kwargs)
232
+ args.reject! {|arg| !arg.is_a?(Hash)}
233
+ orig_read_nonblock(size, *args, **kwargs)
234
+ end
235
+
236
+ end
237
+
185
238
  class StubSocket #:nodoc:
186
239
 
187
- attr_accessor :read_timeout
240
+ attr_accessor :read_timeout, :continue_timeout, :write_timeout
188
241
 
189
242
  def initialize(*args)
190
243
  end
@@ -193,29 +246,64 @@ class StubSocket #:nodoc:
193
246
  @closed ||= true
194
247
  end
195
248
 
249
+ def close
250
+ end
251
+
196
252
  def readuntil(*args)
197
253
  end
198
254
 
255
+ def io
256
+ @io ||= StubIO.new
257
+ end
258
+
259
+ class StubIO
260
+ def setsockopt(*args); end
261
+ end
199
262
  end
200
263
 
201
264
  module Net #:nodoc: all
202
265
 
203
266
  class WebMockNetBufferedIO < BufferedIO
204
- def initialize_with_webmock(io, debug_output = nil)
205
- @read_timeout = 60
206
- @rbuf = ''
207
- @debug_output = debug_output
208
-
209
- @io = case io
267
+ def initialize(io, *args, **kwargs)
268
+ io = case io
210
269
  when Socket, OpenSSL::SSL::SSLSocket, IO
211
270
  io
271
+ when StringIO
272
+ PatchedStringIO.new(io.string)
212
273
  when String
213
- StringIO.new(io)
274
+ PatchedStringIO.new(io)
275
+ end
276
+ raise "Unable to create local socket" unless io
277
+
278
+ # Prior to 2.4.0 `BufferedIO` only takes a single argument (`io`) with no
279
+ # options. Here we pass through our full set of arguments only if we're
280
+ # on 2.4.0 or later, and use a simplified invocation otherwise.
281
+ if RUBY_VERSION >= '2.4.0'
282
+ super
283
+ else
284
+ super(io)
285
+ end
286
+ end
287
+
288
+ if RUBY_VERSION >= '2.6.0'
289
+ # https://github.com/ruby/ruby/blob/7d02441f0d6e5c9d0a73a024519eba4f69e36dce/lib/net/protocol.rb#L208
290
+ # Modified version of method from ruby, so that nil is always passed into orig_read_nonblock to avoid timeout
291
+ def rbuf_fill
292
+ case rv = @io.read_nonblock(BUFSIZE, nil, exception: false)
293
+ when String
294
+ return if rv.nil?
295
+ @rbuf << rv
296
+ rv.clear
297
+ return
298
+ when :wait_readable
299
+ @io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
300
+ when :wait_writable
301
+ @io.to_io.wait_writable(@read_timeout) or raise Net::ReadTimeout
302
+ when nil
303
+ raise EOFError, 'end of file reached'
304
+ end while true
214
305
  end
215
- raise "Unable to create local socket" unless @io
216
306
  end
217
- alias_method :initialize_without_webmock, :initialize
218
- alias_method :initialize, :initialize_with_webmock
219
307
  end
220
308
 
221
309
  end
@@ -225,25 +313,19 @@ module WebMock
225
313
  module NetHTTPUtility
226
314
 
227
315
  def self.request_signature_from_request(net_http, request, body = nil)
228
- protocol = net_http.use_ssl? ? "https" : "http"
229
-
230
316
  path = request.path
231
- path = WebMock::Util::URI.heuristic_parse(request.path).request_uri if request.path =~ /^http/
232
317
 
233
- if request["authorization"] =~ /^Basic /
234
- userinfo = WebMock::Util::Headers.decode_userinfo_from_header(request["authorization"])
235
- userinfo = WebMock::Util::URI.encode_unsafe_chars_in_userinfo(userinfo) + "@"
236
- else
237
- userinfo = ""
318
+ if path.respond_to?(:request_uri) #https://github.com/bblimke/webmock/issues/288
319
+ path = path.request_uri
238
320
  end
239
321
 
240
- uri = "#{protocol}://#{userinfo}#{net_http.address}:#{net_http.port}#{path}"
322
+ path = WebMock::Util::URI.heuristic_parse(path).request_uri if path =~ /^http/
323
+
324
+ uri = get_uri(net_http, path)
241
325
  method = request.method.downcase.to_sym
242
326
 
243
327
  headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
244
-
245
- headers.reject! {|k,v| k =~ /[Aa]uthorization/ && v.first =~ /^Basic / } #we added it to url userinfo
246
-
328
+ validate_headers(headers)
247
329
 
248
330
  if request.body_stream
249
331
  body = request.body_stream.read
@@ -256,9 +338,36 @@ module WebMock
256
338
  request.set_body_internal body
257
339
  end
258
340
 
259
- WebMock::RequestSignature.new(method, uri, :body => request.body, :headers => headers)
341
+ WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
342
+ end
343
+
344
+ def self.get_uri(net_http, path)
345
+ protocol = net_http.use_ssl? ? "https" : "http"
346
+
347
+ hostname = net_http.address
348
+ hostname = "[#{hostname}]" if /\A\[.*\]\z/ !~ hostname && /:/ =~ hostname
349
+
350
+ "#{protocol}://#{hostname}:#{net_http.port}#{path}"
260
351
  end
261
352
 
353
+ def self.validate_headers(headers)
354
+ # For Ruby versions < 2.3.0, if you make a request with headers that are symbols
355
+ # Net::HTTP raises a NoMethodError
356
+ #
357
+ # WebMock normalizes headers when creating a RequestSignature,
358
+ # and will update all headers from symbols to strings.
359
+ #
360
+ # This could create a false positive in a test suite with WebMock.
361
+ #
362
+ # So before this point, WebMock raises an ArgumentError if any of the headers are symbols
363
+ # instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
364
+ if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
365
+ header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
366
+ if header_as_symbol
367
+ raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
368
+ end
369
+ end
370
+ end
262
371
 
263
372
  def self.check_right_http_connection
264
373
  @was_right_http_connection_loaded = defined?(RightHttpConnection)
@@ -23,7 +23,7 @@ module Net
23
23
  return nil if @body.nil?
24
24
 
25
25
  dest ||= ::Net::ReadAdapter.new(block)
26
- dest << @body
26
+ dest << @body.dup
27
27
  @body = dest
28
28
  ensure
29
29
  # allow subsequent calls to #read_body to proceed as normal, without our hack...
@@ -13,7 +13,7 @@ if defined?(::Patron)
13
13
  OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
14
14
 
15
15
  class WebMockPatronSession < ::Patron::Session
16
- def handle_request_with_webmock(req)
16
+ def handle_request(req)
17
17
  request_signature =
18
18
  WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
19
19
 
@@ -25,15 +25,15 @@ if defined?(::Patron)
25
25
  res = WebMock::HttpLibAdapters::PatronAdapter.
26
26
  build_patron_response(webmock_response, default_response_charset)
27
27
  WebMock::CallbackRegistry.invoke_callbacks(
28
- {:lib => :patron}, request_signature, webmock_response)
28
+ {lib: :patron}, request_signature, webmock_response)
29
29
  res
30
30
  elsif WebMock.net_connect_allowed?(request_signature.uri)
31
- res = handle_request_without_webmock(req)
31
+ res = super
32
32
  if WebMock::CallbackRegistry.any_callbacks?
33
33
  webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
34
34
  build_webmock_response(res)
35
35
  WebMock::CallbackRegistry.invoke_callbacks(
36
- {:lib => :patron, :real_request => true}, request_signature,
36
+ {lib: :patron, real_request: true}, request_signature,
37
37
  webmock_response)
38
38
  end
39
39
  res
@@ -41,9 +41,6 @@ if defined?(::Patron)
41
41
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
42
42
  end
43
43
  end
44
-
45
- alias_method :handle_request_without_webmock, :handle_request
46
- alias_method :handle_request, :handle_request_with_webmock
47
44
  end
48
45
 
49
46
  def self.enable!
@@ -71,10 +68,8 @@ if defined?(::Patron)
71
68
  def self.build_request_signature(req)
72
69
  uri = WebMock::Util::URI.heuristic_parse(req.url)
73
70
  uri.path = uri.normalized_path.gsub("[^:]//","/")
74
- uri.user = req.username
75
- uri.password = req.password
76
71
 
77
- if [:put, :post].include?(req.action)
72
+ if [:put, :post, :patch].include?(req.action)
78
73
  if req.file_name
79
74
  if !File.exist?(req.file_name) || !File.readable?(req.file_name)
80
75
  raise ArgumentError.new("Unable to open specified file.")
@@ -87,11 +82,17 @@ if defined?(::Patron)
87
82
  end
88
83
  end
89
84
 
85
+ headers = req.headers
86
+
87
+ if req.credentials
88
+ headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.credentials)
89
+ end
90
+
90
91
  request_signature = WebMock::RequestSignature.new(
91
92
  req.action,
92
93
  uri.to_s,
93
- :body => request_body,
94
- :headers => req.headers
94
+ body: request_body,
95
+ headers: headers
95
96
  )
96
97
  request_signature
97
98
  end
@@ -105,11 +106,11 @@ if defined?(::Patron)
105
106
  header_data = ([status_line] + header_fields).join("\r\n")
106
107
 
107
108
  ::Patron::Response.new(
108
- "",
109
+ "".dup,
109
110
  webmock_response.status[0],
110
111
  0,
111
112
  header_data,
112
- webmock_response.body,
113
+ webmock_response.body.dup,
113
114
  default_response_charset
114
115
  )
115
116
  end
@@ -117,7 +118,7 @@ if defined?(::Patron)
117
118
  def self.build_webmock_response(patron_response)
118
119
  webmock_response = WebMock::Response.new
119
120
  reason = patron_response.status_line.
120
- scan(%r(\AHTTP/(\d+\.\d+)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
121
+ scan(%r(\AHTTP/(\d+(?:\.\d+)?)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
121
122
  webmock_response.status = [patron_response.status, reason]
122
123
  webmock_response.body = patron_response.body
123
124
  webmock_response.headers = patron_response.headers
@@ -14,53 +14,63 @@ if defined?(Typhoeus)
14
14
 
15
15
  def self.enable!
16
16
  @disabled = false
17
+ add_before_callback
17
18
  add_after_request_callback
18
- ::Typhoeus::Hydra.allow_net_connect = true
19
+ ::Typhoeus::Config.block_connection = true
19
20
  end
20
21
 
21
22
  def self.disable!
22
23
  @disabled = true
23
24
  remove_after_request_callback
24
- ::Typhoeus::Hydra.allow_net_connect = true
25
+ remove_before_callback
26
+ ::Typhoeus::Config.block_connection = false
25
27
  end
26
28
 
27
29
  def self.disabled?
28
30
  !!@disabled
29
31
  end
30
32
 
33
+ def self.add_before_callback
34
+ unless Typhoeus.before.include?(BEFORE_CALLBACK)
35
+ Typhoeus.before << BEFORE_CALLBACK
36
+ end
37
+ end
38
+
39
+ def self.remove_before_callback
40
+ Typhoeus.before.delete_if {|v| v == BEFORE_CALLBACK }
41
+ end
42
+
31
43
  def self.add_after_request_callback
32
- unless Typhoeus::Hydra.
33
- global_hooks[:after_request_before_on_complete].
34
- include?(AFTER_REQUEST_CALLBACK)
35
- Typhoeus::Hydra.
36
- global_hooks[:after_request_before_on_complete] << AFTER_REQUEST_CALLBACK
44
+ unless Typhoeus.on_complete.include?(AFTER_REQUEST_CALLBACK)
45
+ Typhoeus.on_complete << AFTER_REQUEST_CALLBACK
37
46
  end
38
47
  end
39
48
 
40
49
  def self.remove_after_request_callback
41
- Typhoeus::Hydra.global_hooks[:after_request_before_on_complete].
42
- delete_if {|v| v == AFTER_REQUEST_CALLBACK }
50
+ Typhoeus.on_complete.delete_if {|v| v == AFTER_REQUEST_CALLBACK }
43
51
  end
44
52
 
45
53
  def self.build_request_signature(req)
46
54
  uri = WebMock::Util::URI.heuristic_parse(req.url)
47
55
  uri.path = uri.normalized_path.gsub("[^:]//","/")
48
- if req.username
49
- uri.user = req.username
50
- uri.password = req.password
56
+
57
+ headers = req.options[:headers]
58
+
59
+ if req.options[:userpwd]
60
+ headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.options[:userpwd])
51
61
  end
52
62
 
53
- body = req.body
63
+ body = req.options[:body]
54
64
 
55
- if req.params && req.method == :post
56
- body = request_body_for_post_request_with_params(req)
65
+ if body.is_a?(Hash)
66
+ body = WebMock::Util::QueryMapper.values_to_query(body)
57
67
  end
58
68
 
59
69
  request_signature = WebMock::RequestSignature.new(
60
- req.method,
70
+ req.options[:method] || :get,
61
71
  uri.to_s,
62
- :body => body,
63
- :headers => req.headers
72
+ body: body,
73
+ headers: headers
64
74
  )
65
75
 
66
76
  req.instance_variable_set(:@__webmock_request_signature, request_signature)
@@ -68,45 +78,35 @@ if defined?(Typhoeus)
68
78
  request_signature
69
79
  end
70
80
 
71
- def self.request_body_for_post_request_with_params(req)
72
- params = req.params
73
- form = Typhoeus::Form.new(params)
74
- form.process!
75
- form.to_s
76
- end
77
81
 
78
82
  def self.build_webmock_response(typhoeus_response)
79
83
  webmock_response = WebMock::Response.new
80
84
  webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message]
81
85
  webmock_response.body = typhoeus_response.body
82
- webmock_response.headers = typhoeus_response.headers_hash
86
+ webmock_response.headers = typhoeus_response.headers
83
87
  webmock_response
84
88
  end
85
89
 
86
- def self.stub_typhoeus(request_signature, webmock_response, typhoeus)
90
+ def self.generate_typhoeus_response(request_signature, webmock_response)
87
91
  response = if webmock_response.should_timeout
88
92
  ::Typhoeus::Response.new(
89
- :code => 0,
90
- :status_message => "",
91
- :body => "",
92
- :headers_hash => {},
93
- :curl_return_code => 28
93
+ code: 0,
94
+ status_message: "",
95
+ body: "",
96
+ headers: {},
97
+ return_code: :operation_timedout
94
98
  )
95
99
  else
96
100
  ::Typhoeus::Response.new(
97
- :code => webmock_response.status[0],
98
- :status_message => webmock_response.status[1],
99
- :body => webmock_response.body,
100
- :headers_hash => webmock_response.headers
101
+ code: webmock_response.status[0],
102
+ status_message: webmock_response.status[1],
103
+ body: webmock_response.body,
104
+ headers: webmock_response.headers,
105
+ effective_url: request_signature.uri
101
106
  )
102
107
  end
103
-
104
-
105
- typhoeus.stub(
106
- request_signature.method || :any,
107
- /.*/,
108
- :webmock_stub => true
109
- ).and_return(response)
108
+ response.mock = :webmock
109
+ response
110
110
  end
111
111
 
112
112
  def self.request_hash(request_signature)
@@ -118,62 +118,56 @@ if defined?(Typhoeus)
118
118
  hash
119
119
  end
120
120
 
121
- AFTER_REQUEST_CALLBACK = Proc.new do |request|
121
+ AFTER_REQUEST_CALLBACK = Proc.new do |response|
122
+ request = response.request
122
123
  request_signature = request.instance_variable_get(:@__webmock_request_signature)
123
124
  webmock_response =
124
125
  ::WebMock::HttpLibAdapters::TyphoeusAdapter.
125
- build_webmock_response(request.response)
126
- if request.response.mock?
126
+ build_webmock_response(response)
127
+ if response.mock
127
128
  WebMock::CallbackRegistry.invoke_callbacks(
128
- {:lib => :typhoeus},
129
+ {lib: :typhoeus},
129
130
  request_signature,
130
131
  webmock_response
131
132
  )
132
133
  else
133
134
  WebMock::CallbackRegistry.invoke_callbacks(
134
- {:lib => :typhoeus, :real_request => true},
135
+ {lib: :typhoeus, real_request: true},
135
136
  request_signature,
136
137
  webmock_response
137
138
  )
138
139
  end
139
140
  end
140
- end
141
- end
142
- end
143
-
144
-
145
- module Typhoeus
146
- class Hydra
147
- def queue_with_webmock(request)
148
- self.clear_webmock_stubs
149
-
150
- if WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
151
- return queue_without_webmock(request)
152
- end
153
-
154
- request_signature =
155
- ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
156
141
 
157
- ::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
158
-
159
- if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
160
- ::WebMock::HttpLibAdapters::TyphoeusAdapter.
161
- stub_typhoeus(request_signature, webmock_response, self)
162
- webmock_response.raise_error_if_any
163
- elsif !WebMock.net_connect_allowed?(request_signature.uri)
164
- raise WebMock::NetConnectNotAllowedError.new(request_signature)
142
+ BEFORE_CALLBACK = Proc.new do |request|
143
+ Typhoeus::Expectation.all.delete_if {|e| e.from == :webmock }
144
+ res = true
145
+
146
+ unless WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
147
+ request_signature = ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
148
+ request.block_connection = false;
149
+
150
+ ::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
151
+
152
+ if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
153
+ # ::WebMock::HttpLibAdapters::TyphoeusAdapter.stub_typhoeus(request_signature, webmock_response, self)
154
+ response = ::WebMock::HttpLibAdapters::TyphoeusAdapter.generate_typhoeus_response(request_signature, webmock_response)
155
+ if request.respond_to?(:on_headers)
156
+ request.execute_headers_callbacks(response)
157
+ end
158
+ if request.respond_to?(:streaming?) && request.streaming?
159
+ response.options[:response_body] = ""
160
+ request.on_body.each { |callback| callback.call(webmock_response.body, response) }
161
+ end
162
+ request.finish(response)
163
+ webmock_response.raise_error_if_any
164
+ res = false
165
+ elsif !WebMock.net_connect_allowed?(request_signature.uri)
166
+ raise WebMock::NetConnectNotAllowedError.new(request_signature)
167
+ end
168
+ end
169
+ res
165
170
  end
166
- queue_without_webmock(request)
167
- end
168
-
169
- alias_method :queue_without_webmock, :queue
170
- alias_method :queue, :queue_with_webmock
171
-
172
- def clear_webmock_stubs
173
- self.stubs = [] unless self.stubs
174
- self.stubs.delete_if {|s|
175
- s.instance_variable_get(:@options)[:webmock_stub]
176
- }
177
171
  end
178
172
  end
179
173
  end
@@ -0,0 +1,13 @@
1
+ module WebMock
2
+ module Matchers
3
+ # this is a based on RSpec::Mocks::ArgumentMatchers::AnyArgMatcher
4
+ class AnyArgMatcher
5
+ def initialize(ignore)
6
+ end
7
+
8
+ def ==(other)
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end