webmock 3.30.0 → 3.32.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0be0b6d1129e7014a36a5dbe7a7e77d3a25852d1668f54c455e0be96cd2d1287
4
- data.tar.gz: db8c3267c3fbf2eef3b69f4b72764a82983e589a6508c9d0be8d2cd53047d484
3
+ metadata.gz: d20abb34dbaefa2fb02ae23a25f33f0762415ead54721033fd7c9ea53a399a9a
4
+ data.tar.gz: 8160f5688d2afa4bd0bf8671ddbf05be797ab7c064a03af7fa7386de7baf424e
5
5
  SHA512:
6
- metadata.gz: ad6692051819395acd28a095acb54762b81b379b9d75115f0572351f2693973558978b24392f2086bb2dd6bb3969730881efb0d2dc54210440c9114bc2c867b6
7
- data.tar.gz: d4c877e82c741f3319e66d803421eb0fb52f3d1a798465bc19c8b55e52d00fc57fca89cd5eb82a52f88d9f0223c2784adcb7110838405a42f05e9e5c26f53561
6
+ metadata.gz: 5fee3bec940d62b056f45cda8e62fab7839bb3d376f4db0b7db64b8a2e2a32ebe48d31b31a84f3c1e8a0662f9e9dd4aa924c44ef4e69a4eb6f63d40a8909c2aa
7
+ data.tar.gz: 38bae4b2800d672db58e5677d40288d5d0d9323414171056bcd19b56ab04432b6a2e64e1c99a600ca8ff5da86bbac29c588eefc3e2705cb792b549bb17b94a5b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ # 3.32.0
4
+
5
+ * Make a `Net::HTTP` object created while WebMock was enabled behave like any other `Net::HTTP` object after `WebMock.disable!` (#1067)
6
+
7
+ Such an object, like a connection cached by net-http-persistent or by Capybara with Selenium, used to raise `ArgumentError` on `start` or a stubbed request, and `WebMock::NetConnectNotAllowedError` on any other request, after WebMock was disabled. It now sends real requests until WebMock is enabled again.
8
+
9
+ Thanks to [Mike Taylor](https://github.com/sealabcore) and [James Rodovich](https://github.com/rodovich)
10
+
11
+ * Connect again when a request is retried on a `Net::HTTP` object that WebMock started without connecting and whose first real connection failed
12
+
13
+ Such a retry used to raise `NoMethodError` (undefined method `closed?` for nil). It now tries to connect again, and raises the connection error if that fails too.
14
+
15
+ * Drop the `Transfer-Encoding` header from stubbed async-http responses, as WebMock already does with `Content-Length` (#1044)
16
+
17
+ A stub with a `Transfer-Encoding` header, such as `chunked`, used to fail with "Message contains both transfer encoding and content length". async-http sets both headers itself from the body, and its responses from real servers don't include them either.
18
+
19
+ Thanks to [Tim Mertens](https://github.com/tmertens)
20
+
21
+ * Record requests made with curb's `http_patch` as PATCH requests with their body (#1112)
22
+
23
+ curb has `http_patch` since 1.0.8. WebMock recorded such a request as a GET, or as a POST after `post_body=`, so a PATCH stub never matched it.
24
+
25
+ Thanks to [Andy Williams](https://github.com/sobakasu)
26
+
27
+ * Record a curb request sent without a body as having none, even after an earlier `http_post` or `http_patch` call with a body on the same `Curl::Easy` object
28
+
29
+ For example, after `c.http_post("a=1")`, `c.reset` and `c.http(:POST)`, the second request was recorded with the body `a=1`, so a stub for that body matched it.
30
+
31
+ # 3.31.0
32
+
33
+ * Return the contents of a `File` or `Pathname` body given to `to_return_json`, or returned by its body lambda, instead of encoding the object as a JSON string (#1119)
34
+
35
+ The file is read and closed as it is for `to_return`: when the stub is declared, or on each request when it comes from a lambda.
36
+
37
+ Thanks to [Alex](https://github.com/ac1982)
38
+
39
+ * Match HTTP methods given as a string or in upper case, as in `stub_request("get", ...)`, `a_request("GET", ...)` or `assert_requested("post", ...)` (#821)
40
+
41
+ Before, such a method never matched, so the stub never applied and negative expectations like `assert_not_requested("get", ...)` always passed. A test that passed only because of this can now fail.
42
+
43
+ The method of a request is now always a lower case Symbol too. A request made with an upper case method, as Typhoeus does with `method: :POST`, now matches a `:post` stub, and callbacks and `with` blocks see `:post`.
44
+
45
+ Thanks to [Euisan Kim](https://github.com/euisan)
46
+
3
47
  # 3.30.0
4
48
 
5
49
  * Allow narrowing an RSpec expectation on a stub with `with`, as in `expect(stub).to have_been_requested.once.with(body: "abc")` (#1128)
data/README.md CHANGED
@@ -363,6 +363,20 @@ stub_request(:any, "www.example.com").
363
363
  Net::HTTP.get('www.example.com', '/') # ===> "{\"foo\": \"bar\"}"
364
364
  ```
365
365
 
366
+ A `File` or `Pathname` body is returned as it is, so it should hold JSON that is already encoded:
367
+
368
+ ```ruby
369
+ stub_request(:get, "www.example.com").
370
+ to_return_json(body: Pathname.new('spec/fixtures/response.json'))
371
+ ```
372
+
373
+ As with `to_return`, the file is read and closed when the stub is declared, so later changes to it don't affect the response. To read the file on every request, return it from a lambda. A lambda that returns a `File` must open a new one each time, since each one is closed after it is read.
374
+
375
+ ```ruby
376
+ stub_request(:get, "www.example.com").
377
+ to_return_json(body: -> { Pathname.new('spec/fixtures/response.json') })
378
+ ```
379
+
366
380
  ### Response with custom status message
367
381
 
368
382
  ```ruby
@@ -207,6 +207,10 @@ if defined?(Async::HTTP)
207
207
  module WebMockApplication
208
208
  WEBMOCK_REQUEST_ID_HEADER = 'x-webmock-request-id'.freeze
209
209
 
210
+ # async-http sets these from the body itself. A stub's own values would
211
+ # conflict, as Transfer-Encoding does with the Content-Length it adds.
212
+ FRAMING_HEADERS = %w[content-length transfer-encoding].freeze
213
+
210
214
  class << self
211
215
  def call(request)
212
216
  request.read
@@ -233,8 +237,10 @@ if defined?(Async::HTTP)
233
237
 
234
238
  def build_response(webmock_response)
235
239
  headers = (webmock_response.headers || {}).each_with_object([]) do |(k, value), o|
240
+ next if FRAMING_HEADERS.include?(k.downcase)
241
+
236
242
  Array(value).each do |v|
237
- o.push [k, v] unless k.downcase == 'content-length' # async-http appends the exact content-length automatically
243
+ o.push [k, v]
238
244
  end
239
245
  end
240
246
 
@@ -261,6 +261,15 @@ if defined?(Curl)
261
261
  end
262
262
  end
263
263
 
264
+ # curb has http_patch since 1.0.8.
265
+ if method_defined?(:http_patch)
266
+ def http_patch *data
267
+ @webmock_method = :patch
268
+ @post_body = data.join('&') unless data.empty?
269
+ super
270
+ end
271
+ end
272
+
264
273
  def http_put data = nil
265
274
  @webmock_method = :put
266
275
  @put_data = data if data
@@ -270,7 +279,7 @@ if defined?(Curl)
270
279
 
271
280
  def http_post *data
272
281
  @webmock_method = :post
273
- @post_body = data.join('&') if data && !data.empty?
282
+ @post_body = data.join('&') unless data.empty?
274
283
  super
275
284
  end
276
285
  alias post http_post
@@ -280,6 +289,8 @@ if defined?(Curl)
280
289
  curb_or_webmock { super }
281
290
  ensure
282
291
  reset_webmock_method
292
+ # The body given to http_post or http_patch is for this request only.
293
+ @post_body = nil
283
294
  end
284
295
 
285
296
  def put_data= data
@@ -15,7 +15,15 @@ module WebMock
15
15
  # This will be removed in Ruby 3.5. In Ruby 3.4, const_remove will warn.
16
16
  HAS_LEGACY_CONSTANT = Net.const_defined?(:HTTPSession)
17
17
 
18
+ # Objects created while WebMock was enabled are instances of WebMock's
19
+ # Net::HTTP class, so they check this to act like Net::HTTP once
20
+ # WebMock is disabled.
21
+ def self.enabled?
22
+ @enabled
23
+ end
24
+
18
25
  def self.enable!
26
+ @enabled = true
19
27
  Net.send(:remove_const, :HTTP)
20
28
  Net.send(:const_set, :HTTP, @webMockNetHTTP)
21
29
  if HAS_LEGACY_CONSTANT
@@ -25,6 +33,7 @@ module WebMock
25
33
  end
26
34
 
27
35
  def self.disable!
36
+ @enabled = false
28
37
  Net.send(:remove_const, :HTTP)
29
38
  Net.send(:const_set, :HTTP, OriginalNetHTTP)
30
39
  if HAS_LEGACY_CONSTANT
@@ -83,12 +92,20 @@ module WebMock
83
92
  end
84
93
 
85
94
  def request(request, body = nil, &block)
95
+ unless webmock_enabled?
96
+ # Reconnect for real if started with WebMock's stub socket.
97
+ ensure_actual_connection if started?
98
+ return super
99
+ end
100
+
86
101
  request_signature = WebMock::NetHTTPUtility.request_signature_from_request(self, request, body)
87
102
 
88
103
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
89
104
 
90
105
  if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
91
- @socket = Net::HTTP.socket_type.new
106
+ # Close the real connection left by an earlier request, if any.
107
+ @socket&.close
108
+ @socket = self.class.socket_type.new
92
109
  WebMock::CallbackRegistry.invoke_callbacks(
93
110
  {lib: :net_http}, request_signature, webmock_response)
94
111
  build_net_http_response(webmock_response, request.uri, &block)
@@ -125,23 +142,22 @@ module WebMock
125
142
  raise IOError, 'HTTP session already opened' if @started
126
143
  if block_given?
127
144
  begin
128
- @socket = Net::HTTP.socket_type.new
145
+ @socket = self.class.socket_type.new
129
146
  @started = true
130
147
  return yield(self)
131
148
  ensure
132
149
  do_finish
133
150
  end
134
151
  end
135
- @socket = Net::HTTP.socket_type.new
152
+ @socket = self.class.socket_type.new
136
153
  @started = true
137
154
  self
138
155
  end
139
156
 
140
-
141
157
  def ensure_actual_connection
142
158
  if @socket.is_a?(StubSocket)
143
- @socket&.close
144
- @socket = nil
159
+ # Keep the closed stub socket, so a failed connect is retried.
160
+ @socket.close
145
161
  do_start
146
162
  end
147
163
  end
@@ -149,6 +165,8 @@ module WebMock
149
165
  alias_method :start_with_connect, :start
150
166
 
151
167
  def start(&block)
168
+ return super unless webmock_enabled?
169
+
152
170
  uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
153
171
 
154
172
  if WebMock.net_http_connect_on_start?(uri)
@@ -205,6 +223,12 @@ module WebMock
205
223
  @@already_checked_for_right_http_connection = true
206
224
  end
207
225
  end
226
+
227
+ private
228
+
229
+ def webmock_enabled?
230
+ WebMock::HttpLibAdapters::NetHttpAdapter.enabled?
231
+ end
208
232
  end
209
233
  @webMockNetHTTP.version_1_2
210
234
  [
@@ -94,8 +94,11 @@ module WebMock
94
94
 
95
95
 
96
96
  class MethodPattern
97
+ # Request signatures store the method as a lower case Symbol, so a method
98
+ # given as a String or in upper case, like "get" or :GET, matches too.
99
+ # Anything else, such as nil, is kept as given and never matches.
97
100
  def initialize(pattern)
98
- @pattern = pattern
101
+ @pattern = pattern.respond_to?(:to_sym) ? pattern.to_sym.downcase : pattern
99
102
  end
100
103
 
101
104
  def matches?(method)
@@ -4,11 +4,11 @@ module WebMock
4
4
 
5
5
  class RequestSignature
6
6
 
7
- attr_accessor :method, :uri, :body
8
- attr_reader :headers
7
+ attr_accessor :uri, :body
8
+ attr_reader :method, :headers
9
9
 
10
10
  def initialize(method, uri, options = {})
11
- self.method = method.to_sym
11
+ self.method = method
12
12
  self.uri = uri.is_a?(Addressable::URI) ? uri : WebMock::Util::URI.normalize_uri(uri)
13
13
  assign_options(options)
14
14
  end
@@ -23,6 +23,10 @@ module WebMock
23
23
  string
24
24
  end
25
25
 
26
+ def method=(method)
27
+ @method = method.to_sym.downcase
28
+ end
29
+
26
30
  def headers=(headers)
27
31
  @headers = WebMock::Util::Headers.normalize_headers(headers)
28
32
  end
@@ -39,13 +39,10 @@ module WebMock
39
39
  else
40
40
  body.call
41
41
  end
42
- b = b.to_json unless b.is_a?(String)
43
- b
42
+ json_response_body(b)
44
43
  }
45
- elsif !body.is_a?(String)
46
- body.to_json
47
44
  else
48
- body
45
+ json_response_body(body)
49
46
  end
50
47
 
51
48
  resp_h.merge(
@@ -130,5 +127,16 @@ module WebMock
130
127
  end
131
128
  stub
132
129
  end
130
+
131
+ private
132
+
133
+ def json_response_body(body)
134
+ case body
135
+ when String, IO, Pathname
136
+ body
137
+ else
138
+ body.to_json
139
+ end
140
+ end
133
141
  end
134
142
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebMock
4
- VERSION = '3.30.0' unless defined?(::WebMock::VERSION)
4
+ VERSION = '3.32.0' unless defined?(::WebMock::VERSION)
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webmock
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.30.0
4
+ version: 3.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bartosz Blimke
@@ -360,9 +360,9 @@ licenses:
360
360
  - MIT
361
361
  metadata:
362
362
  bug_tracker_uri: https://github.com/bblimke/webmock/issues
363
- changelog_uri: https://github.com/bblimke/webmock/blob/v3.30.0/CHANGELOG.md
364
- documentation_uri: https://www.rubydoc.info/gems/webmock/3.30.0
365
- source_code_uri: https://github.com/bblimke/webmock/tree/v3.30.0
363
+ changelog_uri: https://github.com/bblimke/webmock/blob/v3.32.0/CHANGELOG.md
364
+ documentation_uri: https://www.rubydoc.info/gems/webmock/3.32.0
365
+ source_code_uri: https://github.com/bblimke/webmock/tree/v3.32.0
366
366
  wiki_uri: https://github.com/bblimke/webmock/wiki
367
367
  rdoc_options: []
368
368
  require_paths: