faraday 0.17.4 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +156 -8
  3. data/LICENSE.md +1 -1
  4. data/README.md +16 -358
  5. data/Rakefile +1 -7
  6. data/examples/client_spec.rb +97 -0
  7. data/examples/client_test.rb +118 -0
  8. data/lib/faraday/adapter/test.rb +118 -69
  9. data/lib/faraday/adapter/typhoeus.rb +4 -1
  10. data/lib/faraday/adapter.rb +72 -22
  11. data/lib/faraday/adapter_registry.rb +30 -0
  12. data/lib/faraday/autoload.rb +39 -36
  13. data/lib/faraday/connection.rb +343 -185
  14. data/lib/faraday/dependency_loader.rb +37 -0
  15. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  16. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  17. data/lib/faraday/error.rb +29 -35
  18. data/lib/faraday/file_part.rb +128 -0
  19. data/lib/faraday/logging/formatter.rb +105 -0
  20. data/lib/faraday/methods.rb +6 -0
  21. data/lib/faraday/middleware.rb +19 -25
  22. data/lib/faraday/middleware_registry.rb +129 -0
  23. data/lib/faraday/options/connection_options.rb +22 -0
  24. data/lib/faraday/options/env.rb +181 -0
  25. data/lib/faraday/options/proxy_options.rb +32 -0
  26. data/lib/faraday/options/request_options.rb +22 -0
  27. data/lib/faraday/options/ssl_options.rb +59 -0
  28. data/lib/faraday/options.rb +36 -191
  29. data/lib/faraday/param_part.rb +53 -0
  30. data/lib/faraday/parameters.rb +4 -197
  31. data/lib/faraday/rack_builder.rb +76 -64
  32. data/lib/faraday/request/authorization.rb +51 -30
  33. data/lib/faraday/request/basic_authentication.rb +14 -7
  34. data/lib/faraday/request/instrumentation.rb +45 -27
  35. data/lib/faraday/request/multipart.rb +86 -48
  36. data/lib/faraday/request/retry.rb +197 -171
  37. data/lib/faraday/request/token_authentication.rb +15 -10
  38. data/lib/faraday/request/url_encoded.rb +43 -23
  39. data/lib/faraday/request.rb +86 -44
  40. data/lib/faraday/response/logger.rb +22 -69
  41. data/lib/faraday/response/raise_error.rb +49 -18
  42. data/lib/faraday/response.rb +24 -20
  43. data/lib/faraday/utils/headers.rb +139 -0
  44. data/lib/faraday/utils/params_hash.rb +61 -0
  45. data/lib/faraday/utils.rb +38 -247
  46. data/lib/faraday/version.rb +5 -0
  47. data/lib/faraday.rb +127 -189
  48. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  49. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  50. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  51. data/spec/faraday/adapter/excon_spec.rb +49 -0
  52. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  53. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  54. data/spec/faraday/adapter/patron_spec.rb +18 -0
  55. data/spec/faraday/adapter/rack_spec.rb +8 -0
  56. data/spec/faraday/adapter/test_spec.rb +377 -0
  57. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  58. data/spec/faraday/adapter_registry_spec.rb +28 -0
  59. data/spec/faraday/adapter_spec.rb +55 -0
  60. data/spec/faraday/composite_read_io_spec.rb +80 -0
  61. data/spec/faraday/connection_spec.rb +736 -0
  62. data/spec/faraday/error_spec.rb +12 -54
  63. data/spec/faraday/middleware_spec.rb +52 -0
  64. data/spec/faraday/options/env_spec.rb +70 -0
  65. data/spec/faraday/options/options_spec.rb +297 -0
  66. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  67. data/spec/faraday/options/request_options_spec.rb +19 -0
  68. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  69. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  70. data/spec/faraday/rack_builder_spec.rb +345 -0
  71. data/spec/faraday/request/authorization_spec.rb +96 -0
  72. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  73. data/spec/faraday/request/multipart_spec.rb +302 -0
  74. data/spec/faraday/request/retry_spec.rb +242 -0
  75. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  76. data/spec/faraday/request_spec.rb +120 -0
  77. data/spec/faraday/response/logger_spec.rb +220 -0
  78. data/spec/faraday/response/middleware_spec.rb +68 -0
  79. data/spec/faraday/response/raise_error_spec.rb +78 -15
  80. data/spec/faraday/response_spec.rb +75 -0
  81. data/spec/faraday/utils/headers_spec.rb +82 -0
  82. data/spec/faraday/utils_spec.rb +56 -0
  83. data/spec/faraday_spec.rb +37 -0
  84. data/spec/spec_helper.rb +63 -36
  85. data/spec/support/disabling_stub.rb +14 -0
  86. data/spec/support/fake_safe_buffer.rb +15 -0
  87. data/spec/support/helper_methods.rb +133 -0
  88. data/spec/support/shared_examples/adapter.rb +105 -0
  89. data/spec/support/shared_examples/params_encoder.rb +18 -0
  90. data/spec/support/shared_examples/request_method.rb +262 -0
  91. data/spec/support/streaming_response_checker.rb +35 -0
  92. data/spec/support/webmock_rack_app.rb +68 -0
  93. metadata +194 -48
  94. data/lib/faraday/adapter/em_http.rb +0 -243
  95. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  96. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  97. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  98. data/lib/faraday/adapter/excon.rb +0 -82
  99. data/lib/faraday/adapter/httpclient.rb +0 -128
  100. data/lib/faraday/adapter/net_http.rb +0 -153
  101. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  102. data/lib/faraday/adapter/patron.rb +0 -95
  103. data/lib/faraday/adapter/rack.rb +0 -58
  104. data/lib/faraday/deprecate.rb +0 -109
  105. data/lib/faraday/upload_io.rb +0 -67
  106. data/spec/faraday/deprecate_spec.rb +0 -147
  107. data/test/adapters/default_test.rb +0 -14
  108. data/test/adapters/em_http_test.rb +0 -30
  109. data/test/adapters/em_synchrony_test.rb +0 -32
  110. data/test/adapters/excon_test.rb +0 -30
  111. data/test/adapters/httpclient_test.rb +0 -34
  112. data/test/adapters/integration.rb +0 -263
  113. data/test/adapters/logger_test.rb +0 -136
  114. data/test/adapters/net_http_persistent_test.rb +0 -114
  115. data/test/adapters/net_http_test.rb +0 -79
  116. data/test/adapters/patron_test.rb +0 -40
  117. data/test/adapters/rack_test.rb +0 -38
  118. data/test/adapters/test_middleware_test.rb +0 -157
  119. data/test/adapters/typhoeus_test.rb +0 -38
  120. data/test/authentication_middleware_test.rb +0 -65
  121. data/test/composite_read_io_test.rb +0 -109
  122. data/test/connection_test.rb +0 -738
  123. data/test/env_test.rb +0 -268
  124. data/test/helper.rb +0 -75
  125. data/test/live_server.rb +0 -67
  126. data/test/middleware/instrumentation_test.rb +0 -88
  127. data/test/middleware/retry_test.rb +0 -282
  128. data/test/middleware_stack_test.rb +0 -260
  129. data/test/multibyte.txt +0 -1
  130. data/test/options_test.rb +0 -333
  131. data/test/parameters_test.rb +0 -157
  132. data/test/request_middleware_test.rb +0 -126
  133. data/test/response_middleware_test.rb +0 -72
  134. data/test/strawberry.rb +0 -2
  135. data/test/utils_test.rb +0 -98
