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
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+ require "acceptance/webmock_shared"
5
+ require "acceptance/http_rb/http_rb_spec_helper"
6
+
7
+ describe "HTTP.rb" do
8
+ include HttpRbSpecHelper
9
+
10
+ include_examples "with WebMock", :no_status_message
11
+
12
+ context "streaming body" do
13
+ let(:response) { HTTP.get "http://example.com" }
14
+ before { stub_simple_request "example.com", 302, {}, "abc" }
15
+
16
+ it "works as if it was streamed from socket" do
17
+ expect(response.body.readpartial 1).to eq "a"
18
+ end
19
+
20
+ it "fails if body was already streamed" do
21
+ response.body.to_s
22
+ expect { response.body.readpartial 1 }.to raise_error(HTTP::StateError)
23
+ end
24
+ end
25
+
26
+ context "without following redirects" do
27
+ let(:response) { http_request(:get, "http://example.com") }
28
+ let(:headers) { response.headers }
29
+
30
+ it "stops on first request" do
31
+ stub_simple_request("example.com", 302, "Location" => "http://www.example.com")
32
+ stub_simple_request("www.example.com")
33
+
34
+ expect(headers).to include "Host" => "example.com"
35
+ end
36
+ end
37
+
38
+ context "following redirects" do
39
+ let(:options) { { follow: true } }
40
+ let(:response) { http_request(:get, "http://example.com", options) }
41
+ let(:headers) { response.headers }
42
+
43
+ it "returns response of destination" do
44
+ stub_simple_request("example.com", 302, "Location" => "http://www.example.com")
45
+ stub_simple_request("www.example.com")
46
+
47
+ expect(headers).to include "Host" => "www.example.com"
48
+ end
49
+ end
50
+
51
+ context "restored request uri on replayed response object" do
52
+ it "keeps non-default port" do
53
+ stub_request :get, "example.com:1234/foo"
54
+ response = HTTP.get "http://example.com:1234/foo"
55
+
56
+ expect(response.uri.to_s).to eq "http://example.com:1234/foo"
57
+ end
58
+
59
+ it "does not injects default port" do
60
+ stub_request :get, "example.com/foo"
61
+ response = HTTP.get "http://example.com/foo"
62
+
63
+ expect(response.uri.to_s).to eq "http://example.com/foo"
64
+ end
65
+
66
+ it "strips out default port even if it was explicitly given" do
67
+ stub_request :get, "example.com/foo"
68
+ response = HTTP.get "http://example.com:80/foo"
69
+
70
+ expect(response.uri.to_s).to eq "http://example.com/foo"
71
+ end
72
+ end
73
+
74
+ context "streamer" do
75
+ it "can be read to a provided buffer" do
76
+ stub_request(:get, "example.com/foo")
77
+ .to_return(status: 200, body: "Hello world! ")
78
+ response = HTTP.get "http://example.com/foo"
79
+
80
+ buffer = ""
81
+ response.body.readpartial(1024, buffer)
82
+
83
+ expect(buffer).to eq "Hello world! "
84
+ end
85
+
86
+ it "can be closed" do
87
+ stub_request :get, "example.com/foo"
88
+ response = HTTP.get "http://example.com/foo"
89
+
90
+ response.connection.close
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,54 @@
1
+ require "ostruct"
2
+
3
+ module HttpRbSpecHelper
4
+ def http_request(method, uri, options = {})
5
+ chain = HTTP
6
+
7
+ if basic_auth = options.delete(:basic_auth)
8
+ chain = chain.basic_auth(user: basic_auth[0], pass: basic_auth[1])
9
+ end
10
+
11
+ ssl_ctx = OpenSSL::SSL::SSLContext.new
12
+ ssl_ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
13
+
14
+ response = chain.request(method, normalize_uri(uri), options.merge(ssl_context: ssl_ctx))
15
+
16
+ OpenStruct.new({
17
+ body: response.body.to_s,
18
+ headers: normalize_headers(response.headers.to_h),
19
+ status: response.code.to_s,
20
+ message: response.reason
21
+ })
22
+ end
23
+
24
+ def client_timeout_exception_class
25
+ return Errno::ETIMEDOUT if HTTP::VERSION < "1.0.0"
26
+ HTTP::TimeoutError
27
+ end
28
+
29
+ def connection_refused_exception_class
30
+ return Errno::ECONNREFUSED if HTTP::VERSION < "1.0.0"
31
+ HTTP::ConnectionError
32
+ end
33
+
34
+ def http_library
35
+ :http_rb
36
+ end
37
+
38
+ def normalize_uri(uri)
39
+ Addressable::URI.heuristic_parse(uri).normalize.to_s
40
+ end
41
+
42
+ def normalize_headers(headers)
43
+ headers = Hash[headers.map { |k, v| [k, Array(v).join(", ")] }]
44
+ WebMock::Util::Headers.normalize_headers headers
45
+ end
46
+
47
+ def stub_simple_request(host, status = 200, headers = {}, body = nil)
48
+ stub_request(:any, host).to_return({
49
+ status: status,
50
+ headers: headers.merge({ "Host" => host }),
51
+ body: body
52
+ })
53
+ end
54
+ end
@@ -8,25 +8,41 @@ describe "HTTPClient" do
8
8
  include HTTPClientSpecHelper
