webmock 3.6.0 → 3.7.3

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.
@@ -118,7 +118,7 @@ if defined?(::Patron)
118
118
  def self.build_webmock_response(patron_response)
119
119
  webmock_response = WebMock::Response.new
120
120
  reason = patron_response.status_line.
121
- 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]
122
122
  webmock_response.status = [patron_response.status, reason]
123
123
  webmock_response.body = patron_response.body
124
124
  webmock_response.headers = patron_response.headers
@@ -183,8 +183,7 @@ module WebMock
183
183
  def matches_with_variations?(uri)
184
184
  normalized_template = Addressable::Template.new(WebMock::Util::URI.heuristic_parse(@pattern.pattern))
185
185
 
186
- WebMock::Util::URI.variations_of_uri_as_strings(uri, only_with_scheme: true)
187
- .any? { |u| normalized_template.match(u) }
186
+ WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u| normalized_template.match(u) }
188
187
  end
189
188
  end
190
189
 
@@ -41,12 +41,12 @@ module WebMock
41
41
  uris = uris_with_trailing_slash_and_without(uris)
42
42
  end
43
43
 
44
- uris = uris_encoded_and_unencoded(uris)
45
-
46
44
  if normalized_uri.port == Addressable::URI.port_mapping[normalized_uri.scheme]
47
45
  uris = uris_with_inferred_port_and_without(uris)
48
46
  end
49
47
 
48
+ uris = uris_encoded_and_unencoded(uris)
49
+
50
50
  if normalized_uri.scheme == "http" && !only_with_scheme
51
51
  uris = uris_with_scheme_and_without(uris)
52
52
  end
@@ -80,27 +80,27 @@ module WebMock
80
80
 
81
81
  def self.uris_with_inferred_port_and_without(uris)
82
82
  uris.map { |uri|
83
- uri = uri.dup.force_encoding(Encoding::ASCII_8BIT) if uri.respond_to?(:force_encoding)
84
- [ uri, uri.gsub(%r{(:80)|(:443)}, "").freeze ]
83
+ [ uri, uri.omit(:port)]
85
84
  }.flatten
86
85
  end
87
86
 
88
87
  def self.uris_encoded_and_unencoded(uris)
89
88
  uris.map do |uri|
90
- [ uri.to_s, Addressable::URI.unencode(uri, String).freeze ]
89
+ [
90
+ uri.to_s.force_encoding(Encoding::ASCII_8BIT),
91
+ Addressable::URI.unencode(uri, String).force_encoding(Encoding::ASCII_8BIT).freeze
92
+ ]
91
93
  end.flatten
92
94
  end
93
95
 
94
96
  def self.uris_with_scheme_and_without(uris)
