faraday 2.0.0 → 2.7.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -3
  3. data/LICENSE.md +1 -1
  4. data/README.md +1 -6
  5. data/examples/client_spec.rb +40 -18
  6. data/examples/client_test.rb +47 -21
  7. data/lib/faraday/adapter/test.rb +41 -7
  8. data/lib/faraday/adapter.rb +2 -2
  9. data/lib/faraday/connection.rb +34 -34
  10. data/lib/faraday/encoders/nested_params_encoder.rb +11 -4
  11. data/lib/faraday/logging/formatter.rb +17 -3
  12. data/lib/faraday/middleware.rb +3 -0
  13. data/lib/faraday/middleware_registry.rb +19 -1
  14. data/lib/faraday/options/env.rb +18 -0
  15. data/lib/faraday/options/ssl_options.rb +11 -1
  16. data/lib/faraday/rack_builder.rb +2 -2
  17. data/lib/faraday/request/authorization.rb +8 -3
  18. data/lib/faraday/request/url_encoded.rb +3 -1
  19. data/lib/faraday/request.rb +1 -1
  20. data/lib/faraday/response/logger.rb +4 -0
  21. data/lib/faraday/utils/headers.rb +6 -1
  22. data/lib/faraday/version.rb +1 -1
  23. data/lib/faraday.rb +8 -2
  24. data/spec/faraday/adapter/test_spec.rb +36 -0
  25. data/spec/faraday/connection_spec.rb +48 -42
  26. data/spec/faraday/middleware_registry_spec.rb +31 -0
  27. data/spec/faraday/middleware_spec.rb +18 -0
  28. data/spec/faraday/options/env_spec.rb +6 -0
  29. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  30. data/spec/faraday/rack_builder_spec.rb +27 -12
  31. data/spec/faraday/request/authorization_spec.rb +35 -0
  32. data/spec/faraday/request/url_encoded_spec.rb +12 -1
  33. data/spec/faraday/request_spec.rb +5 -4
  34. data/spec/faraday/response/logger_spec.rb +28 -0
  35. data/spec/faraday/utils/headers_spec.rb +22 -4
  36. data/spec/faraday/utils_spec.rb +2 -1
  37. data/spec/support/shared_examples/adapter.rb +2 -1
  38. data/spec/support/shared_examples/request_method.rb +17 -3
  39. metadata +24 -3
@@ -6,15 +6,15 @@ class CustomEncoder
6
6
  end
7
7
 
8
8
  def decode(params)
9
- params.split(',').map { |pair| pair.split('-') }.to_h
9
+ params.split(',').to_h { |pair| pair.split('-') }
10
10
  end
11
11
  end
12
12
 
13
13
  shared_examples 'initializer with url' do
14
14
  context 'with simple url' do
15
- let(:address) { 'http://sushi.com' }
15
+ let(:address) { 'http://httpbingo.org' }
16
16
 
17
- it { expect(subject.host).to eq('sushi.com') }
17
+ it { expect(subject.host).to eq('httpbingo.org') }
18
18
  it { expect(subject.port).to eq(80) }
19
19
  it { expect(subject.scheme).to eq('http') }
20
20
  it { expect(subject.path_prefix).to eq('/') }
@@ -22,7 +22,7 @@ shared_examples 'initializer with url' do
22
22
  end
23
23
 
24
24
  context 'with complex url' do
25
- let(:address) { 'http://sushi.com:815/fish?a=1' }
25
+ let(:address) { 'http://httpbingo.org:815/fish?a=1' }
26
26
 
27
27
  it { expect(subject.port).to eq(815) }
28
28
  it { expect(subject.path_prefix).to eq('/fish') }
@@ -41,17 +41,17 @@ shared_examples 'default connection options' do
41
41
  after { Faraday.default_connection_options = nil }
42
42
 
43
43
  it 'works with implicit url' do
