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
data/lib/webmock.rb CHANGED
@@ -1,49 +1,59 @@
1
1
  require 'singleton'
2
2
 
3
3
  require 'addressable/uri'
4
- require 'crack'
5
-
6
- require 'webmock/deprecation'
7
- require 'webmock/version'
8
-
9
- require 'webmock/errors'
10
-
11
- require 'webmock/util/uri'
12
- require 'webmock/util/headers'
13
- require 'webmock/util/hash_counter'
14
- require 'webmock/util/hash_keys_stringifier'
15
- require 'webmock/util/json'
16
- require 'webmock/util/version_checker'
17
-
18
- require 'webmock/matchers/hash_including_matcher'
19
-
20
- require 'webmock/request_pattern'
21
- require 'webmock/request_signature'
22
- require 'webmock/responses_sequence'
23
- require 'webmock/request_stub'
24
- require 'webmock/response'
25
- require 'webmock/rack_response'
26
-
27
- require 'webmock/stub_request_snippet'
28
-
29
- require 'webmock/assertion_failure'
30
- require 'webmock/request_execution_verifier'
31
- require 'webmock/config'
32
- require 'webmock/callback_registry'
33
- require 'webmock/request_registry'
34
- require 'webmock/stub_registry'
35
- require 'webmock/api'
36
-
37
- require 'webmock/http_lib_adapters/http_lib_adapter_registry'
38
- require 'webmock/http_lib_adapters/http_lib_adapter'
39
- require 'webmock/http_lib_adapters/net_http'
40
- require 'webmock/http_lib_adapters/httpclient_adapter'
41
- require 'webmock/http_lib_adapters/patron_adapter'
42
- require 'webmock/http_lib_adapters/curb_adapter'
43
- require 'webmock/http_lib_adapters/em_http_request_adapter'
44
- require 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
45
- require 'webmock/http_lib_adapters/excon_adapter'
46
-
47
- require 'webmock/webmock'
48
-
49
-
4
+ require 'addressable/template'
5
+ require 'crack/xml'
6
+
7
+ require_relative 'webmock/deprecation'
8
+ require_relative 'webmock/version'
9
+
10
+ require_relative 'webmock/errors'
11
+
12
+ require_relative 'webmock/util/query_mapper'
13
+ require_relative 'webmock/util/uri'
14
+ require_relative 'webmock/util/headers'
15
+ require_relative 'webmock/util/hash_counter'
16
+ require_relative 'webmock/util/hash_keys_stringifier'
17
+ require_relative 'webmock/util/values_stringifier'
18
+ require_relative 'webmock/util/json'
19
+ require_relative 'webmock/util/version_checker'
20
+ require_relative 'webmock/util/hash_validator'
21
+
22
+ require_relative 'webmock/matchers/hash_argument_matcher'
23
+ require_relative 'webmock/matchers/hash_excluding_matcher'
24
+ require_relative 'webmock/matchers/hash_including_matcher'
25
+ require_relative 'webmock/matchers/any_arg_matcher'
26
+
27
+ require_relative 'webmock/request_pattern'
28
+ require_relative 'webmock/request_signature'
29
+ require_relative 'webmock/responses_sequence'
30
+ require_relative 'webmock/request_stub'
31
+ require_relative 'webmock/response'
32
+ require_relative 'webmock/rack_response'
33
+
34
+ require_relative 'webmock/stub_request_snippet'
35
+ require_relative 'webmock/request_signature_snippet'
36
+ require_relative 'webmock/request_body_diff'
37
+
38
+ require_relative 'webmock/assertion_failure'
39
+ require_relative 'webmock/request_execution_verifier'
40
+ require_relative 'webmock/config'
41
+ require_relative 'webmock/callback_registry'
42
+ require_relative 'webmock/request_registry'
43
+ require_relative 'webmock/stub_registry'
44
+ require_relative 'webmock/api'
45
+
46
+ require_relative 'webmock/http_lib_adapters/http_lib_adapter_registry'
47
+ require_relative 'webmock/http_lib_adapters/http_lib_adapter'
48
+ require_relative 'webmock/http_lib_adapters/net_http'
49
+ require_relative 'webmock/http_lib_adapters/http_rb_adapter'
50
+ require_relative 'webmock/http_lib_adapters/httpclient_adapter'
51
+ require_relative 'webmock/http_lib_adapters/patron_adapter'
52
+ require_relative 'webmock/http_lib_adapters/curb_adapter'
53
+ require_relative 'webmock/http_lib_adapters/em_http_request_adapter'
54
+ require_relative 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
55
+ require_relative 'webmock/http_lib_adapters/excon_adapter'
56
+ require_relative 'webmock/http_lib_adapters/manticore_adapter'
57
+ require_relative 'webmock/http_lib_adapters/async_http_client_adapter'
58
+
59
+ require_relative 'webmock/webmock'
@@ -5,11 +5,15 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
5
 
