webmock 1.8.6 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
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