44
- conn = Faraday.new 'http://sushi.com/foo'
44
+ conn = Faraday.new 'http://httpbingo.org/foo'
45
45
  expect(conn.options.timeout).to eq(10)
46
46
  end
47
47
 
48
48
  it 'works with option url' do
49
- conn = Faraday.new url: 'http://sushi.com/foo'
49
+ conn = Faraday.new url: 'http://httpbingo.org/foo'
50
50
  expect(conn.options.timeout).to eq(10)
51
51
  end
52
52
 
53
53
  it 'works with instance connection options' do
54
- conn = Faraday.new 'http://sushi.com/foo', request: { open_timeout: 1 }
54
+ conn = Faraday.new 'http://httpbingo.org/foo', request: { open_timeout: 1 }
55
55
  expect(conn.options.timeout).to eq(10)
56
56
  expect(conn.options.open_timeout).to eq(1)
57
57
  end
@@ -61,7 +61,7 @@ shared_examples 'default connection options' do
61
61
  conn.options.timeout = 1
62
62
  expect(Faraday.default_connection_options.request.timeout).to eq(10)
63
63
 
64
- other = Faraday.new url: 'https://sushi.com/foo'
64
+ other = Faraday.new url: 'https://httpbingo.org/foo'
65
65
  other.options.timeout = 1
66
66
 
67
67
  expect(Faraday.default_connection_options.request.timeout).to eq(10)
@@ -81,14 +81,14 @@ RSpec.describe Faraday::Connection do
81
81
  subject { conn }
82
82
 
83
83
  context 'with implicit url param' do
84
- # Faraday::Connection.new('http://sushi.com')
84
+ # Faraday::Connection.new('http://httpbingo.org')
85
85
  let(:url) { address }
86
86
 
87
87
  it_behaves_like 'initializer with url'
88
88
  end
89
89
 
90
90
  context 'with explicit url param' do
91
- # Faraday::Connection.new(url: 'http://sushi.com')
91
+ # Faraday::Connection.new(url: 'http://httpbingo.org')
92
92
  let(:url) { { url: address } }
93
93
 
94
94
  it_behaves_like 'initializer with url'
@@ -108,13 +108,13 @@ RSpec.describe Faraday::Connection do
108
108
  end
109
109
 
110
110
  context 'with custom params and params in url' do
111
- let(:url) { 'http://sushi.com/fish?a=1&b=2' }
111
+ let(:url) { 'http://httpbingo.org/fish?a=1&b=2' }
112
112
  let(:options) { { params: { a: 3 } } }
113
113
  it { expect(subject.params).to eq('a' => 3, 'b' => '2') }
114
114
  end
115
115
 
116
116
  context 'with basic_auth in url' do
117
- let(:url) { 'http://Aladdin:open%20sesame@sushi.com/fish' }
117
+ let(:url) { 'http://Aladdin:open%20sesame@httpbingo.org/fish' }
118
118
 
119
119
  it { expect(subject.headers['Authorization']).to eq('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') }
120
120
  end
@@ -131,6 +131,12 @@ RSpec.describe Faraday::Connection do
131
131
  it { expect(subject.ssl.verify?).to be_falsey }
132
132
  end
133
133
 
134
+ context 'with verify_hostname false' do
135
+ let(:options) { { ssl: { verify_hostname: false } } }
136
+
137
+ it { expect(subject.ssl.verify_hostname?).to be_falsey }
138
+ end
139
+
134
140
  context 'with empty block' do
135
141
  let(:conn) { Faraday::Connection.new {} }
136
142
 
@@ -141,7 +147,7 @@ RSpec.describe Faraday::Connection do
141
147
  let(:conn) do
142
148
  Faraday::Connection.new(params: { 'a' => '1' }) do |faraday|
143
149
  faraday.adapter :test
144
- faraday.url_prefix = 'http://sushi.com/omnom'
150
+ faraday.url_prefix = 'http://httpbingo.org/omnom'
145
151
  end
