http 5.3.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +241 -41
- data/LICENSE.txt +1 -1
- data/README.md +110 -13
- data/UPGRADING.md +491 -0
- data/http.gemspec +32 -29
- data/lib/http/base64.rb +11 -1
- data/lib/http/chainable/helpers.rb +62 -0
- data/lib/http/chainable/verbs.rb +136 -0
- data/lib/http/chainable.rb +232 -136
- data/lib/http/client.rb +158 -127
- data/lib/http/connection/internals.rb +141 -0
- data/lib/http/connection.rb +126 -97
- data/lib/http/content_type.rb +61 -6
- data/lib/http/errors.rb +25 -1
- data/lib/http/feature.rb +65 -5
- data/lib/http/features/auto_deflate.rb +124 -17
- data/lib/http/features/auto_inflate.rb +38 -15
- data/lib/http/features/caching/entry.rb +178 -0
- data/lib/http/features/caching/in_memory_store.rb +63 -0
- data/lib/http/features/caching.rb +216 -0
- data/lib/http/features/digest_auth.rb +234 -0
- data/lib/http/features/instrumentation.rb +97 -17
- data/lib/http/features/logging.rb +183 -5
- data/lib/http/features/normalize_uri.rb +17 -0
- data/lib/http/features/raise_error.rb +18 -3
- data/lib/http/form_data/composite_io.rb +106 -0
- data/lib/http/form_data/file.rb +95 -0
- data/lib/http/form_data/multipart/param.rb +62 -0
- data/lib/http/form_data/multipart.rb +106 -0
- data/lib/http/form_data/part.rb +52 -0
- data/lib/http/form_data/readable.rb +58 -0
- data/lib/http/form_data/urlencoded.rb +175 -0
- data/lib/http/form_data/version.rb +8 -0
- data/lib/http/form_data.rb +102 -0
- data/lib/http/headers/known.rb +3 -0
- data/lib/http/headers/normalizer.rb +17 -36
- data/lib/http/headers.rb +172 -65
- data/lib/http/mime_type/adapter.rb +24 -9
- data/lib/http/mime_type/json.rb +19 -4
- data/lib/http/mime_type.rb +21 -3
- data/lib/http/options/definitions.rb +189 -0
- data/lib/http/options.rb +172 -125
- data/lib/http/redirector.rb +80 -75
- data/lib/http/request/body.rb +87 -6
- data/lib/http/request/builder.rb +184 -0
- data/lib/http/request/proxy.rb +83 -0
- data/lib/http/request/writer.rb +76 -16
- data/lib/http/request.rb +214 -98
- data/lib/http/response/body.rb +103 -18
- data/lib/http/response/inflater.rb +35 -7
- data/lib/http/response/parser.rb +98 -4
- data/lib/http/response/status/reasons.rb +2 -4
- data/lib/http/response/status.rb +141 -31
- data/lib/http/response.rb +219 -61
- data/lib/http/retriable/delay_calculator.rb +38 -11
- data/lib/http/retriable/errors.rb +21 -0
- data/lib/http/retriable/performer.rb +82 -38
- data/lib/http/session.rb +280 -0
- data/lib/http/timeout/global.rb +147 -34
- data/lib/http/timeout/null.rb +155 -9
- data/lib/http/timeout/per_operation.rb +139 -18
- data/lib/http/uri/normalizer.rb +82 -0
- data/lib/http/uri/parsing.rb +182 -0
- data/lib/http/uri.rb +289 -124
- data/lib/http/version.rb +2 -1
- data/lib/http.rb +11 -2
- data/sig/deps.rbs +122 -0
- data/sig/http.rbs +1619 -0
- data/test/http/base64_test.rb +28 -0
- data/test/http/client_test.rb +739 -0
- data/test/http/connection_test.rb +1533 -0
- data/test/http/content_type_test.rb +190 -0
- data/test/http/errors_test.rb +28 -0
- data/test/http/feature_test.rb +49 -0
- data/test/http/features/auto_deflate_test.rb +317 -0
- data/test/http/features/auto_inflate_test.rb +213 -0
- data/test/http/features/caching_test.rb +942 -0
- data/test/http/features/digest_auth_test.rb +996 -0
- data/test/http/features/instrumentation_test.rb +246 -0
- data/test/http/features/logging_test.rb +654 -0
- data/test/http/features/normalize_uri_test.rb +41 -0
- data/test/http/features/raise_error_test.rb +77 -0
- data/test/http/form_data/composite_io_test.rb +215 -0
- data/test/http/form_data/file_test.rb +255 -0
- data/test/http/form_data/fixtures/the-http-gem.info +1 -0
- data/test/http/form_data/multipart_test.rb +303 -0
- data/test/http/form_data/part_test.rb +90 -0
- data/test/http/form_data/urlencoded_test.rb +164 -0
- data/test/http/form_data_test.rb +232 -0
- data/test/http/headers/normalizer_test.rb +93 -0
- data/test/http/headers_test.rb +888 -0
- data/test/http/mime_type/json_test.rb +39 -0
- data/test/http/mime_type_test.rb +150 -0
- data/test/http/options/base_uri_test.rb +148 -0
- data/test/http/options/body_test.rb +21 -0
- data/test/http/options/features_test.rb +38 -0
- data/test/http/options/form_test.rb +21 -0
- data/test/http/options/headers_test.rb +32 -0
- data/test/http/options/json_test.rb +21 -0
- data/test/http/options/merge_test.rb +78 -0
- data/test/http/options/new_test.rb +37 -0
- data/test/http/options/proxy_test.rb +32 -0
- data/test/http/options_test.rb +575 -0
- data/test/http/redirector_test.rb +639 -0
- data/test/http/request/body_test.rb +318 -0
- data/test/http/request/builder_test.rb +623 -0
- data/test/http/request/writer_test.rb +391 -0
- data/test/http/request_test.rb +1733 -0
- data/test/http/response/body_test.rb +292 -0
- data/test/http/response/parser_test.rb +105 -0
- data/test/http/response/status_test.rb +322 -0
- data/test/http/response_test.rb +502 -0
- data/test/http/retriable/delay_calculator_test.rb +194 -0
- data/test/http/retriable/errors_test.rb +71 -0
- data/test/http/retriable/performer_test.rb +551 -0
- data/test/http/session_test.rb +424 -0
- data/test/http/timeout/global_test.rb +239 -0
- data/test/http/timeout/null_test.rb +218 -0
- data/test/http/timeout/per_operation_test.rb +220 -0
- data/test/http/uri/normalizer_test.rb +89 -0
- data/test/http/uri_test.rb +1140 -0
- data/test/http/version_test.rb +15 -0
- data/test/http_test.rb +818 -0
- data/test/regression_tests.rb +27 -0
- data/test/support/dummy_server/encoding_routes.rb +47 -0
- data/test/support/dummy_server/routes.rb +201 -0
- data/test/support/dummy_server/servlet.rb +81 -0
- data/test/support/dummy_server.rb +200 -0
- data/{spec → test}/support/fakeio.rb +2 -2
- data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
- data/test/support/http_handling_shared/timeout_tests.rb +134 -0
- data/test/support/http_handling_shared.rb +11 -0
- data/test/support/proxy_server.rb +207 -0
- data/test/support/servers/runner.rb +67 -0
- data/{spec → test}/support/simplecov.rb +11 -2
- data/test/support/ssl_helper.rb +108 -0
- data/test/test_helper.rb +38 -0
- metadata +108 -168
- data/.github/workflows/ci.yml +0 -67
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.rubocop/layout.yml +0 -8
- data/.rubocop/metrics.yml +0 -4
- data/.rubocop/rspec.yml +0 -9
- data/.rubocop/style.yml +0 -32
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -219
- data/.yardopts +0 -2
- data/CHANGES_OLD.md +0 -1002
- data/Gemfile +0 -51
- data/Guardfile +0 -18
- data/Rakefile +0 -64
- data/lib/http/headers/mixin.rb +0 -34
- data/lib/http/retriable/client.rb +0 -37
- data/logo.png +0 -0
- data/spec/lib/http/client_spec.rb +0 -556
- data/spec/lib/http/connection_spec.rb +0 -88
- data/spec/lib/http/content_type_spec.rb +0 -47
- data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
- data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
- data/spec/lib/http/features/instrumentation_spec.rb +0 -81
- data/spec/lib/http/features/logging_spec.rb +0 -65
- data/spec/lib/http/features/raise_error_spec.rb +0 -62
- data/spec/lib/http/headers/mixin_spec.rb +0 -36
- data/spec/lib/http/headers/normalizer_spec.rb +0 -52
- data/spec/lib/http/headers_spec.rb +0 -527
- data/spec/lib/http/options/body_spec.rb +0 -15
- data/spec/lib/http/options/features_spec.rb +0 -33
- data/spec/lib/http/options/form_spec.rb +0 -15
- data/spec/lib/http/options/headers_spec.rb +0 -24
- data/spec/lib/http/options/json_spec.rb +0 -15
- data/spec/lib/http/options/merge_spec.rb +0 -68
- data/spec/lib/http/options/new_spec.rb +0 -30
- data/spec/lib/http/options/proxy_spec.rb +0 -20
- data/spec/lib/http/options_spec.rb +0 -13
- data/spec/lib/http/redirector_spec.rb +0 -530
- data/spec/lib/http/request/body_spec.rb +0 -211
- data/spec/lib/http/request/writer_spec.rb +0 -121
- data/spec/lib/http/request_spec.rb +0 -234
- data/spec/lib/http/response/body_spec.rb +0 -85
- data/spec/lib/http/response/parser_spec.rb +0 -74
- data/spec/lib/http/response/status_spec.rb +0 -253
- data/spec/lib/http/response_spec.rb +0 -262
- data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
- data/spec/lib/http/retriable/performer_spec.rb +0 -302
- data/spec/lib/http/uri/normalizer_spec.rb +0 -95
- data/spec/lib/http/uri_spec.rb +0 -71
- data/spec/lib/http_spec.rb +0 -535
- data/spec/regression_specs.rb +0 -24
- data/spec/spec_helper.rb +0 -89
- data/spec/support/black_hole.rb +0 -13
- data/spec/support/dummy_server/servlet.rb +0 -203
- data/spec/support/dummy_server.rb +0 -44
- data/spec/support/fuubar.rb +0 -21
- data/spec/support/http_handling_shared.rb +0 -190
- data/spec/support/proxy_server.rb +0 -39
- data/spec/support/servers/config.rb +0 -11
- data/spec/support/servers/runner.rb +0 -19
- data/spec/support/ssl_helper.rb +0 -104
- /data/{spec → test}/support/capture_warning.rb +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPMimeTypeJSONTest < Minitest::Test
|
|
6
|
+
cover "HTTP::MimeType*"
|
|
7
|
+
|
|
8
|
+
def adapter
|
|
9
|
+
@adapter ||= HTTP::MimeType::JSON.send(:new)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_encode_uses_to_json_when_available
|
|
13
|
+
assert_equal '{"foo":"bar"}', adapter.encode(foo: "bar")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_encode_prefers_to_json_over_json_dump
|
|
17
|
+
obj = Object.new
|
|
18
|
+
def obj.to_json(*args)
|
|
19
|
+
args.empty? ? '"direct"' : '"via_dump"'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
assert_equal '"direct"', adapter.encode(obj)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_encode_falls_back_to_json_dump_for_objects_without_to_json
|
|
26
|
+
obj = Object.new
|
|
27
|
+
obj.define_singleton_method(:respond_to?) do |method, *args|
|
|
28
|
+
return false if method == :to_json
|
|
29
|
+
|
|
30
|
+
super(method, *args)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
assert_kind_of String, adapter.encode(obj)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_decode_parses_json_strings
|
|
37
|
+
assert_equal({ "foo" => "bar" }, adapter.decode('{"foo":"bar"}'))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
class HTTPMimeTypeTest < Minitest::Test
|
|
7
|
+
cover "HTTP::MimeType*"
|
|
8
|
+
|
|
9
|
+
def sample_type
|
|
10
|
+
@sample_type ||= "application/mutant-check-#{SecureRandom.hex(4)}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sample_adapter
|
|
14
|
+
@sample_adapter ||= Module.new do
|
|
15
|
+
def self.encode(obj); end
|
|
16
|
+
|
|
17
|
+
def self.decode(str); end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_register_adapter_stores_the_adapter_retrievable_via_brackets
|
|
22
|
+
HTTP::MimeType.register_adapter(sample_type, sample_adapter)
|
|
23
|
+
|
|
24
|
+
assert_same sample_adapter, HTTP::MimeType[sample_type]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_register_adapter_calls_to_s_on_the_type_argument
|
|
28
|
+
type_str = "application/test-to-s-#{SecureRandom.hex(4)}"
|
|
29
|
+
type_obj = fake(to_s: type_str)
|
|
30
|
+
|
|
31
|
+
HTTP::MimeType.register_adapter(type_obj, sample_adapter)
|
|
32
|
+
|
|
33
|
+
assert_same sample_adapter, HTTP::MimeType[type_str]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_brackets_retrieves_a_registered_adapter
|
|
37
|
+
HTTP::MimeType.register_adapter(sample_type, sample_adapter)
|
|
38
|
+
|
|
39
|
+
assert_same sample_adapter, HTTP::MimeType[sample_type]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_brackets_raises_unsupported_mime_type_error_for_unknown_type
|
|
43
|
+
assert_raises(HTTP::UnsupportedMimeTypeError) do
|
|
44
|
+
HTTP::MimeType["application/nonexistent-#{SecureRandom.hex(4)}"]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_brackets_includes_the_type_in_the_error_message
|
|
49
|
+
unknown = "application/unknown-#{SecureRandom.hex(4)}"
|
|
50
|
+
|
|
51
|
+
err = assert_raises(HTTP::UnsupportedMimeTypeError) do
|
|
52
|
+
HTTP::MimeType[unknown]
|
|
53
|
+
end
|
|
54
|
+
assert_includes err.message, unknown
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_brackets_resolves_aliases_when_looking_up_adapters
|
|
58
|
+
shortcut = :"test_shortcut_#{SecureRandom.hex(4)}"
|
|
59
|
+
HTTP::MimeType.register_adapter(sample_type, sample_adapter)
|
|
60
|
+
HTTP::MimeType.register_alias(sample_type, shortcut)
|
|
61
|
+
|
|
62
|
+
assert_same sample_adapter, HTTP::MimeType[shortcut]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_register_alias_stores_alias_resolvable_via_normalize
|
|
66
|
+
shortcut = :"test_alias_#{SecureRandom.hex(4)}"
|
|
67
|
+
HTTP::MimeType.register_alias(sample_type, shortcut)
|
|
68
|
+
|
|
69
|
+
assert_equal sample_type, HTTP::MimeType.normalize(shortcut)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_register_alias_calls_to_sym_on_the_shortcut_argument
|
|
73
|
+
shortcut_str = "test_sym_shortcut_#{SecureRandom.hex(4)}"
|
|
74
|
+
HTTP::MimeType.register_alias(sample_type, shortcut_str)
|
|
75
|
+
|
|
76
|
+
assert_equal sample_type, HTTP::MimeType.normalize(shortcut_str.to_sym)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_register_alias_calls_to_s_on_the_type_argument
|
|
80
|
+
type_str = "application/test-alias-to-s-#{SecureRandom.hex(4)}"
|
|
81
|
+
type_obj = fake(to_s: type_str)
|
|
82
|
+
|
|
83
|
+
shortcut = :"test_alias_to_s_#{SecureRandom.hex(4)}"
|
|
84
|
+
HTTP::MimeType.register_alias(type_obj, shortcut)
|
|
85
|
+
|
|
86
|
+
assert_equal type_str, HTTP::MimeType.normalize(shortcut)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_normalize_returns_the_type_string_if_no_alias_found
|
|
90
|
+
unaliased = "application/no-alias-#{SecureRandom.hex(4)}"
|
|
91
|
+
|
|
92
|
+
assert_equal unaliased, HTTP::MimeType.normalize(unaliased)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_normalize_returns_aliased_type_if_alias_exists
|
|
96
|
+
shortcut = :"test_norm_#{SecureRandom.hex(4)}"
|
|
97
|
+
HTTP::MimeType.register_alias(sample_type, shortcut)
|
|
98
|
+
|
|
99
|
+
assert_equal sample_type, HTTP::MimeType.normalize(shortcut)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_normalize_calls_to_s_on_the_argument_when_no_alias_found
|
|
103
|
+
type_str = "application/normalize-to-s-#{SecureRandom.hex(4)}"
|
|
104
|
+
type_obj = fake(to_s: type_str)
|
|
105
|
+
|
|
106
|
+
assert_equal type_str, HTTP::MimeType.normalize(type_obj)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_adapters_initializes_as_a_hash_when_accessed_for_the_first_time
|
|
110
|
+
original = HTTP::MimeType.instance_variable_get(:@adapters)
|
|
111
|
+
HTTP::MimeType.instance_variable_set(:@adapters, nil)
|
|
112
|
+
begin
|
|
113
|
+
result = HTTP::MimeType.send(:adapters)
|
|
114
|
+
|
|
115
|
+
assert_instance_of Hash, result
|
|
116
|
+
ensure
|
|
117
|
+
HTTP::MimeType.instance_variable_set(:@adapters, original)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_aliases_initializes_as_a_hash_when_accessed_for_the_first_time
|
|
122
|
+
original = HTTP::MimeType.instance_variable_get(:@aliases)
|
|
123
|
+
HTTP::MimeType.instance_variable_set(:@aliases, nil)
|
|
124
|
+
begin
|
|
125
|
+
result = HTTP::MimeType.send(:aliases)
|
|
126
|
+
|
|
127
|
+
assert_instance_of Hash, result
|
|
128
|
+
ensure
|
|
129
|
+
HTTP::MimeType.instance_variable_set(:@aliases, original)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_adapter_raises_error_on_encode_with_class_name_in_message
|
|
134
|
+
err = assert_raises(HTTP::Error) { HTTP::MimeType::Adapter.instance.encode("data") }
|
|
135
|
+
assert_equal "HTTP::MimeType::Adapter does not supports #encode", err.message
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_adapter_raises_error_on_decode_with_class_name_in_message
|
|
139
|
+
err = assert_raises(HTTP::Error) { HTTP::MimeType::Adapter.instance.decode("data") }
|
|
140
|
+
assert_equal "HTTP::MimeType::Adapter does not supports #decode", err.message
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_builtin_has_json_adapter_registered_for_application_json
|
|
144
|
+
assert_equal HTTP::MimeType::JSON, HTTP::MimeType["application/json"]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_builtin_has_json_alias_for_application_json
|
|
148
|
+
assert_equal "application/json", HTTP::MimeType.normalize(:json)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsBaseURITest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
# #with_base_uri
|
|
9
|
+
|
|
10
|
+
def test_with_base_uri_sets_base_uri_from_a_string
|
|
11
|
+
opts = HTTP::Options.new
|
|
12
|
+
result = opts.with_base_uri("https://example.com/api")
|
|
13
|
+
|
|
14
|
+
assert_equal "https://example.com/api", result.base_uri.to_s
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_with_base_uri_sets_base_uri_from_an_http_uri
|
|
18
|
+
opts = HTTP::Options.new
|
|
19
|
+
uri = HTTP::URI.parse("https://example.com/api")
|
|
20
|
+
result = opts.with_base_uri(uri)
|
|
21
|
+
|
|
22
|
+
assert_equal "https://example.com/api", result.base_uri.to_s
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_with_base_uri_raises_for_uri_without_scheme
|
|
26
|
+
opts = HTTP::Options.new
|
|
27
|
+
err = assert_raises(HTTP::Error) { opts.with_base_uri("/users") }
|
|
28
|
+
|
|
29
|
+
assert_includes err.message, "Invalid base URI"
|
|
30
|
+
assert_includes err.message, "/users"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_with_base_uri_raises_for_protocol_relative_uri
|
|
34
|
+
opts = HTTP::Options.new
|
|
35
|
+
err = assert_raises(HTTP::Error) { opts.with_base_uri("//example.com/users") }
|
|
36
|
+
|
|
37
|
+
assert_includes err.message, "Invalid base URI"
|
|
38
|
+
assert_includes err.message, "//example.com/users"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_with_base_uri_does_not_modify_the_original_options
|
|
42
|
+
opts = HTTP::Options.new
|
|
43
|
+
opts.with_base_uri("https://example.com")
|
|
44
|
+
|
|
45
|
+
refute_predicate opts, :base_uri?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# #base_uri?
|
|
49
|
+
|
|
50
|
+
def test_base_uri_predicate_returns_false_by_default
|
|
51
|
+
opts = HTTP::Options.new
|
|
52
|
+
|
|
53
|
+
refute_predicate opts, :base_uri?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_base_uri_predicate_returns_true_when_base_uri_is_set
|
|
57
|
+
opts = HTTP::Options.new
|
|
58
|
+
result = opts.with_base_uri("https://example.com")
|
|
59
|
+
|
|
60
|
+
assert_predicate result, :base_uri?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# chaining base URIs
|
|
64
|
+
|
|
65
|
+
def test_chaining_joins_a_relative_path_onto_existing_base_uri
|
|
66
|
+
opts = HTTP::Options.new
|
|
67
|
+
result = opts.with_base_uri("https://example.com").with_base_uri("api/v1")
|
|
68
|
+
|
|
69
|
+
assert_equal "https://example.com/api/v1", result.base_uri.to_s
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_chaining_joins_an_absolute_path_onto_existing_base_uri
|
|
73
|
+
opts = HTTP::Options.new
|
|
74
|
+
result = opts.with_base_uri("https://example.com/api").with_base_uri("/v2")
|
|
75
|
+
|
|
76
|
+
assert_equal "https://example.com/v2", result.base_uri.to_s
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_chaining_replaces_with_a_full_uri
|
|
80
|
+
opts = HTTP::Options.new
|
|
81
|
+
result = opts.with_base_uri("https://example.com/api").with_base_uri("https://other.com/v2")
|
|
82
|
+
|
|
83
|
+
assert_equal "https://other.com/v2", result.base_uri.to_s
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_chaining_joins_onto_base_uri_with_trailing_slash
|
|
87
|
+
opts = HTTP::Options.new
|
|
88
|
+
result = opts.with_base_uri("https://example.com/api/").with_base_uri("v2")
|
|
89
|
+
|
|
90
|
+
assert_equal "https://example.com/api/v2", result.base_uri.to_s
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_chaining_handles_parent_path_traversal
|
|
94
|
+
opts = HTTP::Options.new
|
|
95
|
+
result = opts.with_base_uri("https://example.com/api/v1").with_base_uri("../v2")
|
|
96
|
+
|
|
97
|
+
assert_equal "https://example.com/api/v2", result.base_uri.to_s
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_chaining_does_not_mutate_the_intermediate_base_uri
|
|
101
|
+
opts = HTTP::Options.new
|
|
102
|
+
intermediate = opts.with_base_uri("https://example.com/api")
|
|
103
|
+
intermediate.with_base_uri("v2")
|
|
104
|
+
|
|
105
|
+
assert_equal "https://example.com/api", intermediate.base_uri.to_s
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# persistent and base_uri interaction
|
|
109
|
+
|
|
110
|
+
def test_persistent_allows_compatible_persistent_and_base_uri
|
|
111
|
+
opts = HTTP::Options.new
|
|
112
|
+
result = opts.with_base_uri("https://example.com/api").with_persistent("https://example.com")
|
|
113
|
+
|
|
114
|
+
assert_equal "https://example.com/api", result.base_uri.to_s
|
|
115
|
+
assert_equal "https://example.com", result.persistent
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def test_persistent_raises_when_persistent_origin_conflicts_with_base_uri
|
|
119
|
+
opts = HTTP::Options.new
|
|
120
|
+
with_base = opts.with_base_uri("https://example.com/api")
|
|
121
|
+
|
|
122
|
+
err = assert_raises(HTTP::Error) { with_base.with_persistent("https://other.com") }
|
|
123
|
+
assert_includes err.message, "https://other.com"
|
|
124
|
+
assert_includes err.message, "base URI origin (https://example.com)"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_persistent_raises_when_base_uri_origin_conflicts_with_persistent
|
|
128
|
+
opts = HTTP::Options.new
|
|
129
|
+
with_persistent = opts.with_persistent("https://example.com")
|
|
130
|
+
|
|
131
|
+
err = assert_raises(HTTP::Error) { with_persistent.with_base_uri("https://other.com/api") }
|
|
132
|
+
assert_includes err.message, "https://example.com"
|
|
133
|
+
assert_includes err.message, "base URI origin (https://other.com)"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_persistent_allows_setting_both_via_constructor_when_origins_match
|
|
137
|
+
result = HTTP::Options.new(base_uri: "https://example.com/api", persistent: "https://example.com")
|
|
138
|
+
|
|
139
|
+
assert_equal "https://example.com/api", result.base_uri.to_s
|
|
140
|
+
assert_equal "https://example.com", result.persistent
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_persistent_raises_via_constructor_when_origins_conflict
|
|
144
|
+
assert_raises(HTTP::Error) do
|
|
145
|
+
HTTP::Options.new(base_uri: "https://example.com/api", persistent: "https://other.com")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsBodyTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_nil
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_nil opts.body
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_may_be_specified_with_with_body
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_body("foo")
|
|
17
|
+
|
|
18
|
+
assert_nil opts.body
|
|
19
|
+
assert_equal "foo", opts2.body
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsFeaturesTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_be_empty
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_empty opts.features
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_accepts_plain_symbols_in_array
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_features([:auto_inflate])
|
|
17
|
+
|
|
18
|
+
assert_empty opts.features
|
|
19
|
+
assert_equal [:auto_inflate], opts2.features.keys
|
|
20
|
+
assert_instance_of HTTP::Features::AutoInflate, opts2.features[:auto_inflate]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_accepts_feature_name_with_its_options_in_array
|
|
24
|
+
opts = HTTP::Options.new
|
|
25
|
+
opts2 = opts.with_features([{ auto_deflate: { method: :deflate } }])
|
|
26
|
+
|
|
27
|
+
assert_empty opts.features
|
|
28
|
+
assert_equal [:auto_deflate], opts2.features.keys
|
|
29
|
+
assert_instance_of HTTP::Features::AutoDeflate, opts2.features[:auto_deflate]
|
|
30
|
+
assert_equal "deflate", opts2.features[:auto_deflate].method
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_raises_error_for_not_supported_features
|
|
34
|
+
opts = HTTP::Options.new
|
|
35
|
+
error = assert_raises(HTTP::Error) { opts.with_features([:wrong_feature]) }
|
|
36
|
+
assert_equal "Unsupported feature: wrong_feature", error.message
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsFormTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_nil
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_nil opts.form
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_may_be_specified_with_with_form_data
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_form(foo: 42)
|
|
17
|
+
|
|
18
|
+
assert_nil opts.form
|
|
19
|
+
assert_equal({ foo: 42 }, opts2.form)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsHeadersTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_be_empty
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_empty opts.headers
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_may_be_specified_with_with_headers
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_headers(accept: "json")
|
|
17
|
+
|
|
18
|
+
assert_empty opts.headers
|
|
19
|
+
assert_equal [%w[Accept json]], opts2.headers.to_a
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_accepts_any_object_that_respond_to_to_hash
|
|
23
|
+
opts = HTTP::Options.new
|
|
24
|
+
x = if RUBY_VERSION >= "3.2.0"
|
|
25
|
+
Data.define(:to_hash).new(to_hash: { "accept" => "json" })
|
|
26
|
+
else
|
|
27
|
+
Struct.new(:to_hash).new({ "accept" => "json" })
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
assert_equal "json", opts.with_headers(x).headers["accept"]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsJSONTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_nil
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_nil opts.json
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_may_be_specified_with_with_json_data
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_json(foo: 42)
|
|
17
|
+
|
|
18
|
+
assert_nil opts.json
|
|
19
|
+
assert_equal({ foo: 42 }, opts2.json)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsMergeTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_supports_a_hash
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
old_response = opts.response
|
|
11
|
+
|
|
12
|
+
assert_equal :body, opts.merge(response: :body).response
|
|
13
|
+
assert_equal old_response, opts.response
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_supports_another_options
|
|
17
|
+
opts = HTTP::Options.new
|
|
18
|
+
merged = opts.merge(HTTP::Options.new(response: :body))
|
|
19
|
+
|
|
20
|
+
assert_equal :body, merged.response
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_merges_as_expected_in_complex_cases
|
|
24
|
+
# FIXME: yuck :(
|
|
25
|
+
|
|
26
|
+
foo = HTTP::Options.new(
|
|
27
|
+
response: :body,
|
|
28
|
+
params: { baz: "bar" },
|
|
29
|
+
form: { foo: "foo" },
|
|
30
|
+
body: "body-foo",
|
|
31
|
+
json: { foo: "foo" },
|
|
32
|
+
headers: { accept: "json", foo: "foo" },
|
|
33
|
+
proxy: {},
|
|
34
|
+
features: {}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
bar = HTTP::Options.new(
|
|
38
|
+
response: :parsed_body,
|
|
39
|
+
persistent: "https://www.googe.com",
|
|
40
|
+
params: { plop: "plip" },
|
|
41
|
+
form: { bar: "bar" },
|
|
42
|
+
body: "body-bar",
|
|
43
|
+
json: { bar: "bar" },
|
|
44
|
+
keep_alive_timeout: 10,
|
|
45
|
+
headers: { accept: "xml", bar: "bar" },
|
|
46
|
+
timeout_options: { foo: :bar },
|
|
47
|
+
ssl: { foo: "bar" },
|
|
48
|
+
proxy: { proxy_address: "127.0.0.1", proxy_port: 8080 }
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
assert_equal(
|
|
52
|
+
{
|
|
53
|
+
response: :parsed_body,
|
|
54
|
+
timeout_class: HTTP::Options.default_timeout_class,
|
|
55
|
+
timeout_options: { foo: :bar },
|
|
56
|
+
params: { plop: "plip" },
|
|
57
|
+
form: { bar: "bar" },
|
|
58
|
+
body: "body-bar",
|
|
59
|
+
json: { bar: "bar" },
|
|
60
|
+
persistent: "https://www.googe.com",
|
|
61
|
+
keep_alive_timeout: 10,
|
|
62
|
+
ssl: { foo: "bar" },
|
|
63
|
+
headers: { "Foo" => "foo", "Accept" => "xml", "Bar" => "bar" },
|
|
64
|
+
proxy: { proxy_address: "127.0.0.1", proxy_port: 8080 },
|
|
65
|
+
follow: nil,
|
|
66
|
+
retriable: nil,
|
|
67
|
+
base_uri: nil,
|
|
68
|
+
socket_class: HTTP::Options.default_socket_class,
|
|
69
|
+
nodelay: false,
|
|
70
|
+
ssl_socket_class: HTTP::Options.default_ssl_socket_class,
|
|
71
|
+
ssl_context: nil,
|
|
72
|
+
encoding: nil,
|
|
73
|
+
features: {}
|
|
74
|
+
},
|
|
75
|
+
foo.merge(bar).to_hash
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsNewTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_supports_a_options_instance
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_equal opts, HTTP::Options.new(opts)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_with_a_hash_coerces_response_correctly
|
|
15
|
+
opts = HTTP::Options.new(response: :object)
|
|
16
|
+
|
|
17
|
+
assert_equal :object, opts.response
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_with_a_hash_coerces_headers_correctly
|
|
21
|
+
opts = HTTP::Options.new(headers: { accept: "json" })
|
|
22
|
+
|
|
23
|
+
assert_equal [%w[Accept json]], opts.headers.to_a
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_with_a_hash_coerces_proxy_correctly
|
|
27
|
+
opts = HTTP::Options.new(proxy: { proxy_address: "127.0.0.1", proxy_port: 8080 })
|
|
28
|
+
|
|
29
|
+
assert_equal({ proxy_address: "127.0.0.1", proxy_port: 8080 }, opts.proxy)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_with_a_hash_coerces_form_correctly
|
|
33
|
+
opts = HTTP::Options.new(form: { foo: 42 })
|
|
34
|
+
|
|
35
|
+
assert_equal({ foo: 42 }, opts.form)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPOptionsProxyTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Options*"
|
|
7
|
+
|
|
8
|
+
def test_defaults_to_empty_hash
|
|
9
|
+
opts = HTTP::Options.new
|
|
10
|
+
|
|
11
|
+
assert_equal({}, opts.proxy)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_may_be_specified_with_with_proxy
|
|
15
|
+
opts = HTTP::Options.new
|
|
16
|
+
opts2 = opts.with_proxy(proxy_address: "127.0.0.1", proxy_port: 8080)
|
|
17
|
+
|
|
18
|
+
assert_equal({}, opts.proxy)
|
|
19
|
+
assert_equal({ proxy_address: "127.0.0.1", proxy_port: 8080 }, opts2.proxy)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_accepts_proxy_address_port_username_and_password
|
|
23
|
+
opts = HTTP::Options.new
|
|
24
|
+
opts2 = opts.with_proxy(proxy_address: "127.0.0.1", proxy_port: 8080, proxy_username: "username",
|
|
25
|
+
proxy_password: "password")
|
|
26
|
+
|
|
27
|
+
assert_equal(
|
|
28
|
+
{ proxy_address: "127.0.0.1", proxy_port: 8080, proxy_username: "username",
|
|
29
|
+
proxy_password: "password" }, opts2.proxy
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|