9
9
 
10
10
  before(:each) do
11
+ WebMock.reset_callbacks
11
12
  HTTPClientSpecHelper.async_mode = false
12
13
  end
13
14
 
14
15
  include_examples "with WebMock"
15
16
 
17
+ it "should raise a clearly readable error if request with multipart body is sent" do
18
+ stub_request(:post, 'www.example.com').with(body: {type: 'image'})
19
+
20
+ expect {
21
+ HTTPClient.new.post_content('www.example.com', type: 'image', file: File.new('spec/fixtures/test.txt'))
22
+ }.to raise_error(ArgumentError, "WebMock does not support matching body for multipart/form-data requests yet :(")
23
+ end
24
+
16
25
  it "should yield block on response if block provided" do
17
- stub_request(:get, "www.example.com").to_return(:body => "abc")
26
+ stub_request(:get, "www.example.com").to_return(body: "abc")
18
27
  response_body = ""
19
28
  http_request(:get, "http://www.example.com/") do |body|
20
29
  response_body = body
21
30
  end
22
- response_body.should == "abc"
31
+ expect(response_body).to eq("abc")
32
+ end
33
+
34
+ it "should not yield block on empty response if block provided" do
35
+ stub_request(:get, "www.example.com").to_return(body: "")
36
+ response_body = ""
37
+ http_request(:get, "http://www.example.com/"){ raise }
38
+ expect(response_body).to eq("")
23
39
  end
24
40
 
25
41
  it "should match requests if headers are the same but in different order" do
26
- stub_request(:get, "www.example.com").with(:headers => {"a" => ["b", "c"]} )
27
- http_request(
42
+ stub_request(:get, "www.example.com").with(headers: {"a" => ["b", "c"]} )
43
+ expect(http_request(
28
44
  :get, "http://www.example.com/",
29
- :headers => {"a" => ["c", "b"]}).status.should == "200"
45
+ headers: {"a" => ["c", "b"]}).status).to eq("200")
30
46
  end
31
47
 
32
48
  describe "when using async requests" do
@@ -38,14 +54,50 @@ describe "HTTPClient" do
38
54
  end
39
55
 
40
56
  it "should work with get_content" do
41
- stub_request(:get, 'www.example.com').to_return(:status => 200, :body => 'test', :headers => {})
42
- str = ''
57
+ stub_request(:get, 'www.example.com').to_return(status: 200, body: 'test', headers: {})
58
+ str = ''.dup
43
59
  HTTPClient.get_content('www.example.com') do |content|
44
60
  str << content
45
61
  end
46
- str.should == 'test'
62
+ expect(str).to eq('test')
63
+ end
64
+
65
+ it "should work via JSONClient subclass" do
66
+ stub_request(:get, 'www.example.com').to_return(
67
+ status: 200,
68
+ body: '{"test": "foo"}',
69
+ headers: {'Content-Type' => 'application/json'}
70
+ )
71
+ content = JSONClient.get('www.example.com').content
72
+ expect(content).to eq("test" => "foo")
73
+ end
74
+
75
+ context "multipart bodies" do
76
+ let(:header) {{
77
+ 'Accept' => 'application/json',
78
+ 'Content-Type' => 'multipart/form-data'
79
+ }}
80
+
81
+ let(:body) {[
82
+ {
83
+ 'Content-Type' => 'application/json',
84
+ 'Content-Disposition' => 'form-data',
85
+ :content => '{"foo": "bar", "baz": 2}'
86
+ }
87
+ ]}
88
+
89
+ let(:make_request) {HTTPClient.new.post("http://www.example.com", body: body, header: header)}
90
+
91
+ before do
92
+ stub_request(:post, "www.example.com")
93
+ end
94
+
95
+ it "should work with multipart bodies" do
96
+ make_request
97
+ end
47
98
  end