146
152
  end
147
153
 
@@ -165,8 +171,8 @@ RSpec.describe Faraday::Connection do
165
171
  subject { conn.build_exclusive_url('sake.html') }
166
172
 
167
173
  it 'uses connection host as default host' do
168
- conn.host = 'sushi.com'
169
- expect(subject.host).to eq('sushi.com')
174
+ conn.host = 'httpbingo.org'
175
+ expect(subject.host).to eq('httpbingo.org')
170
176
  expect(subject.scheme).to eq('http')
171
177
  end
172
178
 
@@ -203,10 +209,10 @@ RSpec.describe Faraday::Connection do
203
209
  end
204
210
 
205
211
  context 'with complete url' do
206
- subject { conn.build_exclusive_url('http://sushi.com/sake.html?a=1') }
212
+ subject { conn.build_exclusive_url('http://httpbingo.org/sake.html?a=1') }
207
213
 
208
214
  it { expect(subject.scheme).to eq('http') }
209
- it { expect(subject.host).to eq('sushi.com') }
215
+ it { expect(subject.host).to eq('httpbingo.org') }
210
216
  it { expect(subject.port).to eq(80) }
211
217
  it { expect(subject.path).to eq('/sake.html') }
212
218
  it { expect(subject.query).to eq('a=1') }
@@ -214,35 +220,35 @@ RSpec.describe Faraday::Connection do
214
220
 
215
221
  it 'overrides connection port for absolute url' do
216
222
  conn.port = 23
217
- uri = conn.build_exclusive_url('http://sushi.com')
223
+ uri = conn.build_exclusive_url('http://httpbingo.org')
218
224
  expect(uri.port).to eq(80)
219
225
  end
220
226
 
221
227
  it 'does not add ending slash given nil url' do
222
- conn.url_prefix = 'http://sushi.com/nigiri'
228
+ conn.url_prefix = 'http://httpbingo.org/nigiri'
223
229
  uri = conn.build_exclusive_url
224
230
  expect(uri.path).to eq('/nigiri')
225
231
  end
226
232
 
227
233
  it 'does not add ending slash given empty url' do
228
- conn.url_prefix = 'http://sushi.com/nigiri'
234
+ conn.url_prefix = 'http://httpbingo.org/nigiri'
229
235
  uri = conn.build_exclusive_url('')
230
236
  expect(uri.path).to eq('/nigiri')
231
237
  end
232
238
 
233
239
  it 'does not use connection params' do
234
- conn.url_prefix = 'http://sushi.com/nigiri'
240
+ conn.url_prefix = 'http://httpbingo.org/nigiri'
235
241
  conn.params = { a: 1 }
236
- expect(conn.build_exclusive_url.to_s).to eq('http://sushi.com/nigiri')
242
+ expect(conn.build_exclusive_url.to_s).to eq('http://httpbingo.org/nigiri')
237
243
  end
238
244
 
239
245
  it 'allows to provide params argument' do
240
- conn.url_prefix = 'http://sushi.com/nigiri'
246
+ conn.url_prefix = 'http://httpbingo.org/nigiri'
241
247
  conn.params = { a: 1 }
242
248
  params = Faraday::Utils::ParamsHash.new
243
249
  params[:a] = 2
244
250
  uri = conn.build_exclusive_url(nil, params)
245
- expect(uri.to_s).to eq('http://sushi.com/nigiri?a=2')
251
+ expect(uri.to_s).to eq('http://httpbingo.org/nigiri?a=2')
246
252
  end
247
253
 
248
254
  it 'handles uri instances' do
@@ -251,34 +257,34 @@ RSpec.describe Faraday::Connection do
251
257
  end
252
258
 
253
259
  it 'always returns new URI instance' do
254
- conn.url_prefix = 'http://sushi.com'
260
+ conn.url_prefix = 'http://httpbingo.org'
255
261
  uri1 = conn.build_exclusive_url(nil)