@@ -0,0 +1,377 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::Test do
4
+ let(:stubs) do
5
+ described_class::Stubs.new do |stub|
6
+ stub.get('http://domain.test/hello') do
7
+ [200, { 'Content-Type' => 'text/html' }, 'domain: hello']
8
+ end
9
+
10
+ stub.get('http://wrong.test/hello') do
11
+ [200, { 'Content-Type' => 'text/html' }, 'wrong: hello']
12
+ end
13
+
14
+ stub.get('http://wrong.test/bait') do
15
+ [404, { 'Content-Type' => 'text/html' }]
16
+ end
17
+
18
+ stub.get('/hello') do
19
+ [200, { 'Content-Type' => 'text/html' }, 'hello']
20
+ end
21
+
22
+ stub.get('/method-echo') do |env|
23
+ [200, { 'Content-Type' => 'text/html' }, env[:method].to_s]
24
+ end
25
+
26
+ stub.get(%r{\A/resources/\d+(?:\?|\z)}) do
27
+ [200, { 'Content-Type' => 'text/html' }, 'show']
28
+ end
29
+
30
+ stub.get(%r{\A/resources/(specified)\z}) do |_env, meta|
31
+ [200, { 'Content-Type' => 'text/html' }, "show #{meta[:match_data][1]}"]
32
+ end
33
+ end
34
+ end
35
+
36
+ let(:connection) do
37
+ Faraday.new do |builder|
38
+ builder.adapter :test, stubs
39
+ end
40
+ end
41
+
42
+ let(:response) { connection.get('/hello') }
43
+
44
+ context 'with simple path sets status' do
45
+ subject { response.status }
46
+
47
+ it { is_expected.to eq 200 }
48
+ end
49
+
50
+ context 'with simple path sets headers' do
51
+ subject { response.headers['Content-Type'] }
52
+
53
+ it { is_expected.to eq 'text/html' }
54
+ end
55
+
56
+ context 'with simple path sets body' do
57
+ subject { response.body }
58
+
59
+ it { is_expected.to eq 'hello' }
60
+ end
61
+
62
+ context 'with host points to the right stub' do
63
+ subject { connection.get('http://domain.test/hello').body }
64
+
65
+ it { is_expected.to eq 'domain: hello' }
66
+ end
67
+
68
+ describe 'can be called several times' do
69
+ subject { connection.get('/hello').body }
70
+
71
+ it { is_expected.to eq 'hello' }
72
+ end
73
+
74
+ describe 'can handle regular expression path' do
75
+ subject { connection.get('/resources/1').body }
76
+
77
+ it { is_expected.to eq 'show' }
78
+ end
79
+
80
+ describe 'can handle single parameter block' do
81
+ subject { connection.get('/method-echo').body }
82
+
83
+ it { is_expected.to eq 'get' }
84
+ end
85
+
86
+ describe 'can handle regular expression path with captured result' do
87
+ subject { connection.get('/resources/specified').body }
88
+
89
+ it { is_expected.to eq 'show specified' }
90
+ end
91
+
92
+ context 'with get params' do
93
+ subject { connection.get('/param?a=1').body }
94
+
95
+ before do
96
+ stubs.get('/param?a=1') { [200, {}, 'a'] }
97
+ end
98
+
99
+ it { is_expected.to eq 'a' }
100
+ end
101
+
102
+ describe 'ignoring unspecified get params' do
103
+ before do
104
+ stubs.get('/optional?a=1') { [200, {}, 'a'] }
105
+ end
106
+
107
+ context 'with multiple params' do
108
+ subject { connection.get('/optional?a=1&b=1').body }
109
+
110
+ it { is_expected.to eq 'a' }
111
+ end
112
+
113
+ context 'with single param' do
114
+ subject { connection.get('/optional?a=1').body }
115
+
116
+ it { is_expected.to eq 'a' }
117
+ end
118
+
119
+ context 'without params' do
120
+ subject(:request) { connection.get('/optional') }
121
+
122
+ it do
123
+ expect { request }.to raise_error(
124
+ Faraday::Adapter::Test::Stubs::NotFound
125
+ )
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'with http headers' do
131
+ before do
132
+ stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
133
+ stubs.get('/yo') { [200, {}, 'b'] }
134
+ end
135
+
136
+ context 'with header' do
137
+ subject do
138
+ connection.get('/yo') { |env| env.headers['X-HELLO'] = 'hello' }.body
139
+ end
140
+
141
+ it { is_expected.to eq 'a' }
142
+ end
143
+
144
+ context 'without header' do
145
+ subject do
146
+ connection.get('/yo').body
147
+ end
148
+
149
+ it { is_expected.to eq 'b' }
150
+ end
151
+ end
152
+
153
+ describe 'different outcomes for the same request' do
154
+ def make_request
155
+ connection.get('/foo')
156
+ end
157
+
158
+ subject(:request) { make_request.body }
159
+
160
+ before do
161
+ stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
162
+ stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'world'] }
163
+ end
164
+
165
+ context 'the first request' do
166
+ it { is_expected.to eq 'hello' }
167
+ end
168
+
169
+ context 'the second request' do
170
+ before do
171
+ make_request
172
+ end
173
+
174
+ it { is_expected.to eq 'world' }
175
+ end
176
+ end
177
+
178
+ describe 'yielding env to stubs' do
179
+ subject { connection.get('http://foo.com/foo?a=1').body }
180
+
181
+ before do
182
+ stubs.get '/foo' do |env|
183
+ expect(env[:url].path).to eq '/foo'
184
+ expect(env[:url].host).to eq 'foo.com'
185
+ expect(env[:params]['a']).to eq '1'
186
+ expect(env[:request_headers]['Accept']).to eq 'text/plain'
187
+ [200, {}, 'a']
188
+ end
189
+
190
+ connection.headers['Accept'] = 'text/plain'
191
+ end
192
+
193
+ it { is_expected.to eq 'a' }
194
+ end
195
+
196
+ describe 'params parsing' do
197
+ subject { connection.get('http://foo.com/foo?a[b]=1').body }
198
+
199
+ context 'with default encoder' do
200
+ before do
201
+ stubs.get '/foo' do |env|
202
+ expect(env[:params]['a']['b']).to eq '1'
203
+ [200, {}, 'a']
204
+ end
205
+ end
206
+
207
+ it { is_expected.to eq 'a' }
208
+ end
209
+
210
+ context 'with nested encoder' do
211
+ before do
212
+ stubs.get '/foo' do |env|
213
+ expect(env[:params]['a']['b']).to eq '1'
214
+ [200, {}, 'a']
215
+ end
216
+
217
+ connection.options.params_encoder = Faraday::NestedParamsEncoder
218
+ end
219
+
220
+ it { is_expected.to eq 'a' }
221
+ end
222
+
223
+ context 'with flat encoder' do
224
+ before do
225
+ stubs.get '/foo' do |env|
226
+ expect(env[:params]['a[b]']).to eq '1'
227
+ [200, {}, 'a']
228
+ end
229
+
230
+ connection.options.params_encoder = Faraday::FlatParamsEncoder
231
+ end
232
+
233
+ it { is_expected.to eq 'a' }
234
+ end
235
+ end
236
+
237
+ describe 'raising an error if no stub was found' do
238
+ describe 'for request' do
239
+ subject(:request) { connection.get('/invalid') { [200, {}, []] } }
240
+
241
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
242
+ end
243
+
244
+ describe 'for specified host' do
245
+ subject(:request) { connection.get('http://domain.test/bait') }
246
+
247
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
248
+ end
249
+
250
+ describe 'for request without specified header' do
251
+ subject(:request) { connection.get('/yo') }
252
+
253
+ before do
254
+ stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
255
+ end
256
+
257
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
258
+ end
259
+ end
260
+
261
+ describe 'for request with non default params encoder' do
262
+ let(:connection) do
263
+ Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
264
+ builder.adapter :test, stubs
265
+ end
266
+ end
267
+ let(:stubs) do
268
+ described_class::Stubs.new do |stubs|
269
+ stubs.get('/path?a=x&a=y&a=z') { [200, {}, 'a'] }
270
+ end
271
+ end
272
+
273
+ context 'when all flat param values are correctly set' do
274
+ subject(:request) { connection.get('/path?a=x&a=y&a=z') }
275
+
276
+ it { expect(request.status).to eq 200 }
277
+ end
278
+
279
+ shared_examples 'raise NotFound when params do not satisfy the flat param values' do |params|
280
+ subject(:request) { connection.get('/path', params) }
281
+
282
+ context "with #{params.inspect}" do
283
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
284
+ end
285
+ end
286
+
287
+ it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x] }
288
+ it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x y] }
289
+ it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x z y] } # NOTE: The order of the value is also compared.
290
+ it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { b: %w[x y z] }
291
+ end
292
+
293
+ describe 'strict_mode' do
294
+ let(:stubs) do
295
+ described_class::Stubs.new(strict_mode: true) do |stubs|
296
+ stubs.get('/strict?a=12&b=xy', 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello') { [200, {}, 'a'] }
297
+ stubs.get('/with_user_agent?a=12&b=xy', authorization: 'Bearer m_ck', 'User-Agent' => 'My Agent') { [200, {}, 'a'] }
298
+ end
299
+ end
300
+
301
+ context 'when params and headers are exactly set' do
302
+ subject(:request) { connection.get('/strict', { a: '12', b: 'xy' }, { authorization: 'Bearer m_ck', x_c: 'hello' }) }
303
+
304
+ it { expect(request.status).to eq 200 }
305
+ end
306
+
307
+ context 'when params and headers are exactly set with a custom user agent' do
308
+ subject(:request) { connection.get('/with_user_agent', { a: '12', b: 'xy' }, { authorization: 'Bearer m_ck', 'User-Agent' => 'My Agent' }) }
309
+
310
+ it { expect(request.status).to eq 200 }
311
+ end
312
+
313
+ shared_examples 'raise NotFound when params do not satisfy the strict check' do |params|
314
+ subject(:request) { connection.get('/strict', params, { 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello' }) }
315
+
316
+ context "with #{params.inspect}" do
317
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
318
+ end
319
+ end
320
+
321
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12' }
322
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { b: 'xy' }
323
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '123', b: 'xy' }
324
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12', b: 'xyz' }
325
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { a: '12', b: 'xy', c: 'hello' }
326
+ it_behaves_like 'raise NotFound when params do not satisfy the strict check', { additional: 'special', a: '12', b: 'xy', c: 'hello' }
327
+
328
+ shared_examples 'raise NotFound when headers do not satisfy the strict check' do |path, headers|
329
+ subject(:request) { connection.get(path, { a: 12, b: 'xy' }, headers) }
330
+
331
+ context "with #{headers.inspect}" do
332
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
333
+ end
334
+ end
335
+
336
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck' }
337
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { 'X-C' => 'hello' }
338
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'Hi' }
339
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Basic m_ck', 'x-c': 'hello' }
340
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', x_special: 'special' }
341
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck' }
342
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'Unknown' }
343
+ it_behaves_like 'raise NotFound when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' }
344
+
345
+ context 'when strict_mode is disabled' do
346
+ before do
347
+ stubs.strict_mode = false
348
+ end
349
+
350
+ shared_examples 'does not raise NotFound even when params do not satisfy the strict check' do |params|
351
+ subject(:request) { connection.get('/strict', params, { 'Authorization' => 'Bearer m_ck', 'X-C' => 'hello' }) }
352
+
353
+ context "with #{params.inspect}" do
354
+ it { expect(request.status).to eq 200 }
355
+ end
356
+ end
357
+
358
+ it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { a: '12', b: 'xy' }
359
+ it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { a: '12', b: 'xy', c: 'hello' }
360
+ it_behaves_like 'does not raise NotFound even when params do not satisfy the strict check', { additional: 'special', a: '12', b: 'xy', c: 'hello' }
361
+
362
+ shared_examples 'does not raise NotFound even when headers do not satisfy the strict check' do |path, headers|
363
+ subject(:request) { connection.get(path, { a: 12, b: 'xy' }, headers) }
364
+
365
+ context "with #{headers.inspect}" do
366
+ it { expect(request.status).to eq 200 }
367
+ end
368
+ end
369
+
370
+ it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello' }
371
+ it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', x_special: 'special' }
372
+ it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/strict', { authorization: 'Bearer m_ck', 'x-c': 'hello', user_agent: 'Special Agent' }
373
+ it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent' }
374
+ it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' }
375
+ end
376
+ end
377
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::Typhoeus do
4
+ features :request_body_on_query_methods, :parallel, :trace_method
5
+
6
+ it_behaves_like 'an adapter'
7
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::AdapterRegistry do
4
+ describe '#initialize' do
5
+ subject(:registry) { described_class.new }
6
+
7
+ it { expect { registry.get(:FinFangFoom) }.to raise_error(NameError) }
8
+ it { expect { registry.get('FinFangFoom') }.to raise_error(NameError) }
9
+
10
+ it 'looks up class by string name' do
11
+ expect(registry.get('Faraday::Connection')).to eq(Faraday::Connection)
12
+ end
13
+
14
+ it 'looks up class by symbol name' do
15
+ expect(registry.get(:Faraday)).to eq(Faraday)
16
+ end
17
+
18
+ it 'caches lookups with implicit name' do
19
+ registry.set :symbol
20
+ expect(registry.get('symbol')).to eq(:symbol)
21
+ end
22
+
23
+ it 'caches lookups with explicit name' do
24
+ registry.set 'string', :name
25
+ expect(registry.get(:name)).to eq('string')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter do
4
+ let(:adapter) { Faraday::Adapter.new }
5
+ let(:request) { {} }
6
+
7
+ context '#request_timeout' do
8
+ it 'gets :read timeout' do
9
+ expect(timeout(:read)).to eq(nil)
10
+
11
+ request[:timeout] = 5
12
+ request[:write_timeout] = 1
13
+
14
+ expect(timeout(:read)).to eq(5)
15
+
16
+ request[:read_timeout] = 2
17
+
18
+ expect(timeout(:read)).to eq(2)
19
+ end
20
+
21
+ it 'gets :open timeout' do
22
+ expect(timeout(:open)).to eq(nil)
23
+
24
+ request[:timeout] = 5
25
+ request[:write_timeout] = 1
26
+
27
+ expect(timeout(:open)).to eq(5)
28
+
29
+ request[:open_timeout] = 2
30
+
31
+ expect(timeout(:open)).to eq(2)
32
+ end
33
+
34
+ it 'gets :write timeout' do
35
+ expect(timeout(:write)).to eq(nil)
36
+
37
+ request[:timeout] = 5
38
+ request[:read_timeout] = 1
39
+
40
+ expect(timeout(:write)).to eq(5)
41
+
42
+ request[:write_timeout] = 2
43
+
44
+ expect(timeout(:write)).to eq(2)
45
+ end
46
+
47
+ it 'attempts unknown timeout type' do
48
+ expect { timeout(:unknown) }.to raise_error(ArgumentError)
49
+ end
50
+
51
+ def timeout(type)
52
+ adapter.send(:request_timeout, type, request)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ RSpec.describe Faraday::CompositeReadIO do
6
+ Part = Struct.new(:to_io) do
7
+ def length
8
+ to_io.string.length
9
+ end
10
+ end
11
+
12
+ def part(str)
13
+ Part.new StringIO.new(str)
14
+ end
15
+
16
+ def composite_io(*parts)
17
+ Faraday::CompositeReadIO.new(*parts)
18
+ end
19
+
20
+ context 'with empty composite_io' do
21
+ subject { composite_io }
22
+
23
+ it { expect(subject.length).to eq(0) }
24
+ it { expect(subject.read).to eq('') }
25
+ it { expect(subject.read(1)).to be_nil }
26
+ end
27
+
28
+ context 'with empty parts' do
29
+ subject { composite_io(part(''), part('')) }
30
+
31
+ it { expect(subject.length).to eq(0) }
32
+ it { expect(subject.read).to eq('') }
33
+ it { expect(subject.read(1)).to be_nil }
34
+ end
35
+
36
+ context 'with 2 parts' do
37
+ subject { composite_io(part('abcd'), part('1234')) }
38
+
39
+ it { expect(subject.length).to eq(8) }
40
+ it { expect(subject.read).to eq('abcd1234') }
41
+ it 'allows to read in chunks' do
42
+ expect(subject.read(3)).to eq('abc')
43
+ expect(subject.read(3)).to eq('d12')
44
+ expect(subject.read(3)).to eq('34')
45
+ expect(subject.read(3)).to be_nil
46
+ end
47
+ it 'allows to rewind while reading in chunks' do
48
+ expect(subject.read(3)).to eq('abc')
49
+ expect(subject.read(3)).to eq('d12')
50
+ subject.rewind
51
+ expect(subject.read(3)).to eq('abc')
52
+ expect(subject.read(5)).to eq('d1234')
53
+ expect(subject.read(3)).to be_nil
54
+ subject.rewind
55
+ expect(subject.read(2)).to eq('ab')
56
+ end
57
+ end
58
+
59
+ context 'with mix of empty and non-empty parts' do
60
+ subject { composite_io(part(''), part('abcd'), part(''), part('1234'), part('')) }
61
+
62
+ it 'allows to read in chunks' do
63
+ expect(subject.read(6)).to eq('abcd12')
64
+ expect(subject.read(6)).to eq('34')
65
+ expect(subject.read(6)).to be_nil
66
+ end
67
+ end
68
+
69
+ context 'with utf8 multibyte part' do
70
+ subject { composite_io(part("\x86"), part('ファイル')) }
71
+
72
+ it { expect(subject.read).to eq(String.new("\x86\xE3\x83\x95\xE3\x82\xA1\xE3\x82\xA4\xE3\x83\xAB", encoding: 'BINARY')) }
73
+ it 'allows to read in chunks' do
74
+ expect(subject.read(3)).to eq(String.new("\x86\xE3\x83", encoding: 'BINARY'))
75
+ expect(subject.read(3)).to eq(String.new("\x95\xE3\x82", encoding: 'BINARY'))
76
+ expect(subject.read(8)).to eq(String.new("\xA1\xE3\x82\xA4\xE3\x83\xAB", encoding: 'BINARY'))
77
+ expect(subject.read(3)).to be_nil
78
+ end
79
+ end
80
+ end