48
99
 
100
+
49
101
  context "Filters" do
50
102
  class Filter
51
103
  def filter_request(request)
@@ -60,17 +112,106 @@ describe "HTTPClient" do
60
112
  before do
61
113
  @client = HTTPClient.new
62
114
  @client.request_filter << Filter.new
63
- stub_request(:get, 'www.example.com').with(:headers => {'Authorization' => 'Bearer 0123456789'})
115
+ stub_request(:get, 'www.example.com').with(headers: {'Authorization' => 'Bearer 0123456789'})
64
116
  end
65
117
 
66
118
  it "supports request filters" do
67
- @client.request(:get, 'http://www.example.com/').status.should == 200
119
+ expect(@client.request(:get, 'http://www.example.com/').status).to eq(200)
68
120
  end
69
121
 
70
122
  it "supports response filters" do
71
123
  res = @client.request(:get, 'http://www.example.com/')
72
- res.header['X-Powered-By'].first.should == 'webmock'
124
+ expect(res.header['X-Powered-By'].first).to eq('webmock')
73
125
  end
74
126
  end
75
127
 
128
+ context 'when a client instance is re-used for another identical request' do
129
+ let(:client) { HTTPClient.new }
130
+ let(:webmock_server_url) {"http://#{WebMockServer.instance.host_with_port}/"}
131
+
132
+ before { WebMock.allow_net_connect! }
133
+
134
+ it 'invokes the global_stub_request hook for each request' do
135
+ # Mock time to ensure that date headers match
136
+ now = Time.now
137
+ allow(Time).to receive(:now).and_return(now)
138
+
139
+ request_signatures = []
140
+ WebMock.globally_stub_request do |request_sig|
141
+ request_signatures << request_sig
142
+ nil # to let the request be made for real
143
+ end
144
+
145
+ http_request(:get, webmock_server_url, client: client, headers: { "Cookie" => "bar=; foo=" })
146
+
147
+ if defined? HTTP::CookieJar
148
+ http_request(:get, webmock_server_url, client: client, headers: { "Cookie" => "bar=; foo=" })
149
+ else
150
+ # If http-cookie is not present, then the cookie headers will saved between requests
151
+ http_request(:get, webmock_server_url, client: client)
152
+ end
153
+
154
+ expect(request_signatures.size).to eq(2)
155
+ # Verify the request signatures were identical as needed by this example
156
+ expect(request_signatures.first).to eq(request_signatures.last)
157
+ end
158
+ end
159
+
160
+ context 'session headers' do
161
+ it "client sends a User-Agent header when given an agent_name explicitly to the client" do
162
+ user_agent = "Client/0.1"
163
+ stub_request(:get, "www.example.com").with(headers: { 'User-agent' => "#{user_agent} #{HTTPClient::LIB_NAME}" })
164
+ HTTPClient.new(agent_name: user_agent).get("www.example.com")
165
+ end
166
+
167
+ it "client sends the Accept, User-Agent, and Date by default" do
168
+ WebMock.disable_net_connect!
169
+ stub_request(:get, "www.example.com").with do |req|
170
+ req.headers["Accept"] == "*/*" &&
171
+ req.headers["User-Agent"] == "#{HTTPClient::DEFAULT_AGENT_NAME} #{HTTPClient::LIB_NAME}" &&
172
+ req.headers["Date"]
173
+ end
174
+ http_request(:get, "www.example.com")
175
+ end
176
+
177
+ it "explicitly defined headers take precedence over session defaults" do
178
+ headers = { 'Accept' => 'foo/bar', 'User-Agent' => 'custom', 'Date' => 'today' }
179
+ stub_request(:get, "www.example.com").with(headers: headers)
180
+ HTTPClient.new.get("www.example.com", nil, headers)
181
+ end
182
+ end
183
+
184
+ context 'httpclient response header' do
185
+ it 'receives request_method, request_uri, and request_query from the request header' do
186
+ stub_request :get, 'www.example.com'
187
+ message = HTTPClient.new.get 'www.example.com'
188
+ expect(message.header.request_uri.to_s).to eq('www.example.com')
189
+ end
190
+ end
191
+
192
+ context 'httpclient streams response', net_connect: true do
193
+ before do
194
+ WebMock.allow_net_connect!
195
+ WebMock.after_request(except: [:other_lib]) do |_, response|
196
+ @response = response
197
+ end
198
+ end
199
+
200
+ it 'sets the full body on the webmock response' do
201
+ body = ''
202
+ HTTPClient.new.request(:get, 'http://www.example.com/') do |http_res, chunk|
203
+ body += chunk
204
+ end
205
+ expect(@response.body).to eq body
206
+ end
207
+ end
208
+
209
+ context 'credentials' do
210
+ it 'are detected when manually specifying Authorization header' do
211
+ stub_request(:get, "http://www.example.com/").with(basic_auth: ['username', 'password']).to_return(status: 200)
212
+
213
+ headers = {'Authorization' => 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}
214
+ expect(http_request(:get, 'http://www.example.com/', {headers: headers}).status).to eql('200')
215
+ end
216
+ end
76
217
  end