256
262
  uri2 = conn.build_exclusive_url(nil)
257
263
  expect(uri1).not_to equal(uri2)
258
264
  end
259
265
 
260
266
  context 'with url_prefixed connection' do
261
- let(:url) { 'http://sushi.com/sushi/' }
267
+ let(:url) { 'http://httpbingo.org/get/' }
262
268
 
263
269
  it 'parses url and changes scheme' do
264
270
  conn.scheme = 'https'
265
271
  uri = conn.build_exclusive_url('sake.html')
266
- expect(uri.to_s).to eq('https://sushi.com/sushi/sake.html')
272
+ expect(uri.to_s).to eq('https://httpbingo.org/get/sake.html')
267
273
  end
268
274
 
269
275
  it 'joins url to base with ending slash' do
270
276
  uri = conn.build_exclusive_url('sake.html')
271
- expect(uri.to_s).to eq('http://sushi.com/sushi/sake.html')
277
+ expect(uri.to_s).to eq('http://httpbingo.org/get/sake.html')
272
278
  end
273
279
 
274
280
  it 'used default base with ending slash' do
275
281
  uri = conn.build_exclusive_url
276
- expect(uri.to_s).to eq('http://sushi.com/sushi/')
282
+ expect(uri.to_s).to eq('http://httpbingo.org/get/')
277
283
  end
278
284
 
279
285
  it 'overrides base' do
280
286
  uri = conn.build_exclusive_url('/sake/')
281
- expect(uri.to_s).to eq('http://sushi.com/sake/')
287
+ expect(uri.to_s).to eq('http://httpbingo.org/sake/')
282
288
  end
283
289
  end
284
290
 
@@ -307,22 +313,22 @@ RSpec.describe Faraday::Connection do
307
313
  end
308
314
 
309
315
  describe '#build_url' do
310
- let(:url) { 'http://sushi.com/nigiri' }
316
+ let(:url) { 'http://httpbingo.org/nigiri' }
311
317
 
312
318
  it 'uses params' do
313
319
  conn.params = { a: 1, b: 1 }