95
97
  uris.map { |uri|
96
- uri = uri.dup.force_encoding(Encoding::ASCII_8BIT) if uri.respond_to?(:force_encoding)
97
98
  [ uri, uri.gsub(%r{^https?://},"").freeze ]
98
99
  }.flatten
99
100
  end
100
101
 
101
102
  def self.uris_with_trailing_slash_and_without(uris)
102
- uris = uris.map { |uri|
103
- uri = uri.dup.force_encoding(Encoding::ASCII_8BIT) if uri.respond_to?(:force_encoding)
103
+ uris.map { |uri|
104
104
  [ uri, uri.omit(:path).freeze ]
105
105
  }.flatten
106
106
  end
@@ -1,3 +1,3 @@
1
1
  module WebMock
2
- VERSION = '3.6.0' unless defined?(::WebMock::VERSION)
2
+ VERSION = '3.7.3' unless defined?(::WebMock::VERSION)
3
3
  end
@@ -0,0 +1,349 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'acceptance/webmock_shared'
4
+ require_relative './async_http_client_spec_helper'
5
+
6
+ require 'protocol/http/body/file'
7
+
8
+ Async.logger.debug! if ENV['ASYNC_LOGGER_DEBUG']
9
+
10
+ unless RUBY_PLATFORM =~ /java/
11
+ describe 'Async::HTTP::Client' do
12
+ include AsyncHttpClientSpecHelper
13
+
14
+ include_context "with WebMock",
15
+ :no_status_message,
16
+ :no_url_auth,
17
+ :no_content_length_header
18
+
19
+ it 'works' do
20
+ stub_request(:get, 'http://www.example.com')
21
+ expect(make_request(:get, 'http://www.example.com')).to eq(
22
+ status: 200,
23
+ headers: {},
24
+ body: nil
25
+ )
26
+ end
27
+
28
+ it 'works with request path' do
29
+ stub_request(:get, 'http://www.example.com/foo')
30
+ expect(make_request(:get, 'http://www.example.com/foo')).to eq(
31
+ status: 200,
32
+ headers: {},
33
+ body: nil
34
+ )
35
+ end
36
+
37
+ it 'works with request query' do
38
+ stub_request(:get, 'http://www.example.com/').with(
39
+ query: {
40
+ 'foo' => 'bar'
41
+ }
42
+ )
43
+ expect(make_request(:get, 'http://www.example.com/?foo=bar')).to eq(
44
+ status: 200,
45
+ headers: {},
46
+ body: nil
47
+ )
48
+ end
49
+
50
+ it 'works with request headers' do
51
+ stub_request(:get, 'http://www.example.com').with(
52
+ headers: {
53
+ 'X-Token' => 'Token'
54
+ }
55
+ )
56
+ expect(
57
+ make_request :get, 'http://www.example.com',
58
+ headers: {
59
+ 'X-Token' => 'Token'
60
+ }
61
+ ).to eq(
62
+ status: 200,
63
+ headers: {},
64
+ body: nil
65
+ )
66
+ end
67
+
68
+ it 'works with request body as text' do
69
+ stub_request(:post, 'http://www.example.com').with(
70
+ body: 'x'*10_000
71
+ )
72
+ expect(
73
+ make_request :post, 'http://www.example.com',
74
+ body: 'x'*10_000
75
+ ).to eq(
76
+ status: 200,
77
+ headers: {},
78
+ body: nil
79
+ )
80
+ end
81
+
82
+ it 'works with request body as file' do
83
+ stub_request(:post, "www.example.com").with(
84
+ body: File.read(__FILE__)
85
+ )
86
+ expect(
87
+ make_request :post, "http://www.example.com",
88
+ body: ::Protocol::HTTP::Body::File.open(__FILE__, block_size: 32)
89
+ ).to eq(
90
+ status: 200,
91
+ headers: {},
92
+ body: nil
93
+ )
94
+ end
95
+
96
+ it 'works with response status' do
97
+ stub_request(:get, 'http://www.example.com').to_return(
98
+ status: 400
99
+ )
100
+ expect(make_request(:get, 'http://www.example.com')).to eq(
101
+ status: 400,
102
+ headers: {},
103
+ body: nil
104
+ )
105
+ end
106
+
107
+ it 'works with response headers' do
108
+ stub_request(:get, 'http://www.example.com').to_return(
109
+ headers: {
110
+ 'X-Token' => 'TOKEN'
111
+ }
112
+ )
113
+ expect(make_request(:get, 'http://www.example.com')).to eq(
114
+ status: 200,
115
+ headers: {
116
+ 'x-token' => ['TOKEN']
117
+ },
118
+ body: nil
119
+ )
120
+ end
121
+
122
+ it 'works with response body' do
123
+ stub_request(:get, 'http://www.example.com').to_return(
124
+ body: 'abc'
125
+ )
126
+ expect(make_request(:get, 'http://www.example.com')).to eq(
127
+ status: 200,
128
+ headers: {},
129
+ body: 'abc'
130
+ )
131
+ end
132
+
133
+ it 'works with to_timeout' do
134
+ stub_request(:get, 'http://www.example.com').to_timeout
135
+ expect { make_request(:get, 'http://www.example.com') }.to raise_error Async::TimeoutError
136
+ end
137
+
138
+ context 'scheme and protocol' do
139
+ before do
140
+ stub_request(
141
+ :get, "#{scheme}://www.example.com"
142
+ ).and_return(
143
+ body: 'BODY'
144
+ )
145
+ end
146
+
147
+ subject do
148
+ make_request(:get, "#{scheme}://www.example.com", protocol: protocol)
149
+ end
150
+
151
+ shared_examples :common do
152
+ specify do
153
+ expect(subject).to eq(
154
+ status: 200,
155
+ headers: {},
156
+ body: 'BODY'
157
+ )
158
+ end
159
+ end
160
+
161
+ context 'http scheme' do
162
+ let(:scheme) { 'http' }
163
+
164
+ context 'default protocol' do
165
+ let(:protocol) { nil }
166
+
167
+ include_examples :common
168
+ end
169
+
170
+ context 'HTTP10 protocol' do
171
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
172
+
173
+ include_examples :common
174
+ end
175
+
176
+ context 'HTTP11 protocol' do
177
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
178
+
179
+ include_examples :common
180
+ end
181
+
182
+ context 'HTTP2 protocol' do
183
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
184
+
185
+ include_examples :common
186
+ end
187
+ end
188
+
189
+ context 'https scheme' do
190
+ let(:scheme) { 'https' }
191
+
192
+ context 'default protocol' do
193
+ let(:protocol) { nil }
194
+
195
+ include_examples :common
196
+ end
197
+
198
+ context 'HTTP10 protocol' do
199
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
200
+
201
+ include_examples :common
202
+ end
203
+
204
+ context 'HTTP11 protocol' do
205
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
206
+
207
+ include_examples :common
208
+ end
209
+
210
+ context 'HTTP2 protocol' do
211
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
212
+
213
+ include_examples :common
214
+ end
215
+
216
+ context 'HTTPS protocol' do
217
+ let(:protocol) { Async::HTTP::Protocol::HTTPS }
218
+
219
+ include_examples :common
220
+ end
221
+ end
222
+ end
223
+
224
+ context 'multiple requests' do
225
+ let(:endpoint) { Async::HTTP::Endpoint.parse('http://www.example.com') }
226
+ let(:requests_count) { 3 }
227
+
228
+ shared_examples :common do
229
+ before do
230
+ requests_count.times do |index|
231
+ stub_request(
232
+ :get, "http://www.example.com/foo#{index}"
233
+ ).to_return(
234
+ status: 200 + index,
235
+ headers: {'X-Token' => "foo#{index}"},
236
+ body: "FOO#{index}"
237
+ )
238
+ end
239
+ end
240
+
241
+ specify do
242
+ expect(subject).to eq(
243
+ 0 => {
244
+ status: 200,
245
+ headers: {'x-token' => ['foo0']},
246
+ body: 'FOO0'
247
+ },
248
+ 1 => {
249
+ status: 201,
250
+ headers: {'x-token' => ['foo1']},
251
+ body: 'FOO1'
252
+ },
253
+ 2 => {
254
+ status: 202,
255
+ headers: {'x-token' => ['foo2']},
256
+ body: 'FOO2'
257
+ }
258
+ )
259
+ end
260
+ end
261
+
262
+ context 'sequential' do
263
+ subject do
264
+ responses = {}
265
+ Async do |task|
266
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
267
+ requests_count.times do |index|
268
+ response = client.get "/foo#{index}"
269
+ responses[index] = response_to_hash(response)
270
+ end
271
+ end
272
+ end
273
+ responses
274
+ end
275
+
276
+ context 'HTTP1 protocol' do
277
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
278
+
279
+ include_examples :common
280
+ end
281
+
282
+ context 'HTTP2 protocol' do
283
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
284
+
285
+ include_examples :common
286
+ end
287
+ end
288
+
289
+ context 'asynchronous' do
290
+ subject do
291
+ responses = {}
292
+ Async do |task|
293
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
294
+ tasks = requests_count.times.map do |index|
295
+ task.async do
296
+ response = client.get "/foo#{index}"
297
+ responses[index] = response_to_hash(response)
298
+ end
299
+ end
300
+
301
+ tasks.map(&:wait)
302
+ end
303
+ end
304
+ responses
305
+ end
306
+
307
+ context 'HTTP1 protocol' do
308
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
309
+
310
+ include_examples :common
311
+ end
312
+
313
+ context 'HTTP2 protocol' do
314
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
315
+
316
+ include_examples :common
317
+ end
318
+ end
319
+ end
320
+
321
+ def make_request(method, url, protocol: nil, headers: {}, body: nil)
322
+ Async do
323
+ endpoint = Async::HTTP::Endpoint.parse(url)
324
+
325
+ begin
326
+ Async::HTTP::Client.open(endpoint, protocol || endpoint.protocol) do |client|
327
+ response = client.send(
328
+ method,
329
+ endpoint.path,
330
+ headers,
331
+ body
332
+ )
333
+ response_to_hash(response)
334
+ end
335
+ rescue Async::TimeoutError => e
336
+ e
337
+ end
338
+ end.wait
339
+ end
340
+
341
+ def response_to_hash(response)
342
+ {
343
+ status: response.status,
344
+ headers: response.headers.to_h,
345
+ body: response.read
346
+ }
347
+ end
348
+ end
349
+ end
@@ -0,0 +1,73 @@
1
+ module AsyncHttpClientSpecHelper
2
+ def http_request(method, url, options = {}, &block)
3
+ endpoint = Async::HTTP::Endpoint.parse(url)
4
+
5
+ path = endpoint.path
6
+ path = path + "?" + options[:query] if options[:query]
7
+
8
+ headers = (options[:headers] || {}).each_with_object([]) do |(k, v), o|
9
+ Array(v).each do |v|
10
+ o.push [k, v]
11
+ end
12
+ end
13
+ headers.push(
14
+ ['authorization', 'Basic ' + Base64.strict_encode64(options[:basic_auth].join(':'))]
15
+ ) if options[:basic_auth]
16
+
17
+ body = options[:body]
18
+
19
+ Async do
20
+ begin
21
+ Async::HTTP::Client.open(endpoint) do |client|
22
+ response = client.send(
23
+ method,
24
+ path,
25
+ headers,
26
+ body
27
+ )
28
+
29
+ OpenStruct.new(
30
+ build_hash_response(response)
31
+ )
32
+ end
33
+ rescue Exception => e
34
+ e
35
+ end
36
+ end.wait
37
+ end
38
+
39
+ def client_timeout_exception_class
40
+ Async::TimeoutError
41
+ end
42
+
43
+ def connection_refused_exception_class
44
+ Errno::ECONNREFUSED
45
+ end
46
+
47
+ def http_library
48
+ :async_http_client
49
+ end
50
+
51
+ private
52
+
53
+ def build_hash_response(response)
54
+ {
55
+
56
+ status: response.status.to_s,
57
+ message: Protocol::HTTP1::Reason::DESCRIPTIONS[response.status],
58
+ headers: build_response_headers(response),
59
+ body: response.read
60
+ }
61
+ end
62
+
63
+ def build_response_headers(response)
64
+ response.headers.each.each_with_object({}) do |(k, v), o|
65
+ o[k] ||= []
66
+ o[k] << v
67
+ end.tap do |o|
68
+ o.each do |k, v|
69
+ o[k] = v.join(', ')
70
+ end
71
+ end
72
+ end
73
+ end