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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +241 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +110 -13
  5. data/UPGRADING.md +491 -0
  6. data/http.gemspec +32 -29
  7. data/lib/http/base64.rb +11 -1
  8. data/lib/http/chainable/helpers.rb +62 -0
  9. data/lib/http/chainable/verbs.rb +136 -0
  10. data/lib/http/chainable.rb +232 -136
  11. data/lib/http/client.rb +158 -127
  12. data/lib/http/connection/internals.rb +141 -0
  13. data/lib/http/connection.rb +126 -97
  14. data/lib/http/content_type.rb +61 -6
  15. data/lib/http/errors.rb +25 -1
  16. data/lib/http/feature.rb +65 -5
  17. data/lib/http/features/auto_deflate.rb +124 -17
  18. data/lib/http/features/auto_inflate.rb +38 -15
  19. data/lib/http/features/caching/entry.rb +178 -0
  20. data/lib/http/features/caching/in_memory_store.rb +63 -0
  21. data/lib/http/features/caching.rb +216 -0
  22. data/lib/http/features/digest_auth.rb +234 -0
  23. data/lib/http/features/instrumentation.rb +97 -17
  24. data/lib/http/features/logging.rb +183 -5
  25. data/lib/http/features/normalize_uri.rb +17 -0
  26. data/lib/http/features/raise_error.rb +18 -3
  27. data/lib/http/form_data/composite_io.rb +106 -0
  28. data/lib/http/form_data/file.rb +95 -0
  29. data/lib/http/form_data/multipart/param.rb +62 -0
  30. data/lib/http/form_data/multipart.rb +106 -0
  31. data/lib/http/form_data/part.rb +52 -0
  32. data/lib/http/form_data/readable.rb +58 -0
  33. data/lib/http/form_data/urlencoded.rb +175 -0
  34. data/lib/http/form_data/version.rb +8 -0
  35. data/lib/http/form_data.rb +102 -0
  36. data/lib/http/headers/known.rb +3 -0
  37. data/lib/http/headers/normalizer.rb +17 -36
  38. data/lib/http/headers.rb +172 -65
  39. data/lib/http/mime_type/adapter.rb +24 -9
  40. data/lib/http/mime_type/json.rb +19 -4
  41. data/lib/http/mime_type.rb +21 -3
  42. data/lib/http/options/definitions.rb +189 -0
  43. data/lib/http/options.rb +172 -125
  44. data/lib/http/redirector.rb +80 -75
  45. data/lib/http/request/body.rb +87 -6
  46. data/lib/http/request/builder.rb +184 -0
  47. data/lib/http/request/proxy.rb +83 -0
  48. data/lib/http/request/writer.rb +76 -16
  49. data/lib/http/request.rb +214 -98
  50. data/lib/http/response/body.rb +103 -18
  51. data/lib/http/response/inflater.rb +35 -7
  52. data/lib/http/response/parser.rb +98 -4
  53. data/lib/http/response/status/reasons.rb +2 -4
  54. data/lib/http/response/status.rb +141 -31
  55. data/lib/http/response.rb +219 -61
  56. data/lib/http/retriable/delay_calculator.rb +38 -11
  57. data/lib/http/retriable/errors.rb +21 -0
  58. data/lib/http/retriable/performer.rb +82 -38
  59. data/lib/http/session.rb +280 -0
  60. data/lib/http/timeout/global.rb +147 -34
  61. data/lib/http/timeout/null.rb +155 -9
  62. data/lib/http/timeout/per_operation.rb +139 -18
  63. data/lib/http/uri/normalizer.rb +82 -0
  64. data/lib/http/uri/parsing.rb +182 -0
  65. data/lib/http/uri.rb +289 -124
  66. data/lib/http/version.rb +2 -1
  67. data/lib/http.rb +11 -2
  68. data/sig/deps.rbs +122 -0
  69. data/sig/http.rbs +1619 -0
  70. data/test/http/base64_test.rb +28 -0
  71. data/test/http/client_test.rb +739 -0
  72. data/test/http/connection_test.rb +1533 -0
  73. data/test/http/content_type_test.rb +190 -0
  74. data/test/http/errors_test.rb +28 -0
  75. data/test/http/feature_test.rb +49 -0
  76. data/test/http/features/auto_deflate_test.rb +317 -0
  77. data/test/http/features/auto_inflate_test.rb +213 -0
  78. data/test/http/features/caching_test.rb +942 -0
  79. data/test/http/features/digest_auth_test.rb +996 -0
  80. data/test/http/features/instrumentation_test.rb +246 -0
  81. data/test/http/features/logging_test.rb +654 -0
  82. data/test/http/features/normalize_uri_test.rb +41 -0
  83. data/test/http/features/raise_error_test.rb +77 -0
  84. data/test/http/form_data/composite_io_test.rb +215 -0
  85. data/test/http/form_data/file_test.rb +255 -0
  86. data/test/http/form_data/fixtures/the-http-gem.info +1 -0
  87. data/test/http/form_data/multipart_test.rb +303 -0
  88. data/test/http/form_data/part_test.rb +90 -0
  89. data/test/http/form_data/urlencoded_test.rb +164 -0
  90. data/test/http/form_data_test.rb +232 -0
  91. data/test/http/headers/normalizer_test.rb +93 -0
  92. data/test/http/headers_test.rb +888 -0
  93. data/test/http/mime_type/json_test.rb +39 -0
  94. data/test/http/mime_type_test.rb +150 -0
  95. data/test/http/options/base_uri_test.rb +148 -0
  96. data/test/http/options/body_test.rb +21 -0
  97. data/test/http/options/features_test.rb +38 -0
  98. data/test/http/options/form_test.rb +21 -0
  99. data/test/http/options/headers_test.rb +32 -0
  100. data/test/http/options/json_test.rb +21 -0
  101. data/test/http/options/merge_test.rb +78 -0
  102. data/test/http/options/new_test.rb +37 -0
  103. data/test/http/options/proxy_test.rb +32 -0
  104. data/test/http/options_test.rb +575 -0
  105. data/test/http/redirector_test.rb +639 -0
  106. data/test/http/request/body_test.rb +318 -0
  107. data/test/http/request/builder_test.rb +623 -0
  108. data/test/http/request/writer_test.rb +391 -0
  109. data/test/http/request_test.rb +1733 -0
  110. data/test/http/response/body_test.rb +292 -0
  111. data/test/http/response/parser_test.rb +105 -0
  112. data/test/http/response/status_test.rb +322 -0
  113. data/test/http/response_test.rb +502 -0
  114. data/test/http/retriable/delay_calculator_test.rb +194 -0
  115. data/test/http/retriable/errors_test.rb +71 -0
  116. data/test/http/retriable/performer_test.rb +551 -0
  117. data/test/http/session_test.rb +424 -0
  118. data/test/http/timeout/global_test.rb +239 -0
  119. data/test/http/timeout/null_test.rb +218 -0
  120. data/test/http/timeout/per_operation_test.rb +220 -0
  121. data/test/http/uri/normalizer_test.rb +89 -0
  122. data/test/http/uri_test.rb +1140 -0
  123. data/test/http/version_test.rb +15 -0
  124. data/test/http_test.rb +818 -0
  125. data/test/regression_tests.rb +27 -0
  126. data/test/support/dummy_server/encoding_routes.rb +47 -0
  127. data/test/support/dummy_server/routes.rb +201 -0
  128. data/test/support/dummy_server/servlet.rb +81 -0
  129. data/test/support/dummy_server.rb +200 -0
  130. data/{spec → test}/support/fakeio.rb +2 -2
  131. data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
  132. data/test/support/http_handling_shared/timeout_tests.rb +134 -0
  133. data/test/support/http_handling_shared.rb +11 -0
  134. data/test/support/proxy_server.rb +207 -0
  135. data/test/support/servers/runner.rb +67 -0
  136. data/{spec → test}/support/simplecov.rb +11 -2
  137. data/test/support/ssl_helper.rb +108 -0
  138. data/test/test_helper.rb +38 -0
  139. metadata +108 -168
  140. data/.github/workflows/ci.yml +0 -67
  141. data/.gitignore +0 -15
  142. data/.rspec +0 -1
  143. data/.rubocop/layout.yml +0 -8
  144. data/.rubocop/metrics.yml +0 -4
  145. data/.rubocop/rspec.yml +0 -9
  146. data/.rubocop/style.yml +0 -32
  147. data/.rubocop.yml +0 -11
  148. data/.rubocop_todo.yml +0 -219
  149. data/.yardopts +0 -2
  150. data/CHANGES_OLD.md +0 -1002
  151. data/Gemfile +0 -51
  152. data/Guardfile +0 -18
  153. data/Rakefile +0 -64
  154. data/lib/http/headers/mixin.rb +0 -34
  155. data/lib/http/retriable/client.rb +0 -37
  156. data/logo.png +0 -0
  157. data/spec/lib/http/client_spec.rb +0 -556
  158. data/spec/lib/http/connection_spec.rb +0 -88
  159. data/spec/lib/http/content_type_spec.rb +0 -47
  160. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  161. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  162. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  163. data/spec/lib/http/features/logging_spec.rb +0 -65
  164. data/spec/lib/http/features/raise_error_spec.rb +0 -62
  165. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  166. data/spec/lib/http/headers/normalizer_spec.rb +0 -52
  167. data/spec/lib/http/headers_spec.rb +0 -527
  168. data/spec/lib/http/options/body_spec.rb +0 -15
  169. data/spec/lib/http/options/features_spec.rb +0 -33
  170. data/spec/lib/http/options/form_spec.rb +0 -15
  171. data/spec/lib/http/options/headers_spec.rb +0 -24
  172. data/spec/lib/http/options/json_spec.rb +0 -15
  173. data/spec/lib/http/options/merge_spec.rb +0 -68
  174. data/spec/lib/http/options/new_spec.rb +0 -30
  175. data/spec/lib/http/options/proxy_spec.rb +0 -20
  176. data/spec/lib/http/options_spec.rb +0 -13
  177. data/spec/lib/http/redirector_spec.rb +0 -530
  178. data/spec/lib/http/request/body_spec.rb +0 -211
  179. data/spec/lib/http/request/writer_spec.rb +0 -121
  180. data/spec/lib/http/request_spec.rb +0 -234
  181. data/spec/lib/http/response/body_spec.rb +0 -85
  182. data/spec/lib/http/response/parser_spec.rb +0 -74
  183. data/spec/lib/http/response/status_spec.rb +0 -253
  184. data/spec/lib/http/response_spec.rb +0 -262
  185. data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
  186. data/spec/lib/http/retriable/performer_spec.rb +0 -302
  187. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  188. data/spec/lib/http/uri_spec.rb +0 -71
  189. data/spec/lib/http_spec.rb +0 -535
  190. data/spec/regression_specs.rb +0 -24
  191. data/spec/spec_helper.rb +0 -89
  192. data/spec/support/black_hole.rb +0 -13
  193. data/spec/support/dummy_server/servlet.rb +0 -203
  194. data/spec/support/dummy_server.rb +0 -44
  195. data/spec/support/fuubar.rb +0 -21
  196. data/spec/support/http_handling_shared.rb +0 -190
  197. data/spec/support/proxy_server.rb +0 -39
  198. data/spec/support/servers/config.rb +0 -11
  199. data/spec/support/servers/runner.rb +0 -19
  200. data/spec/support/ssl_helper.rb +0 -104
  201. /data/{spec → test}/support/capture_warning.rb +0 -0