314
- expect(conn.build_url.to_s).to eq('http://sushi.com/nigiri?a=1&b=1')
320
+ expect(conn.build_url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=1')
315
321
  end
316
322
 
317
323
  it 'merges params' do
318
324
  conn.params = { a: 1, b: 1 }
319
325
  url = conn.build_url(nil, b: 2, c: 3)
320
- expect(url.to_s).to eq('http://sushi.com/nigiri?a=1&b=2&c=3')
326
+ expect(url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=2&c=3')
321
327
  end
322
328
  end
323
329
 
324
330
  describe '#build_request' do
325
- let(:url) { 'https://asushi.com/sake.html' }
331
+ let(:url) { 'https://ahttpbingo.org/sake.html' }
326
332
  let(:request) { conn.build_request(:get) }
327
333
 
328
334
  before do
@@ -339,7 +345,7 @@ RSpec.describe Faraday::Connection do
339
345
  describe '#to_env' do
340
346
  subject { conn.build_request(:get).to_env(conn).url }
341
347
 
342
- let(:url) { 'http://sushi.com/sake.html' }
348
+ let(:url) { 'http://httpbingo.org/sake.html' }
343
349
  let(:options) { { params: @params } }
344
350
 
345
351
  it 'parses url params into query' do
@@ -505,7 +511,7 @@ RSpec.describe Faraday::Connection do
505
511
  it 'uses env http_proxy' do
506
512
  with_env 'http_proxy' => 'http://proxy.com' do
507
513
  conn = Faraday.new
508
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
514
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
509
515
  expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com')
510
516
  end
511
517
  end
@@ -513,7 +519,7 @@ RSpec.describe Faraday::Connection do
513
519
  it 'uses processes no_proxy before http_proxy' do
514
520
  with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do
515
521
  conn = Faraday.new
516
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
522
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
517
523
  expect(conn.proxy_for_request('http://google.co.uk')).to be_nil
518
524
  end
519
525
  end
@@ -521,7 +527,7 @@ RSpec.describe Faraday::Connection do
521
527
  it 'uses env https_proxy' do
522
528
  with_env 'https_proxy' => 'https://proxy.com' do
523
529
  conn = Faraday.new
524
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
530
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
525
531
  expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com')
526
532
  end
527
533
  end
@@ -529,7 +535,7 @@ RSpec.describe Faraday::Connection do
529
535
  it 'uses processes no_proxy before https_proxy' do
530
536
  with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
531
537
  conn = Faraday.new
532
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
538
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
533
539
  expect(conn.proxy_for_request('https://google.co.uk')).to be_nil
534
540
  end
535
541
  end
@@ -539,7 +545,7 @@ RSpec.describe Faraday::Connection do
539
545
  conn = Faraday.new
540
546
  conn.proxy = 'http://proxy2.com'
541
547
 
542
- expect(conn.instance_variable_get('@manual_proxy')).to be_truthy
548
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_truthy
543
549
  expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com')
544
550
  end
545
551
  end
@@ -574,7 +580,7 @@ RSpec.describe Faraday::Connection do
574
580
  end
575
581
 
576
582
  conn.get(url)
577
- expect(conn.instance_variable_get('@temp_proxy')).to be_nil
583
+ expect(conn.instance_variable_get(:@temp_proxy)).to be_nil
578
584
  end
579
585
 
580
586
  it 'dynamically check no proxy' do
@@ -592,7 +598,7 @@ RSpec.describe Faraday::Connection do
592
598
  describe '#dup' do
593
599
  subject { conn.dup }
594
600
 
595
- let(:url) { 'http://sushi.com/foo' }
601
+ let(:url) { 'http://httpbingo.org/foo' }
596
602
  let(:options) do
597
603
  {
598
604
  ssl: { verify: :none },
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::MiddlewareRegistry do
4
+ before do
5
+ stub_const('CustomMiddleware', custom_middleware_klass)
6
+ end
7
+ let(:custom_middleware_klass) { Class.new(Faraday::Middleware) }
8
+ let(:dummy) { Class.new { extend Faraday::MiddlewareRegistry } }
9
+
10
+ after { dummy.unregister_middleware(:custom) }
11
+
12
+ it 'allows to register with constant' do
13
+ dummy.register_middleware(custom: custom_middleware_klass)
14
+ expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass)
15
+ end
16
+
17
+ it 'allows to register with symbol' do
18
+ dummy.register_middleware(custom: :CustomMiddleware)
19
+ expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass)
20
+ end
21
+
22
+ it 'allows to register with string' do
23
+ dummy.register_middleware(custom: 'CustomMiddleware')
24
+ expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass)
25
+ end
26
+
27
+ it 'allows to register with Proc' do
28
+ dummy.register_middleware(custom: -> { custom_middleware_klass })
29
+ expect(dummy.lookup_middleware(:custom)).to eq(custom_middleware_klass)
30
+ end
31
+ end
@@ -33,6 +33,24 @@ RSpec.describe Faraday::Middleware do
33
33
  end
34
34
  end
35
35
 
36
+ describe '#on_error' do
37
+ subject do
38
+ Class.new(described_class) do
39
+ def on_error(error)
40
+ # do nothing
41
+ end
42
+ end.new(app)
43
+ end
44
+
45
+ it 'is called by #call' do
46
+ expect(app).to receive(:call).and_raise(Faraday::ConnectionFailed)
47
+ is_expected.to receive(:call).and_call_original
48
+ is_expected.to receive(:on_error)
49
+
50
+ expect { subject.call(double) }.to raise_error(Faraday::ConnectionFailed)
51
+ end
52
+ end
53
+
36
54
  describe '#close' do
