faraday 1.0.0 → 2.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +19 -14
  5. data/examples/client_spec.rb +36 -4
  6. data/examples/client_test.rb +43 -4
  7. data/lib/faraday/adapter/test.rb +61 -43
  8. data/lib/faraday/adapter.rb +3 -16
  9. data/lib/faraday/adapter_registry.rb +3 -1
  10. data/lib/faraday/connection.rb +25 -78
  11. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  12. data/lib/faraday/encoders/nested_params_encoder.rb +9 -4
  13. data/lib/faraday/error.rb +23 -8
  14. data/lib/faraday/logging/formatter.rb +1 -0
  15. data/lib/faraday/methods.rb +6 -0
  16. data/lib/faraday/middleware.rb +14 -5
  17. data/lib/faraday/middleware_registry.rb +15 -79
  18. data/lib/faraday/options/proxy_options.rb +4 -0
  19. data/lib/faraday/options.rb +7 -11
  20. data/lib/faraday/rack_builder.rb +34 -30
  21. data/lib/faraday/request/authorization.rb +32 -36
  22. data/lib/faraday/request/instrumentation.rb +2 -0
  23. data/lib/faraday/request/json.rb +55 -0
  24. data/lib/faraday/request/url_encoded.rb +5 -1
  25. data/lib/faraday/request.rb +13 -23
  26. data/lib/faraday/response/json.rb +54 -0
  27. data/lib/faraday/response/logger.rb +4 -4
  28. data/lib/faraday/response/raise_error.rb +20 -1
  29. data/lib/faraday/response.rb +8 -22
  30. data/lib/faraday/utils/headers.rb +3 -3
  31. data/lib/faraday/utils.rb +21 -8
  32. data/lib/faraday/version.rb +5 -0
  33. data/lib/faraday.rb +44 -59
  34. data/spec/faraday/adapter/test_spec.rb +377 -0
  35. data/spec/faraday/connection_spec.rb +147 -51
  36. data/spec/faraday/error_spec.rb +15 -0
  37. data/spec/faraday/middleware_spec.rb +32 -6
  38. data/spec/faraday/options/env_spec.rb +2 -2
  39. data/spec/faraday/options/proxy_options_spec.rb +7 -0
  40. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  41. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  42. data/spec/faraday/rack_builder_spec.rb +144 -38
  43. data/spec/faraday/request/authorization_spec.rb +19 -24
  44. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  45. data/spec/faraday/request/json_spec.rb +111 -0
  46. data/spec/faraday/request/url_encoded_spec.rb +13 -1
  47. data/spec/faraday/request_spec.rb +6 -6
  48. data/spec/faraday/response/json_spec.rb +117 -0
  49. data/spec/faraday/response/raise_error_spec.rb +66 -0
  50. data/spec/faraday/utils_spec.rb +62 -1
  51. data/spec/support/fake_safe_buffer.rb +1 -1
  52. data/spec/support/helper_methods.rb +0 -37
  53. data/spec/support/shared_examples/adapter.rb +2 -2
  54. data/spec/support/shared_examples/request_method.rb +43 -28
  55. metadata +16 -48
  56. data/UPGRADING.md +0 -55
  57. data/lib/faraday/adapter/em_http.rb +0 -285
  58. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  59. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  60. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  61. data/lib/faraday/adapter/excon.rb +0 -124
  62. data/lib/faraday/adapter/httpclient.rb +0 -151
  63. data/lib/faraday/adapter/net_http.rb +0 -209
  64. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  65. data/lib/faraday/adapter/patron.rb +0 -132
  66. data/lib/faraday/adapter/rack.rb +0 -75
  67. data/lib/faraday/adapter/typhoeus.rb +0 -15
  68. data/lib/faraday/autoload.rb +0 -95
  69. data/lib/faraday/dependency_loader.rb +0 -37
  70. data/lib/faraday/file_part.rb +0 -128
  71. data/lib/faraday/param_part.rb +0 -53
  72. data/lib/faraday/request/basic_authentication.rb +0 -20
  73. data/lib/faraday/request/multipart.rb +0 -99
  74. data/lib/faraday/request/retry.rb +0 -239
  75. data/lib/faraday/request/token_authentication.rb +0 -20
  76. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  77. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  78. data/spec/faraday/adapter/excon_spec.rb +0 -49
  79. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  80. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  81. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  82. data/spec/faraday/adapter/patron_spec.rb +0 -18
  83. data/spec/faraday/adapter/rack_spec.rb +0 -8
  84. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  85. data/spec/faraday/composite_read_io_spec.rb +0 -80
  86. data/spec/faraday/request/multipart_spec.rb +0 -274
  87. data/spec/faraday/request/retry_spec.rb +0 -242
  88. data/spec/faraday/response/middleware_spec.rb +0 -52
  89. data/spec/support/webmock_rack_app.rb +0 -68
