webmock 1.8.6 → 3.14.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 +7 -0
- data/.github/workflows/CI.yml +37 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +1198 -0
- data/Gemfile +3 -15
- data/README.md +761 -305
- data/Rakefile +13 -40
- data/lib/webmock/api.rb +63 -17
- data/lib/webmock/callback_registry.rb +1 -1
- data/lib/webmock/config.rb +8 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/errors.rb +8 -24
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
- data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
- data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
- data/lib/webmock/minitest.rb +29 -3
- data/lib/webmock/rack_response.rb +14 -7
- data/lib/webmock/request_body_diff.rb +64 -0
- data/lib/webmock/request_execution_verifier.rb +38 -17
- data/lib/webmock/request_pattern.rb +158 -38
- data/lib/webmock/request_registry.rb +3 -3
- data/lib/webmock/request_signature.rb +7 -3
- data/lib/webmock/request_signature_snippet.rb +61 -0
- data/lib/webmock/request_stub.rb +9 -6
- data/lib/webmock/response.rb +30 -15
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
- data/lib/webmock/rspec/matchers.rb +0 -1
- data/lib/webmock/rspec.rb +11 -2
- data/lib/webmock/stub_registry.rb +31 -10
- data/lib/webmock/stub_request_snippet.rb +14 -6
- data/lib/webmock/test_unit.rb +4 -4
- data/lib/webmock/util/hash_counter.rb +20 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
- data/lib/webmock/util/hash_validator.rb +17 -0
- data/lib/webmock/util/headers.rb +23 -2
- data/lib/webmock/util/json.rb +20 -7
- data/lib/webmock/util/query_mapper.rb +281 -0
- data/lib/webmock/util/uri.rb +29 -19
- data/lib/webmock/util/values_stringifier.rb +20 -0
- data/lib/webmock/util/version_checker.rb +40 -2
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +56 -17
- data/lib/webmock.rb +56 -46
- data/minitest/test_helper.rb +8 -3
- data/minitest/test_webmock.rb +4 -1
- data/minitest/webmock_spec.rb +16 -6
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
- data/spec/acceptance/curb/curb_spec.rb +227 -68
- data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
- data/spec/acceptance/excon/excon_spec.rb +66 -4
- data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
- data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
- data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
- data/spec/acceptance/manticore/manticore_spec.rb +107 -0
- data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
- data/spec/acceptance/net_http/net_http_shared.rb +52 -24
- data/spec/acceptance/net_http/net_http_spec.rb +164 -50
- data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
- data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
- data/spec/acceptance/patron/patron_spec.rb +29 -40
- data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
- data/spec/acceptance/shared/callbacks.rb +32 -30
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
- data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
- data/spec/acceptance/shared/request_expectations.rb +560 -296
- data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
- data/spec/acceptance/shared/stubbing_requests.rb +385 -154
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
- data/spec/acceptance/webmock_shared.rb +2 -2
- data/spec/fixtures/test.txt +1 -0
- data/spec/quality_spec.rb +27 -3
- data/spec/spec_helper.rb +11 -20
- data/spec/support/failures.rb +9 -0
- data/spec/support/my_rack_app.rb +8 -3
- data/spec/support/network_connection.rb +7 -13
- data/spec/support/webmock_server.rb +8 -3
- data/spec/unit/api_spec.rb +175 -0
- data/spec/unit/errors_spec.rb +116 -19
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
- data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
- data/spec/unit/rack_response_spec.rb +54 -16
- data/spec/unit/request_body_diff_spec.rb +90 -0
- data/spec/unit/request_execution_verifier_spec.rb +147 -39
- data/spec/unit/request_pattern_spec.rb +462 -198
- data/spec/unit/request_registry_spec.rb +29 -9
- data/spec/unit/request_signature_snippet_spec.rb +89 -0
- data/spec/unit/request_signature_spec.rb +91 -49
- data/spec/unit/request_stub_spec.rb +71 -70
- data/spec/unit/response_spec.rb +100 -81
- data/spec/unit/stub_registry_spec.rb +37 -20
- data/spec/unit/stub_request_snippet_spec.rb +51 -31
- data/spec/unit/util/hash_counter_spec.rb +6 -6
- data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
- data/spec/unit/util/headers_spec.rb +4 -4
- data/spec/unit/util/json_spec.rb +29 -3
- data/spec/unit/util/query_mapper_spec.rb +157 -0
- data/spec/unit/util/uri_spec.rb +150 -36
- data/spec/unit/util/version_checker_spec.rb +15 -9
- data/spec/unit/webmock_spec.rb +57 -4
- data/test/http_request.rb +3 -3
- data/test/shared_test.rb +45 -13
- data/test/test_helper.rb +1 -1
- data/test/test_webmock.rb +6 -0
- data/webmock.gemspec +30 -11
- metadata +308 -199
- data/.rvmrc +0 -1
- data/.travis.yml +0 -11
- data/Guardfile +0 -24
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +0 -210
@@ -13,10 +13,43 @@ unless RUBY_PLATFORM =~ /java/
|
|
13
13
|
|
14
14
|
#functionality only supported for em-http-request 1.x
|
15
15
|
if defined?(EventMachine::HttpConnection)
|
16
|
+
context 'when a real request is made and redirects are followed', net_connect: true do
|
17
|
+
before { WebMock.allow_net_connect! }
|
18
|
+
|
19
|
+
# This url redirects to the https URL.
|
20
|
+
let(:http_url) { "http://raw.github.com:80/gist/fb555cb593f3349d53af/6921dd638337d3f6a51b0e02e7f30e3c414f70d6/vcr_gist" }
|
21
|
+
let(:https_url) { http_url.gsub('http', 'https').gsub('80', '443') }
|
22
|
+
|
23
|
+
def make_request
|
24
|
+
EM.run do
|
25
|
+
request = EM::HttpRequest.new(http_url).get(redirects: 1)
|
26
|
+
request.callback { EM.stop }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "invokes the globally_stub_request hook with both requests" do
|
31
|
+
urls = []
|
32
|
+
WebMock.globally_stub_request { |r| urls << r.uri.to_s; nil }
|
33
|
+
|
34
|
+
make_request
|
35
|
+
|
36
|
+
expect(urls).to eq([http_url, https_url])
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'invokes the after_request hook with both requests' do
|
40
|
+
urls = []
|
41
|
+
WebMock.after_request { |req, res| urls << req.uri.to_s }
|
42
|
+
|
43
|
+
make_request
|
44
|
+
|
45
|
+
expect(urls).to eq([http_url, https_url])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
16
49
|
describe "with middleware" do
|
17
50
|
|
18
51
|
it "should work with request middleware" do
|
19
|
-
stub_request(:get, "www.example.com").with(:
|
52
|
+
stub_request(:get, "www.example.com").with(body: 'bar')
|
20
53
|
|
21
54
|
middleware = Class.new do
|
22
55
|
def request(client, head, body)
|
@@ -29,37 +62,142 @@ unless RUBY_PLATFORM =~ /java/
|
|
29
62
|
|
30
63
|
conn.use middleware
|
31
64
|
|
32
|
-
http = conn.get(:
|
65
|
+
http = conn.get(body: 'foo')
|
33
66
|
|
34
67
|
http.callback do
|
35
|
-
WebMock.
|
68
|
+
expect(WebMock).to have_requested(:get, "www.example.com").with(body: 'bar')
|
36
69
|
EM.stop
|
37
70
|
end
|
38
71
|
end
|
39
72
|
end
|
40
73
|
|
41
|
-
it "
|
42
|
-
stub_request(:get, "www.example.com")
|
74
|
+
it "only calls request middleware once" do
|
75
|
+
stub_request(:get, "www.example.com")
|
43
76
|
|
44
77
|
middleware = Class.new do
|
78
|
+
def self.called!
|
79
|
+
@called = called + 1
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.called
|
83
|
+
@called || 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def request(client, head, body)
|
87
|
+
self.class.called!
|
88
|
+
[head, body]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
EM.run do
|
93
|
+
conn = EventMachine::HttpRequest.new('http://www.example.com/')
|
94
|
+
conn.use middleware
|
95
|
+
http = conn.get
|
96
|
+
http.callback do
|
97
|
+
expect(middleware.called).to eq(1)
|
98
|
+
EM.stop
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
let(:response_middleware) do
|
104
|
+
Class.new do
|
45
105
|
def response(resp)
|
46
106
|
resp.response = 'bar'
|
47
107
|
end
|
48
108
|
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should work with response middleware" do
|
112
|
+
stub_request(:get, "www.example.com").to_return(body: 'foo')
|
49
113
|
|
50
114
|
EM.run do
|
51
115
|
conn = EventMachine::HttpRequest.new('http://www.example.com/')
|
52
116
|
|
53
|
-
conn.use
|
117
|
+
conn.use response_middleware
|
54
118
|
|
55
119
|
http = conn.get
|
56
120
|
|
57
121
|
http.callback do
|
58
|
-
http.response.
|
122
|
+
expect(http.response).to eq('bar')
|
59
123
|
EM.stop
|
60
124
|
end
|
61
125
|
end
|
62
126
|
end
|
127
|
+
|
128
|
+
let(:webmock_server_url) { "http://#{WebMockServer.instance.host_with_port}/" }
|
129
|
+
|
130
|
+
shared_examples_for "em-http-request middleware/after_request hook integration" do
|
131
|
+
it 'yields the original raw body to the after_request hook even if a response middleware modifies the body' do
|
132
|
+
yielded_response_body = nil
|
133
|
+
::WebMock.after_request do |request, response|
|
134
|
+
yielded_response_body = response.body
|
135
|
+
end
|
136
|
+
|
137
|
+
EM::HttpRequest.use response_middleware
|
138
|
+
|
139
|
+
EM.run do
|
140
|
+
http = EventMachine::HttpRequest.new(webmock_server_url).get
|
141
|
+
http.callback { EM.stop }
|
142
|
+
end
|
143
|
+
|
144
|
+
expect(yielded_response_body).to eq("hello world")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'making a real request', net_connect: true do
|
149
|
+
before { WebMock.allow_net_connect! }
|
150
|
+
include_examples "em-http-request middleware/after_request hook integration"
|
151
|
+
|
152
|
+
it "only calls request middleware once" do
|
153
|
+
middleware = Class.new do
|
154
|
+
def self.called!
|
155
|
+
@called = called + 1
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.called
|
159
|
+
@called || 0
|
160
|
+
end
|
161
|
+
|
162
|
+
def request(client, head, body)
|
163
|
+
self.class.called!
|
164
|
+
[head, body]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
EM.run do
|
169
|
+
conn = EventMachine::HttpRequest.new(webmock_server_url)
|
170
|
+
conn.use middleware
|
171
|
+
http = conn.get
|
172
|
+
http.callback do
|
173
|
+
expect(middleware.called).to eq(1)
|
174
|
+
EM.stop
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the request is stubbed' do
|
181
|
+
before { stub_request(:get, webmock_server_url).to_return(body: 'hello world') }
|
182
|
+
include_examples "em-http-request middleware/after_request hook integration"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should trigger error callbacks asynchronously' do
|
187
|
+
stub_request(:get, 'www.example.com').to_timeout
|
188
|
+
called = false
|
189
|
+
|
190
|
+
EM.run do
|
191
|
+
conn = EventMachine::HttpRequest.new('http://www.example.com/')
|
192
|
+
http = conn.get
|
193
|
+
http.errback do
|
194
|
+
called = true
|
195
|
+
EM.stop
|
196
|
+
end
|
197
|
+
expect(called).to eq(false)
|
198
|
+
end
|
199
|
+
|
200
|
+
expect(called).to eq(true)
|
63
201
|
end
|
64
202
|
|
65
203
|
# not pretty, but it works
|
@@ -78,16 +216,16 @@ unless RUBY_PLATFORM =~ /java/
|
|
78
216
|
end
|
79
217
|
|
80
218
|
it "should work" do
|
81
|
-
stub_request(:post, /.*.testserver.com*/).to_return(:
|
82
|
-
|
219
|
+
stub_request(:post, /.*.testserver.com*/).to_return(status: 200, body: 'ok')
|
220
|
+
expect {
|
83
221
|
EM.run do
|
84
222
|
fiber = Fiber.new do
|
85
|
-
|
223
|
+
EM::HttpRequest.new("http://www.testserver.com").post body: "foo=bar&baz=bang", timeout: 60
|
86
224
|
EM.stop
|
87
225
|
end
|
88
226
|
fiber.resume
|
89
227
|
end
|
90
|
-
}.
|
228
|
+
}.not_to raise_error
|
91
229
|
end
|
92
230
|
|
93
231
|
after(:each) do
|
@@ -105,62 +243,218 @@ unless RUBY_PLATFORM =~ /java/
|
|
105
243
|
end
|
106
244
|
|
107
245
|
it "should work with streaming" do
|
108
|
-
stub_request(:get, "www.example.com").to_return(:
|
246
|
+
stub_request(:get, "www.example.com").to_return(body: "abc")
|
109
247
|
response = ""
|
110
248
|
EM.run {
|
111
249
|
http = EventMachine::HttpRequest.new('http://www.example.com/').get
|
112
250
|
http.stream { |chunk| response = chunk; EM.stop }
|
113
251
|
}
|
114
|
-
response.
|
252
|
+
expect(response).to eq("abc")
|
115
253
|
end
|
116
254
|
|
117
255
|
it "should work with responses that use chunked transfer encoding" do
|
118
|
-
stub_request(:get, "www.example.com").to_return(:
|
119
|
-
http_request(:get, "http://www.example.com").body.
|
256
|
+
stub_request(:get, "www.example.com").to_return(body: "abc", headers: { 'Transfer-Encoding' => 'chunked' })
|
257
|
+
expect(http_request(:get, "http://www.example.com").body).to eq("abc")
|
120
258
|
end
|
121
259
|
|
122
260
|
it "should work with optional query params" do
|
123
|
-
stub_request(:get, "www.example.com/?x=3&a[]=b&a[]=c").to_return(:
|
124
|
-
http_request(:get, "http://www.example.com/?x=3", :
|
261
|
+
stub_request(:get, "www.example.com/?x=3&a[]=b&a[]=c").to_return(body: "abc")
|
262
|
+
expect(http_request(:get, "http://www.example.com/?x=3", query: {"a" => ["b", "c"]}).body).to eq("abc")
|
125
263
|
end
|
126
264
|
|
127
265
|
it "should work with optional query params declared as string" do
|
128
|
-
stub_request(:get, "www.example.com/?x=3&a[]=b&a[]=c").to_return(:
|
129
|
-
http_request(:get, "http://www.example.com/?x=3", :
|
266
|
+
stub_request(:get, "www.example.com/?x=3&a[]=b&a[]=c").to_return(body: "abc")
|
267
|
+
expect(http_request(:get, "http://www.example.com/?x=3", query: "a[]=b&a[]=c").body).to eq("abc")
|
130
268
|
end
|
131
269
|
|
132
270
|
it "should work when the body is passed as a Hash" do
|
133
|
-
stub_request(:post, "www.example.com").with(:
|
134
|
-
http_request(:post, "http://www.example.com", :
|
271
|
+
stub_request(:post, "www.example.com").with(body: {a: "1", b: "2"}).to_return(body: "ok")
|
272
|
+
expect(http_request(:post, "http://www.example.com", body: {a: "1", b: "2"}).body).to eq("ok")
|
273
|
+
end
|
274
|
+
|
275
|
+
if defined?(EventMachine::HttpConnection)
|
276
|
+
it "should work when a file is passed as body" do
|
277
|
+
stub_request(:post, "www.example.com").with(body: File.read(__FILE__)).to_return(body: "ok")
|
278
|
+
expect(http_request(:post, "http://www.example.com", file: __FILE__).body).to eq("ok")
|
279
|
+
end
|
135
280
|
end
|
136
281
|
|
137
282
|
it "should work with UTF-8 strings" do
|
138
283
|
body = "Привет, Мир!"
|
139
|
-
stub_request(:post, "www.example.com").to_return(:
|
140
|
-
http_request(:post, "http://www.example.com").body.bytesize.
|
284
|
+
stub_request(:post, "www.example.com").to_return(body: body)
|
285
|
+
expect(http_request(:post, "http://www.example.com").body.bytesize).to eq(body.bytesize)
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should work with multiple requests to the same connection" do
|
289
|
+
stub_request(:get, "www.example.com/foo").to_return(body: "bar")
|
290
|
+
stub_request(:get, "www.example.com/baz").to_return(body: "wombat")
|
291
|
+
err1 = nil
|
292
|
+
err2 = nil
|
293
|
+
body1 = nil
|
294
|
+
body2 = nil
|
295
|
+
i = 0
|
296
|
+
|
297
|
+
EM.run do
|
298
|
+
conn = EM::HttpRequest.new("http://www.example.com")
|
299
|
+
conn.get(path: "/foo").callback do |resp|
|
300
|
+
body1 = resp.response
|
301
|
+
i += 1; EM.stop if i == 2
|
302
|
+
end.errback do |resp|
|
303
|
+
err1 = resp.error
|
304
|
+
i += 1; EM.stop if i == 2
|
305
|
+
end
|
306
|
+
|
307
|
+
conn.get(path: "/baz").callback do |resp|
|
308
|
+
body2 = resp.response
|
309
|
+
i += 1; EM.stop if i == 2
|
310
|
+
end.errback do |resp|
|
311
|
+
err2 = resp.error
|
312
|
+
i += 1; EM.stop if i == 2
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
expect(err1).to be(nil)
|
317
|
+
expect(err2).to be(nil)
|
318
|
+
expect(body1).to eq("bar")
|
319
|
+
expect(body2).to eq("wombat")
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should work with multiple requests to the same connection when the first request times out" do
|
323
|
+
stub_request(:get, "www.example.com/foo").to_timeout.then.to_return(status: 200, body: "wombat")
|
324
|
+
err = nil
|
325
|
+
body = nil
|
326
|
+
|
327
|
+
EM.run do
|
328
|
+
conn = EM::HttpRequest.new("http://www.example.com")
|
329
|
+
conn.get(path: "/foo").callback do |resp|
|
330
|
+
err = :success_from_timeout
|
331
|
+
EM.stop
|
332
|
+
end.errback do |resp|
|
333
|
+
conn.get(path: "/foo").callback do |retry_resp|
|
334
|
+
expect(retry_resp.response_header.status).to eq(200)
|
335
|
+
body = retry_resp.response
|
336
|
+
EM.stop
|
337
|
+
end.errback do |retry_resp|
|
338
|
+
err = retry_resp.error
|
339
|
+
EM.stop
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
expect(err).to be(nil)
|
345
|
+
expect(body).to eq("wombat")
|
141
346
|
end
|
142
347
|
|
143
348
|
describe "mocking EM::HttpClient API" do
|
349
|
+
let(:uri) { "http://www.example.com/" }
|
350
|
+
|
144
351
|
before do
|
145
|
-
stub_request(:get,
|
352
|
+
stub_request(:get, uri)
|
146
353
|
WebMock::HttpLibAdapters::EmHttpRequestAdapter.enable!
|
147
354
|
end
|
148
|
-
|
355
|
+
|
356
|
+
def client(uri, options = {})
|
149
357
|
client = nil
|
150
358
|
EM.run do
|
151
|
-
client = EventMachine::HttpRequest.new(
|
359
|
+
client = EventMachine::HttpRequest.new(uri).get(options)
|
152
360
|
client.callback { EM.stop }
|
153
361
|
client.errback { failed }
|
154
362
|
end
|
155
363
|
client
|
156
364
|
end
|
157
365
|
|
366
|
+
subject { client(uri) }
|
367
|
+
|
158
368
|
it 'should support #uri' do
|
159
|
-
subject.uri.
|
369
|
+
expect(subject.uri).to eq(Addressable::URI.parse(uri))
|
160
370
|
end
|
161
371
|
|
162
372
|
it 'should support #last_effective_url' do
|
163
|
-
subject.last_effective_url.
|
373
|
+
expect(subject.last_effective_url).to eq(Addressable::URI.parse(uri))
|
374
|
+
end
|
375
|
+
|
376
|
+
context "with a query" do
|
377
|
+
let(:uri) { "http://www.example.com/?a=1&b=2" }
|
378
|
+
subject { client("http://www.example.com/?a=1", query: { 'b' => 2 }) }
|
379
|
+
|
380
|
+
it "#request_signature doesn't mutate the original uri" do
|
381
|
+
expect(subject.uri).to eq(Addressable::URI.parse("http://www.example.com/?a=1"))
|
382
|
+
signature = WebMock::RequestRegistry.instance.requested_signatures.hash.keys.first
|
383
|
+
expect(signature.uri).to eq(Addressable::URI.parse(uri))
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
describe 'get_response_cookie' do
|
388
|
+
|
389
|
+
before(:each) do
|
390
|
+
stub_request(:get, "http://example.org/").
|
391
|
+
to_return(
|
392
|
+
status: 200,
|
393
|
+
body: "",
|
394
|
+
headers: { 'Set-Cookie' => cookie_string }
|
395
|
+
)
|
396
|
+
end
|
397
|
+
|
398
|
+
describe 'success' do
|
399
|
+
|
400
|
+
context 'with only one cookie' do
|
401
|
+
|
402
|
+
let(:cookie_name) { 'name_of_the_cookie' }
|
403
|
+
let(:cookie_value) { 'value_of_the_cookie' }
|
404
|
+
let(:cookie_string) { "#{cookie_name}=#{cookie_value}" }
|
405
|
+
|
406
|
+
it 'successfully gets the cookie' do
|
407
|
+
EM.run {
|
408
|
+
http = EventMachine::HttpRequest.new('http://example.org').get
|
409
|
+
|
410
|
+
http.errback { fail(http.error) }
|
411
|
+
http.callback {
|
412
|
+
expect(http.get_response_cookie(cookie_name)).to eq(cookie_value)
|
413
|
+
EM.stop
|
414
|
+
}
|
415
|
+
}
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
context 'with several cookies' do
|
420
|
+
|
421
|
+
let(:cookie_name) { 'name_of_the_cookie' }
|
422
|
+
let(:cookie_value) { 'value_of_the_cookie' }
|
423
|
+
let(:cookie_2_name) { 'name_of_the_2nd_cookie' }
|
424
|
+
let(:cookie_2_value) { 'value_of_the_2nd_cookie' }
|
425
|
+
let(:cookie_string) { %W(#{cookie_name}=#{cookie_value} #{cookie_2_name}=#{cookie_2_value}) }
|
426
|
+
|
427
|
+
it 'successfully gets both cookies' do
|
428
|
+
EM.run {
|
429
|
+
http = EventMachine::HttpRequest.new('http://example.org').get
|
430
|
+
|
431
|
+
http.errback { fail(http.error) }
|
432
|
+
http.callback {
|
433
|
+
expect(http.get_response_cookie(cookie_name)).to eq(cookie_value)
|
434
|
+
expect(http.get_response_cookie(cookie_2_name)).to eq(cookie_2_value)
|
435
|
+
EM.stop
|
436
|
+
}
|
437
|
+
}
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe 'failure' do
|
443
|
+
|
444
|
+
let(:cookie_string) { 'a=b' }
|
445
|
+
|
446
|
+
it 'returns nil when no cookie is found' do
|
447
|
+
EM.run {
|
448
|
+
http = EventMachine::HttpRequest.new('http://example.org').get
|
449
|
+
|
450
|
+
http.errback { fail(http.error) }
|
451
|
+
http.callback {
|
452
|
+
expect(http.get_response_cookie('not_found_cookie')).to eq(nil)
|
453
|
+
EM.stop
|
454
|
+
}
|
455
|
+
}
|
456
|
+
end
|
457
|
+
end
|
164
458
|
end
|
165
459
|
end
|
166
460
|
|
@@ -8,6 +8,9 @@ module EMHttpRequestSpecHelper
|
|
8
8
|
def http_request(method, uri, options = {}, &block)
|
9
9
|
@http = nil
|
10
10
|
head = options[:headers] || {}
|
11
|
+
if options[:basic_auth]
|
12
|
+
head.merge!('authorization' => options[:basic_auth])
|
13
|
+
end
|
11
14
|
response = nil
|
12
15
|
error = nil
|
13
16
|
error_set = false
|
@@ -15,10 +18,12 @@ module EMHttpRequestSpecHelper
|
|
15
18
|
EventMachine.run {
|
16
19
|
request = EventMachine::HttpRequest.new("#{uri.normalize.to_s}")
|
17
20
|
http = request.send(method, {
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
21
|
+
timeout: 30,
|
22
|
+
body: options[:body],
|
23
|
+
file: options[:file],
|
24
|
+
query: options[:query],
|
25
|
+
head: head,
|
26
|
+
compressed: false
|
22
27
|
}, &block)
|
23
28
|
http.errback {
|
24
29
|
error_set = true
|
@@ -31,10 +36,10 @@ module EMHttpRequestSpecHelper
|
|
31
36
|
}
|
32
37
|
http.callback {
|
33
38
|
response = OpenStruct.new({
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
39
|
+
body: http.response,
|
40
|
+
headers: WebMock::Util::Headers.normalize_headers(extract_response_headers(http)),
|
41
|
+
message: http.response_header.http_reason,
|
42
|
+
status: http.response_header.status.to_s
|
38
43
|
})
|
39
44
|
EventMachine.stop
|
40
45
|
}
|
@@ -45,11 +50,11 @@ module EMHttpRequestSpecHelper
|
|
45
50
|
end
|
46
51
|
|
47
52
|
def client_timeout_exception_class
|
48
|
-
|
53
|
+
'Errno::ETIMEDOUT'
|
49
54
|
end
|
50
55
|
|
51
56
|
def connection_refused_exception_class
|
52
|
-
|
57
|
+
RuntimeError
|
53
58
|
end
|
54
59
|
|
55
60
|
def http_library
|
@@ -4,12 +4,74 @@ require 'acceptance/excon/excon_spec_helper'
|
|
4
4
|
|
5
5
|
describe "Excon" do
|
6
6
|
include ExconSpecHelper
|
7
|
-
include_context "with WebMock", :
|
7
|
+
include_context "with WebMock", :no_url_auth
|
8
8
|
|
9
9
|
it 'should allow Excon requests to use query hash paramters' do
|
10
|
-
stub_request(:get, "http://example.com/resource/?a=1&b=2").to_return(:
|
11
|
-
Excon.
|
10
|
+
stub_request(:get, "http://example.com/resource/?a=1&b=2").to_return(body: "abc")
|
11
|
+
expect(Excon.new('http://example.com').get(path: "resource/", query: {a: 1, b: 2}).body).to eq("abc")
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
it 'should support Excon :expects options' do
|
15
|
+
stub_request(:get, "http://example.com/").to_return(body: 'a')
|
16
|
+
expect { Excon.new('http://example.com').get(expects: 204) }.to raise_error(Excon::Errors::OK)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with response_block" do
|
20
|
+
it "should support excon response_block for real requests", net_connect: true do
|
21
|
+
a = []
|
22
|
+
WebMock.allow_net_connect!
|
23
|
+
r = Excon.new('http://httpstat.us/200', headers: { "Accept" => "*" }).
|
24
|
+
get(response_block: lambda {|e, remaining, total| a << e}, chunk_size: 1)
|
25
|
+
expect(a).to eq(["2", "0", "0", " ", "O", "K"])
|
26
|
+
expect(r.body).to eq("")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should support excon response_block" do
|
30
|
+
a = []
|
31
|
+
stub_request(:get, "http://example.com/").to_return(body: "abc")
|
32
|
+
r = Excon.new('http://example.com').get(response_block: lambda {|e, remaining, total| a << e}, chunk_size: 1)
|
33
|
+
expect(a).to eq(['a', 'b', 'c'])
|
34
|
+
expect(r.body).to eq("")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should invoke callbacks with response body even if a real request is made", net_connect: true do
|
38
|
+
a = []
|
39
|
+
WebMock.allow_net_connect!
|
40
|
+
response = nil
|
41
|
+
WebMock.after_request { |_, res|
|
42
|
+
response = res
|
43
|
+
}
|
44
|
+
r = Excon.new('http://httpstat.us/200', headers: { "Accept" => "*" }).
|
45
|
+
get(response_block: lambda {|e, remaining, total| a << e}, chunk_size: 1)
|
46
|
+
expect(response.body).to eq("200 OK")
|
47
|
+
expect(a).to eq(["2", "0", "0", " ", "O", "K"])
|
48
|
+
expect(r.body).to eq("")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:file) { File.new(__FILE__) }
|
53
|
+
let(:file_contents) { File.read(__FILE__) }
|
54
|
+
|
55
|
+
it 'handles file uploads correctly' do
|
56
|
+
stub_request(:put, "http://example.com/upload").with(body: file_contents)
|
57
|
+
|
58
|
+
yielded_request_body = nil
|
59
|
+
WebMock.after_request do |req, res|
|
60
|
+
yielded_request_body = req.body
|
61
|
+
end
|
15
62
|
|
63
|
+
Excon.new("http://example.com").put(path: "upload", body: file)
|
64
|
+
|
65
|
+
expect(yielded_request_body).to eq(file_contents)
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.request_params_from' do
|
69
|
+
|
70
|
+
it 'rejects invalid request keys' do
|
71
|
+
request_params = WebMock::HttpLibAdapters::ExconAdapter.request_params_from(body: :keep, fake: :reject)
|
72
|
+
expect(request_params).to eq(body: :keep)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -4,11 +4,23 @@ module ExconSpecHelper
|
|
4
4
|
|
5
5
|
def http_request(method, uri, options = {}, &block)
|
6
6
|
Excon.defaults[:ssl_verify_peer] = false
|
7
|
+
Excon.defaults[:ciphers] = 'DEFAULT'
|
7
8
|
uri = Addressable::URI.heuristic_parse(uri)
|
8
|
-
uri = uri.
|
9
|
+
uri = uri.to_s.gsub(' ', '%20')
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
excon_options = {}
|
12
|
+
|
13
|
+
if basic_auth = options.delete(:basic_auth)
|
14
|
+
excon_options = {user: basic_auth[0], password: basic_auth[1]}
|
15
|
+
end
|
16
|
+
|
17
|
+
if Gem::Version.new(Excon::VERSION) < Gem::Version.new("0.29.0")
|
18
|
+
options = options.merge(method: method, nonblock: false) # Dup and merge
|
19
|
+
response = Excon.new(uri, excon_options).request(options, &block)
|
20
|
+
else
|
21
|
+
options = options.merge(method: method) # Dup and merge
|
22
|
+
response = Excon.new(uri, excon_options.merge(nonblock: false)).request(options, &block)
|
23
|
+
end
|
12
24
|
|
13
25
|
headers = WebMock::Util::Headers.normalize_headers(response.headers)
|
14
26
|
headers = headers.inject({}) do |res, (name, value)|
|
@@ -16,11 +28,13 @@ module ExconSpecHelper
|
|
16
28
|
res
|
17
29
|
end
|
18
30
|
|
31
|
+
Excon.set_raise_on_warnings!(true)
|
32
|
+
|
19
33
|
OpenStruct.new \
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
34
|
+
body: response.body,
|
35
|
+
headers: headers,
|
36
|
+
status: response.status.to_s,
|
37
|
+
message: response.reason_phrase
|
24
38
|
end
|
25
39
|
|
26
40
|
def client_timeout_exception_class
|