6
6
  require File.expand_path(File.dirname(__FILE__) + '/../test/http_request')
7
7
 
8
- gem "minitest"
8
+ gem 'minitest'
9
+
9
10
  require 'minitest/autorun'
10
11
  require 'webmock/minitest'
11
12
 
12
- class MiniTest::Unit::TestCase
13
+ test_class = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
14
+
15
+ test_class.class_eval do
16
+
13
17
  def assert_raise(*exp, &block)
14
18
  assert_raises(*exp, &block)
15
19
  end
@@ -26,4 +30,5 @@ class MiniTest::Unit::TestCase
26
30
  def assert_fail(message, &block)
27
31
  assert_raise_with_message(MiniTest::Assertion, message, &block)
28
32
  end
29
- end
33
+
34
+ end
@@ -1,6 +1,9 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../test/shared_test')
3
3
 
4
- class MiniTestWebMock < MiniTest::Unit::TestCase
4
+ test_class = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase
5
+
6
+
7
+ class MiniTestWebMock < test_class
5
8
  include SharedTest
6
9
  end
@@ -8,31 +8,42 @@ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
8
8
  @stub_https = stub_http_request(:any, "https://www.example.com")
9
9
  end
10
10
 
11
+ it "should update assertions count" do
12
+ assert_equal 0, assertions
13
+ http_request(:get, "http://www.example.com/")
14
+
15
+ assert_requested(@stub_http)
16
+ assert_equal 2, assertions
17
+
18
+ assert_not_requested(:post, "http://www.example.com")
19
+ assert_equal 4, assertions
20
+ end
21
+
11
22
  it "should raise error on non stubbed request" do
12
23
  lambda { http_request(:get, "http://www.example.net/") }.must_raise(WebMock::NetConnectNotAllowedError)
13
24
  end
14
25
 
15
26
  it "should verify that expected request occured" do
16
27
  http_request(:get, "http://www.example.com/")
17
- assert_requested(:get, "http://www.example.com", :times => 1)
28
+ assert_requested(:get, "http://www.example.com", times: 1)
18
29
  assert_requested(:get, "http://www.example.com")
19
30
  end
20
31
 
21
32
  it "should verify that expected http stub occured" do
22
33
  http_request(:get, "http://www.example.com/")
23
- assert_requested(@stub_http, :times => 1)
34
+ assert_requested(@stub_http, times: 1)
24
35
  assert_requested(@stub_http)
25
36
  end
26
37
 
27
38
  it "should verify that expected https stub occured" do
28
39
  http_request(:get, "https://www.example.com/")
29
40
  http_request(:get, "https://www.example.com/")
30
- assert_requested(@stub_https, :times => 2)
41
+ assert_requested(@stub_https, times: 2)
31
42
  end
32
43
 
33
44
  it "should verify that expect request didn't occur" do
34
45
  expected_message = "The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times"
35
- expected_message << "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
46
+ expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
36
47
  assert_fail(expected_message) do
37
48
  assert_requested(:get, "http://www.example.com")
38
49
  end
@@ -40,11 +51,10 @@ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
40
51
 
41
52
  it "should verify that expect stub didn't occur" do
42
53
  expected_message = "The request ANY http://www.example.com/ was expected to execute 1 time but it executed 0 times"
43
- expected_message << "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
54
+ expected_message += "\n\nThe following requests were made:\n\nNo requests were made.\n============================================================"
44
55
  assert_fail(expected_message) do
45
56
  assert_requested(@stub_http)
46
57
  end
47
58
  end
48
-
49
59
  end
50
60
 