@@ -5,11 +5,15 @@ module HTTPClientSpecHelper
5
5
 
6
6
  def http_request(method, uri, options = {}, &block)
7
7
  uri = Addressable::URI.heuristic_parse(uri)
8
- c = HTTPClient.new
8
+ c = options.fetch(:client) { HTTPClient.new }
9
9
  c.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
10
- c.set_basic_auth(nil, uri.user, uri.password) if uri.user
11
- params = [method, "#{uri.omit(:userinfo, :query).normalize.to_s}",
12
- uri.query_values, options[:body], options[:headers] || {}]
10
+ c.reset_all
11
+ if options[:basic_auth]
12
+ c.force_basic_auth = true
13
+ c.set_basic_auth(nil, options[:basic_auth][0], options[:basic_auth][1])
14
+ end
15
+ params = [method, uri.normalize.to_s,
16
+ WebMock::Util::QueryMapper.query_to_values(uri.query, notation: WebMock::Config.instance.query_values_notation), options[:body], options[:headers] || {}]
13
17
  if HTTPClientSpecHelper.async_mode
14
18
  connection = c.request_async(*params)
15
19
  connection.join
@@ -17,19 +21,12 @@ module HTTPClientSpecHelper
17
21
  else
18
22
  response = c.request(*params, &block)
19
23
  end
20
- headers = response.header.all.inject({}) do |headers, header|
21
- if !headers.has_key?(header[0])
22
- headers[header[0]] = header[1]
23
- else
24
- headers[header[0]] = [headers[header[0]], header[1]].join(', ')
25
- end
26
- headers
27
- end
24
+ headers = merge_headers(response)
28
25
  OpenStruct.new({
29
- :body => HTTPClientSpecHelper.async_mode ? response.content.read : response.content,
30
- :headers => headers,
31
- :status => response.code.to_s,
32
- :message => response.reason
26
+ body: HTTPClientSpecHelper.async_mode ? response.content.read : response.content,
27
+ headers: headers,
28
+ status: response.code.to_s,
29
+ message: response.reason
33
30
  })
34
31
  end
35
32
 
@@ -45,4 +42,16 @@ module HTTPClientSpecHelper
45
42
  :httpclient
46
43
  end
47
44
 
45
+ private
46
+
47
+ def merge_headers(response)
48
+ response.header.all.inject({}) do |headers, header|
49
+ if !headers.has_key?(header[0])
50
+ headers[header[0]] = header[1]
51
+ else
52
+ headers[header[0]] = [headers[header[0]], header[1]].join(', ')
53
+ end
54
+ headers
55
+ end
56
+ end
48
57
  end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+ require 'acceptance/webmock_shared'