@@ -1,274 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Request::Multipart do
4
- let(:conn) do
5
- Faraday.new do |b|
6
- b.request :multipart
7
- b.request :url_encoded
8
- b.adapter :test do |stub|
9
- stub.post('/echo') do |env|
10
- posted_as = env[:request_headers]['Content-Type']
11
- expect(env[:body]).to be_a_kind_of(Faraday::CompositeReadIO)
12
- [200, { 'Content-Type' => posted_as }, env[:body].read]
13
- end
14
- end
15
- end
16
- end
17
-
18
- shared_examples 'a multipart request' do
19
- it 'generates a unique boundary for each request' do
20
- response1 = conn.post('/echo', payload)
21
- response2 = conn.post('/echo', payload)
22
-
23
- b1 = parse_multipart_boundary(response1.headers['Content-Type'])
24
- b2 = parse_multipart_boundary(response2.headers['Content-Type'])
25
- expect(b1).to_not eq(b2)
26
- end
27
- end
28
-
29
- context 'FilePart: when multipart objects in param' do
30
- let(:payload) do
31
- {
32
- a: 1,
33
- b: {
34
- c: Faraday::FilePart.new(__FILE__, 'text/x-ruby', nil,
35
- 'Content-Disposition' => 'form-data; foo=1'),
36
- d: 2
37
- }
38
- }
39
- end
40
- it_behaves_like 'a multipart request'
41
-
42
- it 'forms a multipart request' do
43
- response = conn.post('/echo', payload)
44
-
45
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
46
- result = parse_multipart(boundary, response.body)
47
- expect(result[:errors]).to be_empty
48
-
49
- part_a, body_a = result.part('a')
50
- expect(part_a).to_not be_nil
51
- expect(part_a.filename).to be_nil
52
- expect(body_a).to eq('1')
53
-
54
- part_bc, body_bc = result.part('b[c]')
55
- expect(part_bc).to_not be_nil
56
- expect(part_bc.filename).to eq('multipart_spec.rb')
57
- expect(part_bc.headers['content-disposition']).to eq(
58
- 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
59
- )
60
- expect(part_bc.headers['content-type']).to eq('text/x-ruby')
61
- expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
62
- expect(body_bc).to eq(File.read(__FILE__))
63
-
64
- part_bd, body_bd = result.part('b[d]')
65
- expect(part_bd).to_not be_nil
66
- expect(part_bd.filename).to be_nil
67
- expect(body_bd).to eq('2')
68
- end
69
- end
70
-
71
- context 'FilePart: when providing json and IO content in the same payload' do
72
- let(:io) { StringIO.new('io-content') }
73
- let(:json) do
74
- {
75
- b: 1,
76
- c: 2
77
- }.to_json
78
- end
79
-
80
- let(:payload) do
81
- {
82
- json: Faraday::ParamPart.new(json, 'application/json'),
83
- io: Faraday::FilePart.new(io, 'application/pdf')
84
- }
85
- end
86
-
87
- it_behaves_like 'a multipart request'
88
-
89
- it 'forms a multipart request' do
90
- response = conn.post('/echo', payload)
91
-
92
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
93
- result = parse_multipart(boundary, response.body)
94
- expect(result[:errors]).to be_empty
95
-
96
- part_json, body_json = result.part('json')
97
- expect(part_json).to_not be_nil
98
- expect(part_json.mime).to eq('application/json')
99
- expect(part_json.filename).to be_nil
100
- expect(body_json).to eq(json)
101
-
102
- part_io, body_io = result.part('io')
103
- expect(part_io).to_not be_nil
104
- expect(part_io.mime).to eq('application/pdf')
105
- expect(part_io.filename).to eq('local.path')
106
- expect(body_io).to eq(io.string)
107
- end
108
- end
109
-
110
- context 'FilePart: when multipart objects in array param' do
111
- let(:payload) do
112
- {
113
- a: 1,
114
- b: [{
115
- c: Faraday::FilePart.new(__FILE__, 'text/x-ruby'),
116
- d: 2
117
- }]
118
- }
119
- end
120
-
121
- it_behaves_like 'a multipart request'
122
-
123
- it 'forms a multipart request' do
124
- response = conn.post('/echo', payload)
125
-
126
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
127
- result = parse_multipart(boundary, response.body)
128
- expect(result[:errors]).to be_empty
129
-
130
- part_a, body_a = result.part('a')
131
- expect(part_a).to_not be_nil
132
- expect(part_a.filename).to be_nil
133
- expect(body_a).to eq('1')
134
-
135
- part_bc, body_bc = result.part('b[][c]')
136
- expect(part_bc).to_not be_nil
137
- expect(part_bc.filename).to eq('multipart_spec.rb')
138
- expect(part_bc.headers['content-disposition']).to eq(
139
- 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
140
- )
141
- expect(part_bc.headers['content-type']).to eq('text/x-ruby')
142
- expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
143
- expect(body_bc).to eq(File.read(__FILE__))
144
-
145
- part_bd, body_bd = result.part('b[][d]')
146
- expect(part_bd).to_not be_nil
147
- expect(part_bd.filename).to be_nil
148
- expect(body_bd).to eq('2')
149
- end
150
- end
151
-
152
- context 'UploadIO: when multipart objects in param' do
153
- let(:payload) do
154
- {
155
- a: 1,
156
- b: {
157
- c: Faraday::UploadIO.new(__FILE__, 'text/x-ruby', nil,
158
- 'Content-Disposition' => 'form-data; foo=1'),
159
- d: 2
160
- }
161
- }
162
- end
163
- it_behaves_like 'a multipart request'
164
-
165
- it 'forms a multipart request' do
166
- response = conn.post('/echo', payload)
167
-
168
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
169
- result = parse_multipart(boundary, response.body)
170
- expect(result[:errors]).to be_empty
171
-
172
- part_a, body_a = result.part('a')
173
- expect(part_a).to_not be_nil
174
- expect(part_a.filename).to be_nil
175
- expect(body_a).to eq('1')
176
-
177
- part_bc, body_bc = result.part('b[c]')
178
- expect(part_bc).to_not be_nil
179
- expect(part_bc.filename).to eq('multipart_spec.rb')
180
- expect(part_bc.headers['content-disposition']).to eq(
181
- 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
182
- )
183
- expect(part_bc.headers['content-type']).to eq('text/x-ruby')
184
- expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
185
- expect(body_bc).to eq(File.read(__FILE__))
186
-
187
- part_bd, body_bd = result.part('b[d]')
188
- expect(part_bd).to_not be_nil
189
- expect(part_bd.filename).to be_nil
190
- expect(body_bd).to eq('2')
191
- end
192
- end
193
-
194
- context 'UploadIO: when providing json and IO content in the same payload' do
195
- let(:io) { StringIO.new('io-content') }
196
- let(:json) do
197
- {
198
- b: 1,
199
- c: 2
200
- }.to_json
201
- end
202
-
203
- let(:payload) do
204
- {
205
- json: Faraday::ParamPart.new(json, 'application/json'),
206
- io: Faraday::UploadIO.new(io, 'application/pdf')
207
- }
208
- end
209
-
210
- it_behaves_like 'a multipart request'
211
-
212
- it 'forms a multipart request' do
213
- response = conn.post('/echo', payload)
214
-
215
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
216
- result = parse_multipart(boundary, response.body)
217
- expect(result[:errors]).to be_empty
218
-
219
- part_json, body_json = result.part('json')
220
- expect(part_json).to_not be_nil
221
- expect(part_json.mime).to eq('application/json')
222
- expect(part_json.filename).to be_nil
223
- expect(body_json).to eq(json)
224
-
225
- part_io, body_io = result.part('io')
226
- expect(part_io).to_not be_nil
227
- expect(part_io.mime).to eq('application/pdf')
228
- expect(part_io.filename).to eq('local.path')
229
- expect(body_io).to eq(io.string)
230
- end
231
- end
232
-
233
- context 'UploadIO: when multipart objects in array param' do
234
- let(:payload) do
235
- {
236
- a: 1,
237
- b: [{
238
- c: Faraday::UploadIO.new(__FILE__, 'text/x-ruby'),
239
- d: 2
240
- }]
241
- }
242
- end
243
-
244
- it_behaves_like 'a multipart request'
245
-
246
- it 'forms a multipart request' do
247
- response = conn.post('/echo', payload)
248
-
249
- boundary = parse_multipart_boundary(response.headers['Content-Type'])
250
- result = parse_multipart(boundary, response.body)
251
- expect(result[:errors]).to be_empty
252
-
253
- part_a, body_a = result.part('a')
254
- expect(part_a).to_not be_nil
255
- expect(part_a.filename).to be_nil
256
- expect(body_a).to eq('1')
257
-
258
- part_bc, body_bc = result.part('b[][c]')
259
- expect(part_bc).to_not be_nil
260
- expect(part_bc.filename).to eq('multipart_spec.rb')
261
- expect(part_bc.headers['content-disposition']).to eq(
262
- 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
263
- )
264
- expect(part_bc.headers['content-type']).to eq('text/x-ruby')
265
- expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
266
- expect(body_bc).to eq(File.read(__FILE__))
267
-
268
- part_bd, body_bd = result.part('b[][d]')
269
- expect(part_bd).to_not be_nil
270
- expect(part_bd.filename).to be_nil
271
- expect(body_bd).to eq('2')
272
- end
273
- end
274
- end
@@ -1,242 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Request::Retry do
4
- let(:calls) { [] }
5
- let(:times_called) { calls.size }
6
- let(:options) { [] }
7
- let(:conn) do
8
- Faraday.new do |b|
9
- b.request :retry, *options
10
-
11
- b.adapter :test do |stub|
12
- %w[get post].each do |method|
13
- stub.send(method, '/unstable') do |env|
14
- calls << env.dup
15
- env[:body] = nil # simulate blanking out response body
16
- callback.call
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- context 'when an unexpected error happens' do
24
- let(:callback) { -> { raise 'boom!' } }
25
-
26
- before { expect { conn.get('/unstable') }.to raise_error(RuntimeError) }
27
-
28
- it { expect(times_called).to eq(1) }
29
-
30
- context 'and this is passed as a custom exception' do
31
- let(:options) { [{ exceptions: StandardError }] }
32
-
33
- it { expect(times_called).to eq(3) }
34
- end
35
- end
36
-
37
- context 'when an expected error happens' do
38
- let(:callback) { -> { raise Errno::ETIMEDOUT } }
39
-
40
- before do
41
- @started = Time.now
42
- expect { conn.get('/unstable') }.to raise_error(Errno::ETIMEDOUT)
43
- end
44
-
45
- it { expect(times_called).to eq(3) }
46
-
47
- context 'and legacy max_retry set to 1' do
48
- let(:options) { [1] }
49
-
50
- it { expect(times_called).to eq(2) }
51
- end
52
-
53
- context 'and legacy max_retry set to -9' do
54
- let(:options) { [-9] }
55
-
56
- it { expect(times_called).to eq(1) }
57
- end
58
-
59
- context 'and new max_retry set to 3' do
60
- let(:options) { [{ max: 3 }] }
61
-
62
- it { expect(times_called).to eq(4) }
63
- end
64
-
65
- context 'and new max_retry set to -9' do
66
- let(:options) { [{ max: -9 }] }
67
-
68
- it { expect(times_called).to eq(1) }
69
- end
70
-
71
- context 'and both max_retry and interval are set' do
72
- let(:options) { [{ max: 2, interval: 0.1 }] }
73
-
74
- it { expect(Time.now - @started).to be_within(0.04).of(0.2) }
75
- end
76
- end
77
-
78
- context 'when no exception raised' do
79
- let(:options) { [{ max: 1, retry_statuses: 429 }] }
80
-
81
- before { conn.get('/unstable') }
82
-
83
- context 'and response code is in retry_statuses' do
84
- let(:callback) { -> { [429, {}, ''] } }
85
-
86
- it { expect(times_called).to eq(2) }
87
- end
88
-
89
- context 'and response code is not in retry_statuses' do
90
- let(:callback) { -> { [503, {}, ''] } }
91
-
92
- it { expect(times_called).to eq(1) }
93
- end
94
- end
95
-
96
- describe '#calculate_retry_interval' do
97
- context 'with exponential backoff' do
98
- let(:options) { { max: 5, interval: 0.1, backoff_factor: 2 } }
99
- let(:middleware) { Faraday::Request::Retry.new(nil, options) }
100
-
101
- it { expect(middleware.send(:calculate_retry_interval, 5)).to eq(0.1) }
102
- it { expect(middleware.send(:calculate_retry_interval, 4)).to eq(0.2) }
103
- it { expect(middleware.send(:calculate_retry_interval, 3)).to eq(0.4) }
104
- end
105
-
106
- context 'with exponential backoff and max_interval' do
107
- let(:options) { { max: 5, interval: 0.1, backoff_factor: 2, max_interval: 0.3 } }
108
- let(:middleware) { Faraday::Request::Retry.new(nil, options) }
109
-
110
- it { expect(middleware.send(:calculate_retry_interval, 5)).to eq(0.1) }
111
- it { expect(middleware.send(:calculate_retry_interval, 4)).to eq(0.2) }
112
- it { expect(middleware.send(:calculate_retry_interval, 3)).to eq(0.3) }
113
- it { expect(middleware.send(:calculate_retry_interval, 2)).to eq(0.3) }
114
- end
115
-
116
- context 'with exponential backoff and interval_randomness' do
117
- let(:options) { { max: 2, interval: 0.1, interval_randomness: 0.05 } }
118
- let(:middleware) { Faraday::Request::Retry.new(nil, options) }
119
-
120
- it { expect(middleware.send(:calculate_retry_interval, 2)).to be_between(0.1, 0.15) }
121
- end
122
- end
123
-
124
- context 'when method is not idempotent' do
125
- let(:callback) { -> { raise Errno::ETIMEDOUT } }
126
-
127
- before { expect { conn.post('/unstable') }.to raise_error(Errno::ETIMEDOUT) }
128
-
129
- it { expect(times_called).to eq(1) }
130
- end
131
-
132
- describe 'retry_if option' do
133
- let(:callback) { -> { raise Errno::ETIMEDOUT } }
134
- let(:options) { [{ retry_if: @check }] }
135
-
136
- it 'retries if retry_if block always returns true' do
137
- body = { foo: :bar }
138
- @check = ->(_, _) { true }
139
- expect { conn.post('/unstable', body) }.to raise_error(Errno::ETIMEDOUT)
140
- expect(times_called).to eq(3)
141
- expect(calls.all? { |env| env[:body] == body }).to be_truthy
142
- end
143
-
144
- it 'does not retry if retry_if block returns false checking env' do
145
- @check = ->(env, _) { env[:method] != :post }
146
- expect { conn.post('/unstable') }.to raise_error(Errno::ETIMEDOUT)
147
- expect(times_called).to eq(1)
148
- end
149
-
150
- it 'does not retry if retry_if block returns false checking exception' do
151
- @check = ->(_, exception) { !exception.is_a?(Errno::ETIMEDOUT) }
152
- expect { conn.post('/unstable') }.to raise_error(Errno::ETIMEDOUT)
153
- expect(times_called).to eq(1)
154
- end
155
-
156
- it 'FilePart: should rewind files on retry' do
157
- io = StringIO.new('Test data')
158
- filepart = Faraday::FilePart.new(io, 'application/octet/stream')
159
-
160
- rewound = 0
161
- rewind = -> { rewound += 1 }
162
-
163
- @check = ->(_, _) { true }
164
- allow(filepart).to receive(:rewind, &rewind)
165
- expect { conn.post('/unstable', file: filepart) }.to raise_error(Errno::ETIMEDOUT)
166
- expect(times_called).to eq(3)
167
- expect(rewound).to eq(2)
168
- end
169
-
170
- it 'UploadIO: should rewind files on retry' do
171
- io = StringIO.new('Test data')
172
- upload_io = Faraday::UploadIO.new(io, 'application/octet/stream')
173
-
174
- rewound = 0
175
- rewind = -> { rewound += 1 }
176
-
177
- @check = ->(_, _) { true }
178
- allow(upload_io).to receive(:rewind, &rewind)
179
- expect { conn.post('/unstable', file: upload_io) }.to raise_error(Errno::ETIMEDOUT)
180
- expect(times_called).to eq(3)
181
- expect(rewound).to eq(2)
182
- end
183
-
184
- context 'when explicitly specifying methods to retry' do
185
- let(:options) { [{ retry_if: @check, methods: [:post] }] }
186
-
187
- it 'does not call retry_if for specified methods' do
188
- @check = ->(_, _) { raise 'this should have never been called' }
189
- expect { conn.post('/unstable') }.to raise_error(Errno::ETIMEDOUT)
190
- expect(times_called).to eq(3)
191
- end
192
- end
193
-
194
- context 'with empty list of methods to retry' do
195
- let(:options) { [{ retry_if: @check, methods: [] }] }
196
-
197
- it 'calls retry_if for all methods' do
198
- @check = ->(_, _) { calls.size < 2 }
199
- expect { conn.get('/unstable') }.to raise_error(Errno::ETIMEDOUT)
200
- expect(times_called).to eq(2)
201
- end
202
- end
203
- end
204
-
205
- describe 'retry_after header support' do
206
- let(:callback) { -> { [504, headers, ''] } }
207
- let(:elapsed) { Time.now - @started }
208
-
209
- before do
210
- @started = Time.now
211
- conn.get('/unstable')
212
- end
213
-
214
- context 'when retry_after bigger than interval' do
215
- let(:headers) { { 'Retry-After' => '0.5' } }
216
- let(:options) { [{ max: 1, interval: 0.1, retry_statuses: 504 }] }
217
-
218
- it { expect(elapsed).to be > 0.5 }
219
- end
220
-
221
- context 'when retry_after smaller than interval' do
222
- let(:headers) { { 'Retry-After' => '0.1' } }
223
- let(:options) { [{ max: 1, interval: 0.2, retry_statuses: 504 }] }
224
-
225
- it { expect(elapsed).to be > 0.2 }
226
- end
227
-
228
- context 'when retry_after is a timestamp' do
229
- let(:headers) { { 'Retry-After' => (Time.now.utc + 2).strftime('%a, %d %b %Y %H:%M:%S GMT') } }
230
- let(:options) { [{ max: 1, interval: 0.1, retry_statuses: 504 }] }
231
-
232
- it { expect(elapsed).to be > 1 }
233
- end
234
-
235
- context 'when retry_after is bigger than max_interval' do
236
- let(:headers) { { 'Retry-After' => (Time.now.utc + 20).strftime('%a, %d %b %Y %H:%M:%S GMT') } }
237
- let(:options) { [{ max: 2, interval: 0.1, max_interval: 5, retry_statuses: 504 }] }
238
-
239
- it { expect(times_called).to eq(1) }
240
- end
241
- end
242
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Response::Middleware do
4
- let(:conn) do
5
- Faraday.new do |b|
6
- b.use custom_middleware
7
- b.adapter :test do |stub|
8
- stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
9
- stub.get('not_modified') { [304, nil, nil] }
10
- stub.get('no_content') { [204, nil, nil] }
11
- end
12
- end
13
- end
14
-
15
- context 'with a custom ResponseMiddleware' do
16
- let(:custom_middleware) do
17
- Class.new(Faraday::Response::Middleware) do
18
- def parse(body)
19
- body.upcase
20
- end
21
- end
22
- end
23
-
24
- it 'parses the response' do
25
- expect(conn.get('ok').body).to eq('<BODY></BODY>')
26
- end
27
- end
28
-
29
- context 'with a custom ResponseMiddleware but empty response' do
30
- let(:custom_middleware) do
31
- Class.new(Faraday::Response::Middleware) do
32
- def parse(_body)
33
- raise 'this should not be called'
34
- end
35
- end
36
- end
37
-
38
- it 'raises exception for 200 responses' do
39
- expect { conn.get('ok') }.to raise_error(StandardError)
40
- end
41
-
42
- it 'doesn\'t call the middleware for 204 responses' do
43
- expect_any_instance_of(custom_middleware).not_to receive(:parse)
44
- expect(conn.get('no_content').body).to be_nil
45
- end
46
-
47
- it 'doesn\'t call the middleware for 304 responses' do
48
- expect_any_instance_of(custom_middleware).not_to receive(:parse)
49
- expect(conn.get('not_modified').body).to be_nil
50
- end
51
- end
52
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Rack app used to test the Rack adapter.
4
- # Uses Webmock to check if requests are registered, in which case it returns
5
- # the registered response.
6
- class WebmockRackApp
7
- def call(env)
8
- req_signature = WebMock::RequestSignature.new(
9
- req_method(env),
10
- req_uri(env),
11
- body: req_body(env),
12
- headers: req_headers(env)
13
- )
14
-
15
- WebMock::RequestRegistry
16
- .instance
17
- .requested_signatures
18
- .put(req_signature)
19
-
20
- process_response(req_signature)
21
- end
22
-
23
- def req_method(env)
24
- env['REQUEST_METHOD'].downcase.to_sym
25
- end
26
-
27
- def req_uri(env)
28
- scheme = env['rack.url_scheme']
29
- host = env['SERVER_NAME']
30
- port = env['SERVER_PORT']
31
- path = env['PATH_INFO']
32
- query = env['QUERY_STRING']
33
-
34
- url = +"#{scheme}://#{host}:#{port}#{path}"
35
- url += "?#{query}" if query
36
-
37
- uri = WebMock::Util::URI.heuristic_parse(url)
38
- uri.path = uri.normalized_path.gsub('[^:]//', '/')
39
- uri
40
- end
41
-
42
- def req_headers(env)
43
- http_headers = env.select { |k, _| k.start_with?('HTTP_') }
44
- .map { |k, v| [k[5..-1], v] }
45
- .to_h
46
-
47
- special_headers = Faraday::Adapter::Rack::SPECIAL_HEADERS
48
- http_headers.merge(env.select { |k, _| special_headers.include?(k) })
49
- end
50
-
51
- def req_body(env)
52
- env['rack.input'].read
53
- end
54
-
55
- def process_response(req_signature)
56
- res = WebMock::StubRegistry.instance.response_for_request(req_signature)
57
-
58
- if res.nil? && req_signature.uri.host == 'localhost'
59
- raise Faraday::ConnectionFailed, 'Trying to connect to localhost'
60
- end
61
-
62
- raise WebMock::NetConnectNotAllowedError, req_signature unless res
63
-
64
- raise Faraday::TimeoutError if res.should_timeout
65
-
66
- [res.status[0], res.headers || {}, [res.body || '']]
67
- end
68
- end