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.
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
@@ -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(:body => 'bar')
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(:body => 'foo')
65
+ http = conn.get(body: 'foo')
33
66
 
34
67
  http.callback do
35
- WebMock.should have_requested(:get, "www.example.com").with(:body => 'bar')
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 "should work with response middleware" do
42
- stub_request(:get, "www.example.com").to_return(:body => 'foo')
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 middleware
117
+ conn.use response_middleware
54
118
 
55
119
  http = conn.get
56
120
 
57
121
  http.callback do
58
- http.response.should be == 'bar'
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(:status => 200, :body => 'ok')
82
- lambda {
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
- http = EM::HttpRequest.new("http://www.testserver.com").post :body => "foo=bar&baz=bang", :timeout => 60
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
- }.should_not raise_error
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(:body => "abc")
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.should == "abc"
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(:body => "abc", :headers => { 'Transfer-Encoding' => 'chunked' })
119
- http_request(:get, "http://www.example.com").body.should == "abc"
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(:body => "abc")
124
- http_request(:get, "http://www.example.com/?x=3", :query => {"a" => ["b", "c"]}).body.should == "abc"
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(:body => "abc")
129
- http_request(:get, "http://www.example.com/?x=3", :query => "a[]=b&a[]=c").body.should == "abc"
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(:body => {:a => "1", :b => "2"}).to_return(:body => "ok")
134
- http_request(:post, "http://www.example.com", :body => {:a => "1", :b => "2"}).body.should == "ok"
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(:body => body)
140
- http_request(:post, "http://www.example.com").body.bytesize.should == 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, "www.example.com/")
352
+ stub_request(:get, uri)
146
353
  WebMock::HttpLibAdapters::EmHttpRequestAdapter.enable!
147
354
  end
148
- subject do
355
+
356
+ def client(uri, options = {})
149
357
  client = nil
150
358
  EM.run do
151
- client = EventMachine::HttpRequest.new('http://www.example.com/').get
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.should == Addressable::URI.parse('http://www.example.com/')
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.should == Addressable::URI.parse('http://www.example.com/')
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
- :timeout => 30,
19
- :body => options[:body],
20
- :query => options[:query],
21
- :head => head.merge('authorization' => [uri.user, uri.password])
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
- :body => http.response,
35
- :headers => WebMock::Util::Headers.normalize_headers(extract_response_headers(http)),
36
- :message => http.response_header.http_reason,
37
- :status => http.response_header.status.to_s
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
- "WebMock timeout error"
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", :no_status_message, :no_url_auth
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(:body => "abc")
11
- Excon.get('http://example.com', :path => "resource/", :query => {:a => 1, :b => 2}).body.should == "abc"
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
- end
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.omit(:userinfo).to_s.gsub(' ', '+')
9
+ uri = uri.to_s.gsub(' ', '%20')
9
10
 
10
- options = options.merge(:method => method) # Dup and merge
11
- response = Excon.new(uri).request(options, &block)
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
- :body => response.body,
21
- :headers => headers,
22
- :status => response.status.to_s,
23
- :message => ""
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