@@ -0,0 +1,575 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class HTTPOptionsTest < Minitest::Test
6
+ cover "HTTP::Options*"
7
+
8
+ # .new
9
+
10
+ def test_new_returns_the_same_instance_when_given_an_options_object
11
+ original = HTTP::Options.new
12
+ result = HTTP::Options.new(original)
13
+
14
+ assert_same original, result
15
+ end
16
+
17
+ def test_new_does_not_treat_a_hash_as_an_options_instance
18
+ result = HTTP::Options.new(response: :body)
19
+
20
+ assert_instance_of HTTP::Options, result
21
+ end
22
+
23
+ def test_new_creates_from_a_hash_argument
24
+ result = HTTP::Options.new(response: :body)
25
+
26
+ assert_equal :body, result.response
27
+ end
28
+
29
+ def test_new_creates_from_keyword_arguments
30
+ result = HTTP::Options.new(response: :object)
31
+
32
+ assert_equal :object, result.response
33
+ end
34
+
35
+ def test_new_prefers_positional_hash_over_kwargs
36
+ result = HTTP::Options.new({ response: :body })
37
+
38
+ assert_equal :body, result.response
39
+ end
40
+
41
+ # .defined_options
42
+
43
+ def test_defined_options_returns_an_array
44
+ assert_kind_of Array, HTTP::Options.defined_options
45
+ end
46
+
47
+ def test_defined_options_contains_all_expected_option_names_as_symbols
48
+ expected = %i[
49
+ headers encoding features proxy params form json body response
50
+ socket_class nodelay ssl_socket_class ssl_context ssl
51
+ keep_alive_timeout timeout_class timeout_options
52
+ follow retriable base_uri persistent
53
+ ]
54
+
55
+ expected.each do |name|
56
+ assert_includes HTTP::Options.defined_options, name
57
+ end
58
+ end
59
+
60
+ # .register_feature
61
+
62
+ def test_register_feature_stores_the_feature_implementation_by_name
63
+ fake_feature = Class.new(HTTP::Feature)
64
+ HTTP::Options.register_feature(:test_feature_register, fake_feature)
65
+
66
+ assert_equal fake_feature, HTTP::Options.available_features[:test_feature_register]
67
+ ensure
68
+ HTTP::Options.available_features.delete(:test_feature_register)
69
+ end
70
+
71
+ # #initialize defaults
72
+
73
+ def test_initialize_defaults_response_to_auto
74
+ opts = HTTP::Options.new
75
+
76
+ assert_equal :auto, opts.response
77
+ end
78
+
79
+ def test_initialize_defaults_keep_alive_timeout_to_5
80
+ opts = HTTP::Options.new
81
+
82
+ assert_equal 5, opts.keep_alive_timeout
83
+ end
84
+
85
+ def test_initialize_defaults_nodelay_to_false
86
+ opts = HTTP::Options.new
87
+
88
+ refute opts.nodelay
89
+ end
90
+
91
+ def test_initialize_defaults_headers_to_empty
92
+ opts = HTTP::Options.new
93
+
94
+ assert_empty opts.headers
95
+ end
96
+
97
+ def test_initialize_defaults_ssl_to_empty_hash
98
+ opts = HTTP::Options.new
99
+
100
+ assert_equal({}, opts.ssl)
101
+ end
102
+
103
+ def test_initialize_defaults_timeout_options_to_empty_hash
104
+ opts = HTTP::Options.new
105
+
106
+ assert_equal({}, opts.timeout_options)
107
+ end
108
+
109
+ def test_initialize_defaults_proxy_to_empty_hash
110
+ opts = HTTP::Options.new
111
+
112
+ assert_equal({}, opts.proxy)
113
+ end
114
+
115
+ def test_initialize_defaults_features_to_empty_hash
116
+ opts = HTTP::Options.new
117
+
118
+ assert_equal({}, opts.features)
119
+ end
120
+
121
+ def test_initialize_defaults_timeout_class_to_timeout_null
122
+ opts = HTTP::Options.new
123
+
124
+ assert_equal HTTP::Timeout::Null, opts.timeout_class
125
+ end
126
+
127
+ def test_initialize_defaults_socket_class_to_tcpsocket
128
+ opts = HTTP::Options.new
129
+
130
+ assert_equal TCPSocket, opts.socket_class
131
+ end
132
+
133
+ def test_initialize_defaults_ssl_socket_class_to_openssl_ssl_sslsocket
134
+ opts = HTTP::Options.new
135
+
136
+ assert_equal OpenSSL::SSL::SSLSocket, opts.ssl_socket_class
137
+ end
138
+
139
+ def test_initialize_defaults_encoding_to_nil
140
+ opts = HTTP::Options.new
141
+
142
+ assert_nil opts.encoding
143
+ end
144
+
145
+ def test_initialize_defaults_params_to_nil
146
+ opts = HTTP::Options.new
147
+
148
+ assert_nil opts.params
149
+ end
150
+
151
+ def test_initialize_defaults_form_to_nil
152
+ opts = HTTP::Options.new
153
+
154
+ assert_nil opts.form
155
+ end
156
+
157
+ def test_initialize_defaults_json_to_nil
158
+ opts = HTTP::Options.new
159
+
160
+ assert_nil opts.json
161
+ end
162
+
163
+ def test_initialize_defaults_body_to_nil
164
+ opts = HTTP::Options.new
165
+
166
+ assert_nil opts.body
167
+ end
168
+
169
+ def test_initialize_defaults_follow_to_nil
170
+ opts = HTTP::Options.new
171
+
172
+ assert_nil opts.follow
173
+ end
174
+
175
+ def test_initialize_defaults_retriable_to_nil
176
+ opts = HTTP::Options.new
177
+
178
+ assert_nil opts.retriable
179
+ end
180
+
181
+ def test_initialize_defaults_base_uri_to_nil
182
+ opts = HTTP::Options.new
183
+
184
+ assert_nil opts.base_uri
185
+ end
186
+
187
+ def test_initialize_defaults_persistent_to_nil
188
+ opts = HTTP::Options.new
189
+
190
+ assert_nil opts.persistent
191
+ end
192
+
193
+ def test_initialize_defaults_ssl_context_to_nil
194
+ opts = HTTP::Options.new
195
+
196
+ assert_nil opts.ssl_context
197
+ end
198
+
199
+ # #to_hash
200
+
201
+ def test_to_hash_contains_all_defined_options
202
+ opts = HTTP::Options.new
203
+ hash = opts.to_hash
204
+
205
+ HTTP::Options.defined_options.each do |name|
206
+ assert_includes hash.keys, name
207
+ end
208
+ end
209
+
210
+ def test_to_hash_returns_correct_values_for_custom_options
211
+ custom = HTTP::Options.new(response: :body, keep_alive_timeout: 10)
212
+ hash = custom.to_hash
213
+
214
+ assert_equal :body, hash[:response]
215
+ assert_equal 10, hash[:keep_alive_timeout]
216
+ end
217
+
218
+ # #merge
219
+
220
+ def test_merge_merges_headers_by_combining_them
221
+ opts1 = HTTP::Options.new(headers: { foo: "bar" })
222
+ opts2 = HTTP::Options.new(headers: { baz: "qux" })
223
+ merged = opts1.merge(opts2)
224
+
225
+ assert_equal "bar", merged.headers["Foo"]
226
+ assert_equal "qux", merged.headers["Baz"]
227
+ end
228
+
229
+ def test_merge_replaces_non_header_values
230
+ opts1 = HTTP::Options.new(response: :auto)
231
+ merged = opts1.merge(response: :body)
232
+
233
+ assert_equal :body, merged.response
234
+ end
235
+
236
+ # #dup
237
+
238
+ def test_dup_returns_a_duplicate
239
+ opts = HTTP::Options.new
240
+ dupped = opts.dup
241
+
242
+ assert_equal :auto, dupped.response
243
+ end
244
+
245
+ def test_dup_yields_the_duplicate_when_a_block_is_given
246
+ opts = HTTP::Options.new
247
+ yielded = nil
248
+ dupped = opts.dup { |d| yielded = d }
249
+
250
+ assert_same dupped, yielded
251
+ end
252
+
253
+ # #feature
254
+
255
+ def test_feature_returns_nil_for_unregistered_feature
256
+ opts = HTTP::Options.new
257
+
258
+ assert_nil opts.feature(:nonexistent)
259
+ end
260
+
261
+ def test_feature_returns_the_feature_instance_for_a_registered_feature
262
+ opts = HTTP::Options.new
263
+ opts_with = opts.with_features([:auto_inflate])
264
+
265
+ assert_instance_of HTTP::Features::AutoInflate, opts_with.feature(:auto_inflate)
266
+ end
267
+
268
+ # #with_follow
269
+
270
+ def test_with_follow_sets_follow_to_empty_hash_when_true
271
+ opts = HTTP::Options.new
272
+ result = opts.with_follow(true)
273
+
274
+ assert_equal({}, result.follow)
275
+ end
276
+
277
+ def test_with_follow_sets_follow_to_nil_when_false
278
+ opts = HTTP::Options.new
279
+ result = opts.with_follow(false)
280
+
281
+ assert_nil result.follow
282
+ end
283
+
284
+ def test_with_follow_sets_follow_to_nil_when_nil
285
+ opts = HTTP::Options.new
286
+ result = opts.with_follow(nil)
287
+
288
+ assert_nil result.follow
289
+ end
290
+
291
+ def test_with_follow_passes_through_hash_options
292
+ opts = HTTP::Options.new
293
+ result = opts.with_follow(max_hops: 5)
294
+
295
+ assert_equal({ max_hops: 5 }, result.follow)
296
+ end
297
+
298
+ def test_with_follow_raises_error_for_unsupported_follow_value
299
+ opts = HTTP::Options.new
300
+ err = assert_raises(HTTP::Error) { opts.with_follow(42) }
301
+
302
+ assert_match(/Unsupported follow/, err.message)
303
+ assert_includes err.message, "42"
304
+ end
305
+
306
+ def test_with_follow_does_not_modify_original
307
+ opts = HTTP::Options.new
308
+ opts.with_follow(true)
309
+
310
+ assert_nil opts.follow
311
+ end
312
+
313
+ # #with_retriable
314
+
315
+ def test_with_retriable_sets_retriable_to_empty_hash_when_true
316
+ opts = HTTP::Options.new
317
+ result = opts.with_retriable(true)
318
+
319
+ assert_equal({}, result.retriable)
320
+ end
321
+
322
+ def test_with_retriable_sets_retriable_to_nil_when_false
323
+ opts = HTTP::Options.new
324
+ result = opts.with_retriable(false)
325
+
326
+ assert_nil result.retriable
327
+ end
328
+
329
+ def test_with_retriable_sets_retriable_to_nil_when_nil
330
+ opts = HTTP::Options.new
331
+ result = opts.with_retriable(nil)
332
+
333
+ assert_nil result.retriable
334
+ end
335
+
336
+ def test_with_retriable_passes_through_hash_options
337
+ opts = HTTP::Options.new
338
+ result = opts.with_retriable(max_retries: 3)
339
+
340
+ assert_equal({ max_retries: 3 }, result.retriable)
341
+ end
342
+
343
+ def test_with_retriable_raises_error_for_unsupported_retriable_value
344
+ opts = HTTP::Options.new
345
+ err = assert_raises(HTTP::Error) { opts.with_retriable(42) }
346
+
347
+ assert_match(/Unsupported retriable/, err.message)
348
+ assert_includes err.message, "42"
349
+ end
350
+
351
+ def test_with_retriable_does_not_modify_original
352
+ opts = HTTP::Options.new
353
+ opts.with_retriable(true)
354
+
355
+ assert_nil opts.retriable
356
+ end
357
+
358
+ # #persistent?
359
+
360
+ def test_persistent_returns_false_by_default
361
+ opts = HTTP::Options.new
362
+
363
+ refute_predicate opts, :persistent?
364
+ end
365
+
366
+ def test_persistent_returns_true_when_persistent_is_set
367
+ opts = HTTP::Options.new
368
+ result = opts.with_persistent("https://example.com")
369
+
370
+ assert_predicate result, :persistent?
371
+ end
372
+
373
+ # #with_persistent
374
+
375
+ def test_with_persistent_sets_persistent_to_origin
376
+ opts = HTTP::Options.new
377
+ result = opts.with_persistent("https://example.com/path")
378
+
379
+ assert_equal "https://example.com", result.persistent
380
+ end
381
+
382
+ def test_with_persistent_clears_persistent_when_set_to_nil
383
+ opts = HTTP::Options.new
384
+ with_persistent = opts.with_persistent("https://example.com")
385
+ result = with_persistent.with_persistent(nil)
386
+
387
+ assert_nil result.persistent
388
+ end
389
+
390
+ # #with_encoding
391
+
392
+ def test_with_encoding_finds_encoding_by_name
393
+ opts = HTTP::Options.new
394
+ result = opts.with_encoding("UTF-8")
395
+
396
+ assert_equal Encoding::UTF_8, result.encoding
397
+ end
398
+
399
+ # #features=
400
+
401
+ def test_features_accepts_pre_built_feature_instances
402
+ feature_instance = HTTP::Features::AutoInflate.new
403
+ result = HTTP::Options.new(features: { auto_inflate: feature_instance })
404
+
405
+ assert_same feature_instance, result.features[:auto_inflate]
406
+ end
407
+
408
+ def test_features_raises_for_unsupported_feature_names
409
+ err = assert_raises(HTTP::Error) { HTTP::Options.new(features: { bogus: {} }) }
410
+
411
+ assert_equal "Unsupported feature: bogus", err.message
412
+ end
413
+
414
+ # with_ methods for simple options
415
+
416
+ def test_with_proxy_returns_new_options_with_updated_proxy
417
+ opts = HTTP::Options.new
418
+ result = opts.with_proxy(proxy_address: "127.0.0.1")
419
+
420
+ assert_equal({ proxy_address: "127.0.0.1" }, result.proxy)
421
+ assert_equal({}, opts.proxy)
422
+ end
423
+
424
+ def test_with_params_returns_new_options_with_updated_params
425
+ opts = HTTP::Options.new
426
+ result = opts.with_params(foo: "bar")
427
+
428
+ assert_equal({ foo: "bar" }, result.params)
429
+ assert_nil opts.params
430
+ end
431
+
432
+ def test_with_form_returns_new_options_with_updated_form
433
+ opts = HTTP::Options.new
434
+ result = opts.with_form(foo: 42)
435
+
436
+ assert_equal({ foo: 42 }, result.form)
437
+ assert_nil opts.form
438
+ end
439
+
440
+ def test_with_json_returns_new_options_with_updated_json
441
+ opts = HTTP::Options.new
442
+ result = opts.with_json(foo: 42)
443
+
444
+ assert_equal({ foo: 42 }, result.json)
445
+ assert_nil opts.json
446
+ end
447
+
448
+ def test_with_body_returns_new_options_with_updated_body
449
+ opts = HTTP::Options.new
450
+ result = opts.with_body("data")
451
+
452
+ assert_equal "data", result.body
453
+ assert_nil opts.body
454
+ end
455
+
456
+ def test_with_response_returns_new_options_with_updated_response
457
+ opts = HTTP::Options.new
458
+ result = opts.with_response(:body)
459
+
460
+ assert_equal :body, result.response
461
+ assert_equal :auto, opts.response
462
+ end
463
+
464
+ def test_with_socket_class_returns_new_options
465
+ opts = HTTP::Options.new
466
+ custom_class = Class.new
467
+ result = opts.with_socket_class(custom_class)
468
+
469
+ assert_equal custom_class, result.socket_class
470
+ end
471
+
472
+ def test_with_nodelay_returns_new_options
473
+ opts = HTTP::Options.new
474
+ result = opts.with_nodelay(true)
475
+
476
+ assert result.nodelay
477
+ end
478
+
479
+ def test_with_ssl_socket_class_returns_new_options
480
+ opts = HTTP::Options.new
481
+ custom_class = Class.new
482
+ result = opts.with_ssl_socket_class(custom_class)
483
+
484
+ assert_equal custom_class, result.ssl_socket_class
485
+ end
486
+
487
+ def test_with_ssl_context_returns_new_options
488
+ opts = HTTP::Options.new
489
+ ctx = OpenSSL::SSL::SSLContext.new
490
+ result = opts.with_ssl_context(ctx)
491
+
492
+ assert_equal ctx, result.ssl_context
493
+ end
494
+
495
+ def test_with_ssl_returns_new_options
496
+ opts = HTTP::Options.new
497
+ result = opts.with_ssl(verify_mode: OpenSSL::SSL::VERIFY_NONE)
498
+
499
+ assert_equal({ verify_mode: OpenSSL::SSL::VERIFY_NONE }, result.ssl)
500
+ end
501
+
502
+ def test_with_keep_alive_timeout_returns_new_options
503
+ opts = HTTP::Options.new
504
+ result = opts.with_keep_alive_timeout(10)
505
+
506
+ assert_equal 10, result.keep_alive_timeout
507
+ end
508
+
509
+ def test_with_timeout_class_returns_new_options
510
+ opts = HTTP::Options.new
511
+ custom_class = Class.new
512
+ result = opts.with_timeout_class(custom_class)
513
+
514
+ assert_equal custom_class, result.timeout_class
515
+ end
516
+
517
+ def test_with_timeout_options_returns_new_options
518
+ opts = HTTP::Options.new
519
+ result = opts.with_timeout_options(read_timeout: 5)
520
+
521
+ assert_equal({ read_timeout: 5 }, result.timeout_options)
522
+ end
523
+
524
+ # #argument_error! backtrace
525
+
526
+ def test_argument_error_excludes_argument_error_from_the_backtrace
527
+ opts = HTTP::Options.new
528
+ err = assert_raises(HTTP::Error) { opts.with_follow(42) }
529
+
530
+ refute err.backtrace.any? { |line| line.include?("argument_error!") },
531
+ "backtrace should not include argument_error! method"
532
+ end
533
+
534
+ def test_argument_error_starts_the_backtrace_at_the_calling_setter_method
535
+ opts = HTTP::Options.new
536
+ err = assert_raises(HTTP::Error) { opts.with_follow(42) }
537
+
538
+ assert_includes err.backtrace.first, "definitions.rb"
539
+ end
540
+
541
+ def test_argument_error_includes_more_than_one_backtrace_frame
542
+ opts = HTTP::Options.new
543
+ err = assert_raises(HTTP::Error) { opts.with_follow(42) }
544
+
545
+ assert_operator err.backtrace.length, :>, 1
546
+ end
547
+
548
+ def test_argument_error_preserves_the_full_backtrace_down_to_the_bottom_of_the_stack
549
+ opts = HTTP::Options.new
550
+ ref_err = begin; raise HTTP::Error, "ref"; rescue HTTP::Error => e; e; end
551
+ arg_err = assert_raises(HTTP::Error) { opts.with_follow(42) }
552
+
553
+ assert_equal ref_err.backtrace.last, arg_err.backtrace.last
554
+ end
555
+
556
+ # non-reader_only options have protected writers
557
+
558
+ def test_response_writer_is_protected
559
+ opts = HTTP::Options.new
560
+
561
+ assert_raises(NoMethodError) { opts.response = :body }
562
+ end
563
+
564
+ def test_proxy_writer_is_protected
565
+ opts = HTTP::Options.new
566
+
567
+ assert_raises(NoMethodError) { opts.proxy = {} }
568
+ end
569
+
570
+ def test_keep_alive_timeout_writer_is_protected
571
+ opts = HTTP::Options.new
572
+
573
+ assert_raises(NoMethodError) { opts.keep_alive_timeout = 10 }
574
+ end
575
+ end