37
55
  context "with app that doesn't support \#close" do
38
56
  it 'should issue warning' do
@@ -27,6 +27,12 @@ RSpec.describe Faraday::Env do
27
27
  expect(ssl.fetch(:verify, true)).to be_falsey
28
28
  end
29
29
 
30
+ it 'handle verify_hostname when fetching' do
31
+ ssl = Faraday::SSLOptions.new
32
+ ssl.verify_hostname = true
33
+ expect(ssl.fetch(:verify_hostname, false)).to be_truthy
34
+ end
35
+
30
36
  it 'retains custom members' do
31
37
  env[:foo] = 'custom 1'
32
38
  env[:bar] = :custom2
@@ -102,6 +102,14 @@ RSpec.describe Faraday::NestedParamsEncoder do
102
102
  Faraday::NestedParamsEncoder.sort_params = true
103
103
  end
104
104
 
105
+ it 'encodes arrays indices when asked' do
106
+ params = { a: [0, 1, 2] }
107
+ expect(subject.encode(params)).to eq('a%5B%5D=0&a%5B%5D=1&a%5B%5D=2')
108
+ Faraday::NestedParamsEncoder.array_indices = true
109
+ expect(subject.encode(params)).to eq('a%5B0%5D=0&a%5B1%5D=1&a%5B2%5D=2')
110
+ Faraday::NestedParamsEncoder.array_indices = false
111
+ end
112
+
105
113
  shared_examples 'a wrong decoding' do
106
114
  it do
107
115
  expect { subject.decode(query) }.to raise_error(TypeError) do |e|
@@ -110,18 +110,6 @@ RSpec.describe Faraday::RackBuilder do
110
110
  end
111
111
  end
112
112
 
113
- context 'with custom registered middleware' do
114
- let(:conn) { Faraday::Connection.new {} }
115
-
116
- after { Faraday::Middleware.unregister_middleware(:apple) }
117
-
118
- it 'allows to register with constant' do
119
- Faraday::Middleware.register_middleware(apple: Apple)
120
- subject.use(:apple)
121
- expect(subject.handlers).to eq([Apple])
122
- end
123
- end
124
-
125
113
  context 'when having two handlers' do
126
114
  let(:conn) { Faraday::Connection.new {} }
127
115
 
@@ -151,6 +139,33 @@ RSpec.describe Faraday::RackBuilder do
151
139
  end
152
140
  end
153
141
 
142
+ context 'when adapter is added with named options' do
143
+ after { Faraday.default_adapter_options = {} }
144
+ let(:conn) { Faraday::Connection.new {} }
145
+
146
+ let(:cat_adapter) do
147
+ Class.new(Faraday::Adapter) do
148
+ attr_accessor :name
149
+
150
+ def initialize(app, name:)
151
+ super(app)
152
+ @name = name
153
+ end
154
+ end
155
+ end
156
+
157
+ let(:cat) { subject.adapter.build }
158
+
159
+ it 'adds a handler to construct adapter with named options' do
160
+ Faraday.default_adapter = cat_adapter
161
+ Faraday.default_adapter_options = { name: 'Chloe' }
162
+ expect { cat }.to_not output(
163
+ /warning: Using the last argument as keyword parameters is deprecated/
164
+ ).to_stderr
165
+ expect(cat.name).to eq 'Chloe'
166
+ end
167
+ end
168
+
154
169
  context 'when middleware is added with named arguments' do
155
170
  let(:conn) { Faraday::Connection.new {} }
156
171
 
@@ -72,6 +72,41 @@ RSpec.describe Faraday::Request::Authorization do
72
72
  include_examples 'does not interfere with existing authentication'
73
73
  end
74
74
 