3
+
4
+ if RUBY_PLATFORM =~ /java/
5
+ require 'acceptance/manticore/manticore_spec_helper'
6
+
7
+ describe "Manticore" do
8
+ include ManticoreSpecHelper
9
+
10
+ include_context "with WebMock", :no_status_message
11
+
12
+ context "calling http methods on Manticore directly using Manticore's facade" do
13
+ it "handles GET" do
14
+ stub_request(:get, "http://example-foo.com").to_return(status: 301)
15
+ response = Manticore.get("http://example-foo.com")
16
+ expect(response.code).to eq(301)
17
+ end
18
+
19
+ it "handles POST" do
20
+ stub_request(:post, "http://example-foo.com").to_return(status: 201)
21
+ response = Manticore.post("http://example-foo.com", {hello: "world"})
22
+ expect(response.code).to eq(201)
23
+ end
24
+
25
+ it "handles PUT" do
26
+ stub_request(:put, "http://example-foo.com").to_return(status: 409)
27
+ response = Manticore.put("http://example-foo.com", {hello: "world"})
28
+ expect(response.code).to eq(409)
29
+ end
30
+
31
+ it "handles PATCH" do
32
+ stub_request(:patch, "http://example-foo.com").to_return(status: 409)
33
+ response = Manticore.patch("http://example-foo.com", {hello: "world"})
34
+ expect(response.code).to eq(409)
35
+ end
36
+
37
+ it "handles DELETE" do
38
+ stub_request(:delete, "http://example-foo.com").to_return(status: 204)
39
+ response = Manticore.delete("http://example-foo.com", {id: 1})
40
+ expect(response.code).to eq(204)
41
+ end
42
+
43
+ it "handles OPTIONS" do
44
+ stub_request(:options, "http://example-foo.com").to_return(status: 200)
45
+ response = Manticore.options("http://example-foo.com")
46
+ expect(response.code).to eq(200)
47
+ end
48
+
49
+ it "handles HEAD" do
50
+ stub_request(:head, "http://example-foo.com").to_return(status: 204)
51
+ response = Manticore.head("http://example-foo.com")
52
+ expect(response.code).to eq(204)
53
+ end
54
+
55
+ context "when a custom failure handler is defined" do
56
+ let(:failure_handler) { proc {} }
57
+
58
+ before do
59
+ allow(failure_handler).to receive(:call).with(kind_of(Manticore::Timeout)) do |ex|
60
+ raise ex
61
+ end
62
+ end
63
+
64
+ it "handles timeouts by invoking the failure handler" do
65
+ stub_request(:get, "http://example-foo.com").to_timeout
66
+ request = Manticore.get("http://example-foo.com").tap do |req|
67
+ req.on_failure(&failure_handler)
68
+ end
69
+ expect { request.call }.to raise_error(Manticore::Timeout)
70
+ expect(failure_handler).to have_received(:call)
71
+ end
72
+ end
73
+
74
+ context 'when used in a streaming mode' do
75
+ let(:webmock_server_url) {"http://#{WebMockServer.instance.host_with_port}/"}
76
+ let(:result_chunks) { [] }
77
+
78
+ def manticore_streaming_get
79
+ Manticore.get(webmock_server_url).tap do |req|
80
+ req.on_success do |response|
81
+ response.body do |chunk|
82
+ result_chunks << chunk
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'when connections are allowed' do
89
+ it 'works' do
90
+ WebMock.allow_net_connect!
91
+ expect { manticore_streaming_get.call }.to_not raise_error
92
+ expect(result_chunks).to_not be_empty
93
+ end
94
+ end
95
+
96
+ context 'when stubbed' do
97
+ it 'works' do
98
+ stub_body = 'hello!'
99
+ stub_request(:get, webmock_server_url).to_return(body: stub_body)
100
+ expect { manticore_streaming_get.call }.to_not raise_error
101
+ expect(result_chunks).to eq [stub_body]
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,35 @@
1
+ module ManticoreSpecHelper
2
+ def http_request(method, uri, options = {})
3
+ client = Manticore::Client.new
4
+
5
+ if basic_auth = options[:basic_auth]
6
+ options = options.merge(auth: {user: basic_auth[0], pass: basic_auth[1]})
7
+ end
8
+
9
+ response = client.http(method, uri, options)
10
+ OpenStruct.new({
11
+ body: response.body || '',
12
+ headers: WebMock::Util::Headers.normalize_headers(join_array_values(response.headers)),
13
+ status: response.code.to_s
14
+ })
15
+ end
16
+
17
+ def join_array_values(hash)
18
+ hash.reduce({}) do |h, (k,v)|
19
+ v = v.join(', ') if v.is_a?(Array)
20
+ h.merge(k => v)
21
+ end
22
+ end
23
+
24
+ def client_timeout_exception_class
25
+ Manticore::ConnectTimeout
26
+ end
27
+
28
+ def connection_refused_exception_class
29
+ Manticore::SocketException
30
+ end
31
+
32
+ def http_library
33
+ :manticore
34
+ end
35
+ end