webmock 3.5.1 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +15 -12
  3. data/CHANGELOG.md +211 -0
  4. data/README.md +92 -26
  5. data/Rakefile +0 -2
  6. data/lib/webmock.rb +1 -0
  7. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +214 -0
  8. data/lib/webmock/http_lib_adapters/curb_adapter.rb +10 -1
  9. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +1 -1
  10. data/lib/webmock/http_lib_adapters/excon_adapter.rb +3 -0
  11. data/lib/webmock/http_lib_adapters/http_rb/client.rb +4 -1
  12. data/lib/webmock/http_lib_adapters/http_rb/response.rb +11 -1
  13. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +2 -2
  14. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +23 -6
  15. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +25 -14
  16. data/lib/webmock/http_lib_adapters/net_http.rb +35 -17
  17. data/lib/webmock/http_lib_adapters/patron_adapter.rb +1 -1
  18. data/lib/webmock/request_body_diff.rb +1 -1
  19. data/lib/webmock/request_pattern.rb +76 -48
  20. data/lib/webmock/response.rb +11 -5
  21. data/lib/webmock/rspec.rb +2 -1
  22. data/lib/webmock/stub_registry.rb +26 -11
  23. data/lib/webmock/test_unit.rb +1 -3
  24. data/lib/webmock/util/query_mapper.rb +4 -2
  25. data/lib/webmock/util/uri.rb +8 -8
  26. data/lib/webmock/version.rb +1 -1
  27. data/lib/webmock/webmock.rb +10 -3
  28. data/spec/acceptance/async_http_client/async_http_client_spec.rb +353 -0
  29. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  30. data/spec/acceptance/curb/curb_spec.rb +23 -5
  31. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +1 -1
  32. data/spec/acceptance/excon/excon_spec_helper.rb +2 -0
  33. data/spec/acceptance/http_rb/http_rb_spec.rb +11 -0
  34. data/spec/acceptance/manticore/manticore_spec.rb +19 -0
  35. data/spec/acceptance/net_http/net_http_spec.rb +12 -0
  36. data/spec/acceptance/shared/callbacks.rb +2 -1
  37. data/spec/acceptance/shared/request_expectations.rb +7 -0
  38. data/spec/acceptance/shared/returning_declared_responses.rb +36 -15
  39. data/spec/acceptance/shared/stubbing_requests.rb +40 -0
  40. data/spec/support/webmock_server.rb +1 -0
  41. data/spec/unit/request_pattern_spec.rb +119 -3
  42. data/spec/unit/response_spec.rb +22 -18
  43. data/spec/unit/util/query_mapper_spec.rb +7 -0
  44. data/spec/unit/util/uri_spec.rb +74 -2
  45. data/spec/unit/webmock_spec.rb +54 -5
  46. data/test/test_webmock.rb +6 -0
  47. data/webmock.gemspec +9 -2
  48. metadata +39 -10
@@ -1,3 +1,3 @@
1
1
  module WebMock
2
- VERSION = '3.5.1' unless defined?(::WebMock::VERSION)
2
+ VERSION = '3.11.0' unless defined?(::WebMock::VERSION)
3
3
  end
@@ -53,12 +53,19 @@ module WebMock
53
53
  Config.instance.net_http_connect_on_start = options[:net_http_connect_on_start]
54
54
  end
55
55
 
56
+ class << self
57
+ alias :enable_net_connect! :allow_net_connect!
58
+ alias :disallow_net_connect! :disable_net_connect!
59
+ end
60
+
56
61
  def self.net_connect_allowed?(uri = nil)
62
+ return !!Config.instance.allow_net_connect if uri.nil?
63
+
57
64
  if uri.is_a?(String)
58
65
  uri = WebMock::Util::URI.normalize_uri(uri)
59
66
  end
60
67
 
61
- Config.instance.allow_net_connect ||
68
+ !!Config.instance.allow_net_connect ||
62
69
  ( Config.instance.allow_localhost && WebMock::Util::URI.is_uri_localhost?(uri) ||
63
70
  Config.instance.allow && net_connect_explicit_allowed?(Config.instance.allow, uri) )
64
71
  end
@@ -133,8 +140,8 @@ module WebMock
133
140
  puts WebMock::RequestExecutionVerifier.executed_requests_message
134
141
  end
135
142
 
136
- def self.globally_stub_request(&block)
137
- WebMock::StubRegistry.instance.register_global_stub(&block)
143
+ def self.globally_stub_request(order = :before_local_stubs, &block)
144
+ WebMock::StubRegistry.instance.register_global_stub(order, &block)
138
145
  end
139
146
 