75
+ context 'with an argument' do
76
+ let(:response) { conn.get('/auth-echo', nil, 'middle' => 'crunchy surprise') }
77
+
78
+ context 'when passed a proc' do
79
+ let(:auth_config) { [proc { |env| "proc #{env.request_headers['middle']}" }] }
80
+
81
+ it { expect(response.body).to eq('Bearer proc crunchy surprise') }
82
+
83
+ include_examples 'does not interfere with existing authentication'
84
+ end
85
+
86
+ context 'when passed a lambda' do
87
+ let(:auth_config) { [->(env) { "lambda #{env.request_headers['middle']}" }] }
88
+
89
+ it { expect(response.body).to eq('Bearer lambda crunchy surprise') }
90
+
91
+ include_examples 'does not interfere with existing authentication'
92
+ end
93
+
94
+ context 'when passed a callable with an argument' do
95
+ let(:callable) do
96
+ Class.new do
97
+ def call(env)
98
+ "callable #{env.request_headers['middle']}"
99
+ end
100
+ end.new
101
+ end
102
+ let(:auth_config) { [callable] }
103
+
104
+ it { expect(response.body).to eq('Bearer callable crunchy surprise') }
105
+
106
+ include_examples 'does not interfere with existing authentication'
107
+ end
108
+ end
109
+
75
110
  context 'when passed too many arguments' do
76
111
  let(:auth_config) { %w[baz foo] }
77
112
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'stringio'
4
+
3
5
  RSpec.describe Faraday::Request::UrlEncoded do
4
6
  let(:conn) do
5
7
  Faraday.new do |b|
@@ -7,7 +9,11 @@ RSpec.describe Faraday::Request::UrlEncoded do
7
9
  b.adapter :test do |stub|
8
10
  stub.post('/echo') do |env|
9
11
  posted_as = env[:request_headers]['Content-Type']
10
- [200, { 'Content-Type' => posted_as }, env[:body]]
12
+ body = env[:body]
13
+ if body.respond_to?(:read)
14
+ body = body.read
15
+ end
16
+ [200, { 'Content-Type' => posted_as }, body]
11
17
  end
12
18
  end
13
19
  end
@@ -67,6 +73,11 @@ RSpec.describe Faraday::Request::UrlEncoded do
67
73
  expect(response.body).to eq('a%5Bb%5D%5Bc%5D%5B%5D=d')
68
74
  end
69
75
 
76
+ it 'works with files' do
77
+ response = conn.post('/echo', StringIO.new('str=apple'))
78
+ expect(response.body).to eq('str=apple')
79
+ end
80
+
70
81
  context 'customising default_space_encoding' do
71
82
  around do |example|
72
83
  Faraday::Utils.default_space_encoding = '%20'
@@ -2,7 +2,7 @@
2
2
 
3
3
  RSpec.describe Faraday::Request do
4
4
  let(:conn) do