@@ -0,0 +1,375 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'acceptance/webmock_shared'
4
+ require_relative './async_http_client_spec_helper'
5
+
6
+ require 'protocol/http/body/file'
7
+
8
+ Async.logger.debug! if ENV['ASYNC_LOGGER_DEBUG']
9
+
10
+ unless RUBY_PLATFORM =~ /java/
11
+ describe 'Async::HTTP::Client' do
12
+ include AsyncHttpClientSpecHelper
13
+
14
+ include_context "with WebMock",
15
+ :no_status_message,
16
+ :no_url_auth,
17
+ :no_content_length_header
18
+
19
+ it 'works' do
20
+ stub_request(:get, 'http://www.example.com')
21
+ expect(make_request(:get, 'http://www.example.com')).to eq(
22
+ status: 200,
23
+ headers: {},
24
+ body: nil
25
+ )
26
+ end
27
+
28
+ it 'works with request path' do
29
+ stub_request(:get, 'http://www.example.com/foo')
30
+ expect(make_request(:get, 'http://www.example.com/foo')).to eq(
31
+ status: 200,
32
+ headers: {},
33
+ body: nil
34
+ )
35
+ end
36
+
37
+ it 'works with request query' do
38
+ stub_request(:get, 'http://www.example.com/').with(
39
+ query: {
40
+ 'foo' => 'bar'
41
+ }
42
+ )
43
+ expect(make_request(:get, 'http://www.example.com/?foo=bar')).to eq(
44
+ status: 200,
45
+ headers: {},
46
+ body: nil
47
+ )
48
+ end
49
+
50
+ it 'works with request headers' do
51
+ stub_request(:get, 'http://www.example.com').with(
52
+ headers: {
53
+ 'X-Token' => 'Token'
54
+ }
55
+ )
56
+ expect(
57
+ make_request :get, 'http://www.example.com',
58
+ headers: {
59
+ 'X-Token' => 'Token'
60
+ }
61
+ ).to eq(
62
+ status: 200,
63
+ headers: {},
64
+ body: nil
65
+ )
66
+ end
67
+
68
+ it 'works with request body as text' do
69
+ stub_request(:post, 'http://www.example.com').with(
70
+ body: 'x'*10_000
71
+ )
72
+ expect(
73
+ make_request :post, 'http://www.example.com',
74
+ body: 'x'*10_000
75
+ ).to eq(
76
+ status: 200,
77
+ headers: {},
78
+ body: nil
79
+ )
80
+ end
81
+
82
+ it 'works with request body as file' do
83
+ stub_request(:post, "www.example.com").with(
84
+ body: File.read(__FILE__)
85
+ )
86
+ expect(
87
+ make_request :post, "http://www.example.com",
88
+ body: ::Protocol::HTTP::Body::File.open(__FILE__, block_size: 32)
89
+ ).to eq(
90
+ status: 200,
91
+ headers: {},
92
+ body: nil
93
+ )
94
+ end
95
+
96
+ it 'works with response status' do
97
+ stub_request(:get, 'http://www.example.com').to_return(
98
+ status: 400
99
+ )
100
+ expect(make_request(:get, 'http://www.example.com')).to eq(
101
+ status: 400,
102
+ headers: {},
103
+ body: nil
104
+ )
105
+ end
106
+
107
+ it 'works with response headers' do
108
+ stub_request(:get, 'http://www.example.com').to_return(
109
+ headers: {
110
+ 'X-Token' => 'TOKEN'
111
+ }
112
+ )
113
+ expect(make_request(:get, 'http://www.example.com')).to eq(
114
+ status: 200,
115
+ headers: {
116
+ 'x-token' => ['TOKEN']
117
+ },
118
+ body: nil
119
+ )
120
+ end
121
+
122
+ it 'works with response body' do
123
+ stub_request(:get, 'http://www.example.com').to_return(
124
+ body: 'abc'
125
+ )
126
+ expect(make_request(:get, 'http://www.example.com')).to eq(
127
+ status: 200,
128
+ headers: {},
129
+ body: 'abc'
130
+ )
131
+ end
132
+
133
+ it 'works with to_timeout' do
134
+ stub_request(:get, 'http://www.example.com').to_timeout
135
+ expect { make_request(:get, 'http://www.example.com') }.to raise_error Async::TimeoutError
136
+ end
137
+
138
+ it 'does not invoke "after real request" callbacks for stubbed requests' do
139
+ WebMock.allow_net_connect!
140
+ stub_request(:get, 'http://www.example.com').to_return(body: 'abc')
141
+
142
+ callback_invoked = false
143
+ WebMock.after_request(real_requests_only: true) { |_| callback_invoked = true }
144
+
145
+ make_request(:get, 'http://www.example.com')
146
+ expect(callback_invoked).to eq(false)
147
+ end
148
+
149
+ it 'does invoke "after request" callbacks for stubbed requests' do
150
+ WebMock.allow_net_connect!
151
+ stub_request(:get, 'http://www.example.com').to_return(body: 'abc')
152
+
153
+ callback_invoked = false
154
+ WebMock.after_request(real_requests_only: false) { |_| callback_invoked = true }
155
+
156
+ make_request(:get, 'http://www.example.com')
157
+ expect(callback_invoked).to eq(true)
158
+ end
159
+
160
+ context 'scheme and protocol' do
161
+ let(:default_response_headers) { {} }
162
+
163
+ before do
164
+ stub_request(
165
+ :get, "#{scheme}://www.example.com"
166
+ ).and_return(
167
+ body: 'BODY'
168
+ )
169
+ end
170
+
171
+ subject do
172
+ make_request(:get, "#{scheme}://www.example.com", protocol: protocol)
173
+ end
174
+
175
+ shared_examples :common do
176
+ specify do
177
+ expect(subject).to eq(
178
+ status: 200,
179
+ headers: default_response_headers,
180
+ body: 'BODY'
181
+ )
182
+ end
183
+ end
184
+
185
+ context 'http scheme' do
186
+ let(:scheme) { 'http' }
187
+
188
+ context 'default protocol' do
189
+ let(:protocol) { nil }
190
+
191
+ include_examples :common
192
+ end
193
+
194
+ context 'HTTP10 protocol' do
195
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
196
+ let(:default_response_headers) { {"connection"=>["keep-alive"]} }
197
+
198
+ include_examples :common
199
+ end
200
+
201
+ context 'HTTP11 protocol' do
202
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
203
+
204
+ include_examples :common
205
+ end
206
+
207
+ context 'HTTP2 protocol' do
208
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
209
+
210
+ include_examples :common
211
+ end
212
+ end
213
+
214
+ context 'https scheme' do
215
+ let(:scheme) { 'https' }
216
+
217
+ context 'default protocol' do
218
+ let(:protocol) { nil }
219
+
220
+ include_examples :common
221
+ end
222
+
223
+ context 'HTTP10 protocol' do
224
+ let(:protocol) { Async::HTTP::Protocol::HTTP10 }
225
+ let(:default_response_headers) { {"connection"=>["keep-alive"]} }
226
+
227
+ include_examples :common
228
+ end
229
+
230
+ context 'HTTP11 protocol' do
231
+ let(:protocol) { Async::HTTP::Protocol::HTTP11 }
232
+
233
+ include_examples :common
234
+ end
235
+
236
+ context 'HTTP2 protocol' do
237
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
238
+
239
+ include_examples :common
240
+ end
241
+
242
+ context 'HTTPS protocol' do
243
+ let(:protocol) { Async::HTTP::Protocol::HTTPS }
244
+
245
+ include_examples :common
246
+ end
247
+ end
248
+ end
249
+
250
+ context 'multiple requests' do
251
+ let(:endpoint) { Async::HTTP::Endpoint.parse('http://www.example.com') }
252
+ let(:requests_count) { 3 }
253
+
254
+ shared_examples :common do
255
+ before do
256
+ requests_count.times do |index|
257
+ stub_request(
258
+ :get, "http://www.example.com/foo#{index}"
259
+ ).to_return(
260
+ status: 200 + index,
261
+ headers: {'X-Token' => "foo#{index}"},
262
+ body: "FOO#{index}"
263
+ )
264
+ end
265
+ end
266
+
267
+ specify do
268
+ expect(subject).to eq(
269
+ 0 => {
270
+ status: 200,
271
+ headers: {'x-token' => ['foo0']},
272
+ body: 'FOO0'
273
+ },
274
+ 1 => {
275
+ status: 201,
276
+ headers: {'x-token' => ['foo1']},
277
+ body: 'FOO1'
278
+ },
279
+ 2 => {
280
+ status: 202,
281
+ headers: {'x-token' => ['foo2']},
282
+ body: 'FOO2'
283
+ }
284
+ )
285
+ end
286
+ end
287
+
288
+ context 'sequential' do
289
+ subject do
290
+ responses = {}
291
+ Async do |task|
292
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
293
+ requests_count.times do |index|
294
+ response = client.get "/foo#{index}"
295
+ responses[index] = response_to_hash(response)
296
+ end
297
+ end
298
+ end
299
+ responses
300
+ end
301
+
302
+ context 'HTTP1 protocol' do
303
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
304
+
305
+ include_examples :common
306
+ end
307
+
308
+ context 'HTTP2 protocol' do
309
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
310
+
311
+ include_examples :common
312
+ end
313
+ end
314
+
315
+ context 'asynchronous' do
316
+ subject do
317
+ responses = {}
318
+ Async do |task|
319
+ Async::HTTP::Client.open(endpoint, protocol) do |client|
320
+ tasks = requests_count.times.map do |index|
321
+ task.async do
322
+ response = client.get "/foo#{index}"
323
+ responses[index] = response_to_hash(response)
324
+ end
325
+ end
326
+
327
+ tasks.map(&:wait)
328
+ end
329
+ end
330
+ responses
331
+ end
332
+
333
+ context 'HTTP1 protocol' do
334
+ let(:protocol) { Async::HTTP::Protocol::HTTP1 }
335
+
336
+ include_examples :common
337
+ end
338
+
339
+ context 'HTTP2 protocol' do
340
+ let(:protocol) { Async::HTTP::Protocol::HTTP2 }
341
+
342
+ include_examples :common
343
+ end
344
+ end
345
+ end
346
+
347
+ def make_request(method, url, protocol: nil, headers: {}, body: nil)
348
+ Async do
349
+ endpoint = Async::HTTP::Endpoint.parse(url)
350
+
351
+ begin
352
+ Async::HTTP::Client.open(endpoint, protocol || endpoint.protocol) do |client|
353
+ response = client.send(
354
+ method,
355
+ endpoint.path,
356
+ headers,
357
+ body
358
+ )
359
+ response_to_hash(response)
360
+ end
361
+ rescue Async::TimeoutError => e
362
+ e
363
+ end
364
+ end.wait
365
+ end
366
+
367
+ def response_to_hash(response)
368
+ {
369
+ status: response.status,
370
+ headers: response.headers.to_h,
371
+ body: response.read
372
+ }
373
+ end
374
+ end
375
+ end
@@ -0,0 +1,73 @@
1
+ module AsyncHttpClientSpecHelper
2
+ def http_request(method, url, options = {}, &block)
3
+ endpoint = Async::HTTP::Endpoint.parse(url)
4
+
5
+ path = endpoint.path
6
+ path = path + "?" + options[:query] if options[:query]
7
+
8
+ headers = (options[:headers] || {}).each_with_object([]) do |(k, v), o|
9
+ Array(v).each do |v|
10
+ o.push [k, v]
11
+ end
12
+ end
13
+ headers.push(
14
+ ['authorization', 'Basic ' + Base64.strict_encode64(options[:basic_auth].join(':'))]
15
+ ) if options[:basic_auth]
16
+
17
+ body = options[:body]
18
+
19
+ Async do
20
+ begin
21
+ Async::HTTP::Client.open(endpoint) do |client|
22
+ response = client.send(
23
+ method,
24
+ path,
25
+ headers,
26
+ body
27
+ )
28
+
29
+ OpenStruct.new(
30
+ build_hash_response(response)
31
+ )
32
+ end
33
+ rescue Exception => e
34
+ e
35
+ end
36
+ end.wait
37
+ end
38
+
39
+ def client_timeout_exception_class
40
+ Async::TimeoutError
41
+ end
42
+
43
+ def connection_refused_exception_class
44
+ Errno::ECONNREFUSED
45
+ end
46
+
47
+ def http_library
48
+ :async_http_client
49
+ end
50
+
51
+ private
52
+
53
+ def build_hash_response(response)
54
+ {
55
+
56
+ status: response.status.to_s,
57
+ message: Protocol::HTTP1::Reason::DESCRIPTIONS[response.status],
58
+ headers: build_response_headers(response),
59
+ body: response.read
60
+ }
61
+ end
62
+
63
+ def build_response_headers(response)
64
+ response.headers.each.each_with_object({}) do |(k, v), o|
65
+ o[k] ||= []
66
+ o[k] << v
67
+ end.tap do |o|
68
+ o.each do |k, v|
69
+ o[k] = v.join(', ')
70
+ end
71
+ end
72
+ end
73
+ end