140
147
  %w(
@@ -0,0 +1,353 @@
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
+ let(:default_response_headers) { {} }
140
+
141
+ before do
142
+ stub_request(
143
+ :get, "#{scheme}://www.example.com"
144
+ ).and_return(
145
+ body: 'BODY'
146
+ )
147
+ end
148
+
149
+ subject do
150
+ make_request(:get, "#{scheme}://www.example.com", protocol: protocol)
151
+ end
152
+
153
+ shared_examples :common do
154
+ specify do
155
+ expect(subject).to eq(
156
+ status: 200,
157
+ headers: default_response_headers,
158
+ body: 'BODY'
159
+ )
160
+ end
161
+ end
162
+
163
+ context 'http scheme' do
164
+ let(:scheme) { 'http' }
165
+
166
+ context 'default protocol' do
167
+ let(:protocol) { nil }
168
+
169
+ include_examples :common
170
+ end
171
+
172
+ context 'HTTP10 protocol' do
173
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
174
+ let(:default_response_headers) { {"connection"=>["keep-alive"]} }
175
+
176
+ include_examples :common
177
+ end
178
+
179
+ context 'HTTP11 protocol' do
180
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
181
+
182
+ include_examples :common
183
+ end
184
+
185
+ context 'HTTP2 protocol' do
186
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
187
+
188
+ include_examples :common
189
+ end
190
+ end
191
+
192
+ context 'https scheme' do
193
+ let(:scheme) { 'https' }
194
+
195
+ context 'default protocol' do
196
+ let(:protocol) { nil }
197
+
198
+ include_examples :common
199
+ end
200
+
201
+ context 'HTTP10 protocol' do
202
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
203
+ let(:default_response_headers) { {"connection"=>["keep-alive"]} }
204
+
205
+ include_examples :common
206
+ end
207
+
208
+ context 'HTTP11 protocol' do
209
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
210
+
211
+ include_examples :common
212
+ end
213
+
214
+ context 'HTTP2 protocol' do
215
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
216
+
217
+ include_examples :common
218
+ end
219
+
220
+ context 'HTTPS protocol' do
221
+ let(:protocol) { Async::HTTP::Protocol::HTTPS }
222
+
223
+ include_examples :common
224
+ end
225
+ end
226
+ end
227
+
228
+ context 'multiple requests' do
229
+ let(:endpoint) { Async::HTTP::Endpoint.parse('http://www.example.com') }
230
+ let(:requests_count) { 3 }
231
+
232
+ shared_examples :common do
233
+ before do
234
+ requests_count.times do |index|
235
+ stub_request(
236
+ :get, "http://www.example.com/foo#{index}"
237
+ ).to_return(
238
+ status: 200 + index,
239
+ headers: {'X-Token' => "foo#{index}"},
240
+ body: "FOO#{index}"
241
+ )
242
+ end
243
+ end
244
+
245
+ specify do
246
+ expect(subject).to eq(
247
+ 0 => {
248
+ status: 200,
249
+ headers: {'x-token' => ['foo0']},
250
+ body: 'FOO0'
251
+ },
252
+ 1 => {
253
+ status: 201,
254
+ headers: {'x-token' => ['foo1']},
255
+ body: 'FOO1'
256
+ },
257
+ 2 => {
258
+ status: 202,
259
+ headers: {'x-token' => ['foo2']},
260
+ body: 'FOO2'
261
+ }
262
+ )
263
+ end
264
+ end
265
+
266
+ context 'sequential' do
267
+ subject do
268
+ responses = {}
269
+ Async do |task|
270
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
271
+ requests_count.times do |index|
272
+ response = client.get "/foo#{index}"
273
+ responses[index] = response_to_hash(response)
274
+ end
275
+ end
276
+ end
277
+ responses
278
+ end
279
+
280
+ context 'HTTP1 protocol' do
281
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
282
+
283
+ include_examples :common
284
+ end
285
+
286
+ context 'HTTP2 protocol' do
287
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
288
+
289
+ include_examples :common
290
+ end
291
+ end
292
+
293
+ context 'asynchronous' do
294
+ subject do
295
+ responses = {}
296
+ Async do |task|
297
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
298
+ tasks = requests_count.times.map do |index|
299
+ task.async do
300
+ response = client.get "/foo#{index}"
301
+ responses[index] = response_to_hash(response)
302
+ end
303
+ end
304
+
305
+ tasks.map(&:wait)
306
+ end
307
+ end
308
+ responses
309
+ end
310
+
311
+ context 'HTTP1 protocol' do
312
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
313
+
314
+ include_examples :common
315
+ end
316
+
317
+ context 'HTTP2 protocol' do
318
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
319
+
320
+ include_examples :common
321
+ end
322
+ end
323
+ end
324
+
325
+ def make_request(method, url, protocol: nil, headers: {}, body: nil)
326
+ Async do
327
+ endpoint = Async::HTTP::Endpoint.parse(url)
328
+
329
+ begin
330
+ Async::HTTP::Client.open(endpoint, protocol || endpoint.protocol) do |client|
331
+ response = client.send(
332
+ method,
333
+ endpoint.path,
334
+ headers,
335
+ body
336
+ )
337
+ response_to_hash(response)
338
+ end
339
+ rescue Async::TimeoutError => e
340
+ e
341
+ end
342
+ end.wait
343
+ end
344
+
345
+ def response_to_hash(response)
346
+ {
347
+ status: response.status,
348
+ headers: response.headers.to_h,
349
+ body: response.read
350
+ }
351
+ end
352
+ end
353
+ 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