5
- Faraday.new(url: 'http://sushi.com/api',
5
+ Faraday.new(url: 'http://httpbingo.org/api',
6
6
  headers: { 'Mime-Version' => '1.0' },
7
7
  request: { oauth: { consumer_key: 'anonymous' } })
8
8
  end
@@ -14,6 +14,7 @@ RSpec.describe Faraday::Request do
14
14
  context 'when nothing particular is configured' do
15
15
  it { expect(subject.http_method).to eq(:get) }
16
16
  it { expect(subject.to_env(conn).ssl.verify).to be_falsey }
17
+ it { expect(subject.to_env(conn).ssl.verify_hostname).to be_falsey }
17
18
  end
18
19
 
19
20
  context 'when HTTP method is post' do
@@ -27,7 +28,7 @@ RSpec.describe Faraday::Request do
27
28
 
28
29
  it { expect(subject.path).to eq(URI.parse('foo.json')) }
29
30
  it { expect(subject.params).to eq('a' => '1') }
30
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1') }
31
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
31
32
  end
32
33
 
33
34
  context 'when setting the url on setup with a string path and params' do
@@ -35,7 +36,7 @@ RSpec.describe Faraday::Request do
35
36
 
36
37
  it { expect(subject.path).to eq('foo.json') }
37
38
  it { expect(subject.params).to eq('a' => 1) }
38
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1') }
39
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
39
40
  end
40
41
 
41
42
  context 'when setting the url on setup with a path including params' do
@@ -43,7 +44,7 @@ RSpec.describe Faraday::Request do
43
44
 
44
45
  it { expect(subject.path).to eq('foo.json') }
45
46
  it { expect(subject.params).to eq('a' => '1', 'b' => '2') }
46
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1&b=2') }
47
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1&b=2') }
47
48
  end
48
49
 
49
50
  context 'when setting a header on setup with []= syntax' do
@@ -64,6 +64,15 @@ RSpec.describe Faraday::Response::Logger do
64
64
  expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
65
65
  conn.get '/hello'
66
66
  end
67
+
68
+ context 'when no route' do
69
+ it 'delegates logging to the formatter' do
70
+ expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
71
+ expect(formatter).to receive(:error).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
72
+
73
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
74
+ end
75
+ end
67
76
  end
68
77
 
69
78
  context 'with custom formatter' do
@@ -94,6 +103,16 @@ RSpec.describe Faraday::Response::Logger do
94
103
  expect(string_io.string).to match('GET http:/hello')
95
104
  end
96
105
 
106
+ it 'logs status' do
107
+ conn.get '/hello', nil, accept: 'text/html'
108
+ expect(string_io.string).to match('Status 200')
109
+ end
110
+
111
+ it 'does not log error message by default' do
112
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
113
+ expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
114
+ end
115
+
97
116
  it 'logs request headers by default' do
98
117
  conn.get '/hello', nil, accept: 'text/html'
99
118
  expect(string_io.string).to match(%(Accept: "text/html))
@@ -188,6 +207,15 @@ RSpec.describe Faraday::Response::Logger do
188
207
  end
189
208
  end
190
209
 
210
+ context 'when logging errors' do
211
+ let(:logger_options) { { errors: true } }
212
+
213
+ it 'logs error message' do
214
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
215
+ expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
216
+ end
217
+ end
218
+
191
219
  context 'when using log_level' do
192
220
  let(:logger_options) { { bodies: true, log_level: :debug } }
193
221
 
@@ -57,26 +57,44 @@ RSpec.describe Faraday::Utils::Headers do
57
57
  end
58
58
 
59
59
  describe '#parse' do
60
- before { subject.parse(headers) }
61
-
62
60
  context 'when response headers leave http status line out' do
63
61
  let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" }
64
62
 
63
+ before { subject.parse(headers) }
64
+
65
65
  it { expect(subject.keys).to eq(%w[Content-Type]) }
66
66
  it { expect(subject['Content-Type']).to eq('text/html') }
67
67
  it { expect(subject['content-type']).to eq('text/html') }
68
68
  end
69
69
 
70
70
  context 'when response headers values include a colon' do
71
- let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n" }
71
+ let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" }
72
72
 
73
- it { expect(subject['location']).to eq('http://sushi.com/') }
73
+ before { subject.parse(headers) }
74
+
75
+ it { expect(subject['location']).to eq('http://httpbingo.org/') }
74
76
  end
75
77
 
76
78
  context 'when response headers include a blank line' do
77
79
  let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" }
78
80
 
81
+ before { subject.parse(headers) }
82
+
79
83
  it { expect(subject['content-type']).to eq('text/html') }
80
84
  end
85
+
86
+ context 'when response headers include already stored keys' do
87
+ let(:headers) { "HTTP/1.1 200 OK\r\nX-Numbers: 123\r\n\r\n" }
88
+
89
+ before do
90
+ h = subject
91
+ h[:x_numbers] = 8
92
+ h.parse(headers)
93
+ end
94
+
95
+ it do
96
+ expect(subject[:x_numbers]).to eq('8, 123')
97
+ end
98
+ end
81
99
  end
82
100
  end