faraday 1.10.4 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +198 -4
- data/LICENSE.md +1 -1
- data/README.md +34 -20
- data/Rakefile +6 -1
- data/examples/client_spec.rb +41 -19
- data/examples/client_test.rb +48 -22
- data/lib/faraday/adapter/test.rb +62 -13
- data/lib/faraday/adapter.rb +6 -10
- data/lib/faraday/connection.rb +72 -150
- data/lib/faraday/encoders/nested_params_encoder.rb +14 -7
- data/lib/faraday/error.rb +24 -5
- data/lib/faraday/logging/formatter.rb +29 -16
- data/lib/faraday/middleware.rb +43 -2
- data/lib/faraday/middleware_registry.rb +17 -63
- data/lib/faraday/options/connection_options.rb +7 -6
- data/lib/faraday/options/env.rb +85 -62
- data/lib/faraday/options/proxy_options.rb +11 -5
- data/lib/faraday/options/request_options.rb +7 -6
- data/lib/faraday/options/ssl_options.rb +62 -45
- data/lib/faraday/options.rb +7 -6
- data/lib/faraday/rack_builder.rb +43 -40
- data/lib/faraday/request/authorization.rb +33 -41
- data/lib/faraday/request/instrumentation.rb +5 -1
- data/lib/faraday/request/json.rb +18 -3
- data/lib/faraday/request/url_encoded.rb +5 -1
- data/lib/faraday/request.rb +15 -30
- data/lib/faraday/response/json.rb +25 -5
- data/lib/faraday/response/logger.rb +11 -3
- data/lib/faraday/response/raise_error.rb +45 -18
- data/lib/faraday/response.rb +9 -21
- data/lib/faraday/utils/headers.rb +15 -4
- data/lib/faraday/utils.rb +11 -7
- data/lib/faraday/version.rb +1 -1
- data/lib/faraday.rb +8 -44
- data/spec/faraday/adapter/test_spec.rb +65 -0
- data/spec/faraday/connection_spec.rb +165 -93
- data/spec/faraday/error_spec.rb +39 -6
- data/spec/faraday/middleware_registry_spec.rb +31 -0
- data/spec/faraday/middleware_spec.rb +161 -0
- data/spec/faraday/options/env_spec.rb +8 -2
- data/spec/faraday/options/options_spec.rb +1 -1
- data/spec/faraday/options/proxy_options_spec.rb +35 -0
- data/spec/faraday/params_encoders/nested_spec.rb +10 -1
- data/spec/faraday/rack_builder_spec.rb +26 -54
- data/spec/faraday/request/authorization_spec.rb +50 -28
- data/spec/faraday/request/instrumentation_spec.rb +5 -7
- data/spec/faraday/request/json_spec.rb +88 -0
- data/spec/faraday/request/url_encoded_spec.rb +12 -2
- data/spec/faraday/request_spec.rb +5 -15
- data/spec/faraday/response/json_spec.rb +93 -6
- data/spec/faraday/response/logger_spec.rb +77 -4
- data/spec/faraday/response/raise_error_spec.rb +111 -5
- data/spec/faraday/response_spec.rb +3 -1
- data/spec/faraday/utils/headers_spec.rb +31 -4
- data/spec/faraday/utils_spec.rb +65 -1
- data/spec/faraday_spec.rb +10 -4
- data/spec/spec_helper.rb +5 -6
- data/spec/support/fake_safe_buffer.rb +1 -1
- data/spec/support/faraday_middleware_subclasses.rb +18 -0
- data/spec/support/helper_methods.rb +0 -37
- data/spec/support/shared_examples/adapter.rb +2 -2
- data/spec/support/shared_examples/request_method.rb +22 -21
- metadata +24 -149
- data/lib/faraday/adapter/typhoeus.rb +0 -15
- data/lib/faraday/autoload.rb +0 -89
- data/lib/faraday/dependency_loader.rb +0 -39
- data/lib/faraday/deprecate.rb +0 -110
- data/lib/faraday/request/basic_authentication.rb +0 -20
- data/lib/faraday/request/token_authentication.rb +0 -20
- data/spec/faraday/adapter/em_http_spec.rb +0 -49
- data/spec/faraday/adapter/em_synchrony_spec.rb +0 -18
- data/spec/faraday/adapter/excon_spec.rb +0 -49
- data/spec/faraday/adapter/httpclient_spec.rb +0 -73
- data/spec/faraday/adapter/net_http_spec.rb +0 -64
- data/spec/faraday/adapter/patron_spec.rb +0 -18
- data/spec/faraday/adapter/rack_spec.rb +0 -8
- data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
- data/spec/faraday/composite_read_io_spec.rb +0 -80
- data/spec/faraday/deprecate_spec.rb +0 -147
- data/spec/faraday/response/middleware_spec.rb +0 -68
- data/spec/support/webmock_rack_app.rb +0 -68
@@ -73,6 +73,30 @@ RSpec.describe Faraday::Request::Json do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
context 'true body' do
|
77
|
+
let(:result) { process(true) }
|
78
|
+
|
79
|
+
it 'encodes body' do
|
80
|
+
expect(result_body).to eq('true')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'adds content type' do
|
84
|
+
expect(result_type).to eq('application/json')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'false body' do
|
89
|
+
let(:result) { process(false) }
|
90
|
+
|
91
|
+
it 'encodes body' do
|
92
|
+
expect(result_body).to eq('false')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'adds content type' do
|
96
|
+
expect(result_type).to eq('application/json')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
76
100
|
context 'object body with json type' do
|
77
101
|
let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') }
|
78
102
|
|
@@ -108,4 +132,68 @@ RSpec.describe Faraday::Request::Json do
|
|
108
132
|
expect(result_type).to eq('application/xml; charset=utf-8')
|
109
133
|
end
|
110
134
|
end
|
135
|
+
|
136
|
+
context 'with encoder' do
|
137
|
+
let(:encoder) do
|
138
|
+
double('Encoder').tap do |e|
|
139
|
+
allow(e).to receive(:dump) { |s, opts| JSON.generate(s, opts) }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
let(:result) { process(a: 1) }
|
144
|
+
|
145
|
+
context 'when encoder is passed as object' do
|
146
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: encoder }) }
|
147
|
+
|
148
|
+
it 'calls specified JSON encoder\'s dump method' do
|
149
|
+
expect(encoder).to receive(:dump).with({ a: 1 })
|
150
|
+
|
151
|
+
result
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'encodes body' do
|
155
|
+
expect(result_body).to eq('{"a":1}')
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'adds content type' do
|
159
|
+
expect(result_type).to eq('application/json')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when encoder is passed as an object-method pair' do
|
164
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: [encoder, :dump] }) }
|
165
|
+
|
166
|
+
it 'calls specified JSON encoder' do
|
167
|
+
expect(encoder).to receive(:dump).with({ a: 1 })
|
168
|
+
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'encodes body' do
|
173
|
+
expect(result_body).to eq('{"a":1}')
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'adds content type' do
|
177
|
+
expect(result_type).to eq('application/json')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'when encoder is not passed' do
|
182
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) }
|
183
|
+
|
184
|
+
it 'calls JSON.generate' do
|
185
|
+
expect(JSON).to receive(:generate).with({ a: 1 })
|
186
|
+
|
187
|
+
result
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'encodes body' do
|
191
|
+
expect(result_body).to eq('{"a":1}')
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'adds content type' do
|
195
|
+
expect(result_type).to eq('application/json')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
111
199
|
end
|
@@ -1,14 +1,19 @@
|
|
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|
|
6
|
-
b.request :multipart
|
7
8
|
b.request :url_encoded
|
8
9
|
b.adapter :test do |stub|
|
9
10
|
stub.post('/echo') do |env|
|
10
11
|
posted_as = env[:request_headers]['Content-Type']
|
11
|
-
|
12
|
+
body = env[:body]
|
13
|
+
if body.respond_to?(:read)
|
14
|
+
body = body.read
|
15
|
+
end
|
16
|
+
[200, { 'Content-Type' => posted_as }, body]
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -68,6 +73,11 @@ RSpec.describe Faraday::Request::UrlEncoded do
|
|
68
73
|
expect(response.body).to eq('a%5Bb%5D%5Bc%5D%5B%5D=d')
|
69
74
|
end
|
70
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
|
+
|
71
81
|
context 'customising default_space_encoding' do
|
72
82
|
around do |example|
|
73
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://
|
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
|
@@ -22,23 +23,12 @@ RSpec.describe Faraday::Request do
|
|
22
23
|
it { expect(subject.http_method).to eq(:post) }
|
23
24
|
end
|
24
25
|
|
25
|
-
describe 'deprecate method for HTTP method' do
|
26
|
-
let(:http_method) { :post }
|
27
|
-
let(:expected_warning) do
|
28
|
-
%r{NOTE: Faraday::Request#method is deprecated; use http_method instead\. It will be removed in or after version 2.0 \nFaraday::Request#method called from .+/spec/faraday/request_spec.rb:\d+.}
|
29
|
-
end
|
30
|
-
|
31
|
-
it { expect(subject.method).to eq(:post) }
|
32
|
-
|
33
|
-
it { expect { subject.method }.to output(expected_warning).to_stderr }
|
34
|
-
end
|
35
|
-
|
36
26
|
context 'when setting the url on setup with a URI' do
|
37
27
|
let(:block) { proc { |req| req.url URI.parse('foo.json?a=1') } }
|
38
28
|
|
39
29
|
it { expect(subject.path).to eq(URI.parse('foo.json')) }
|
40
30
|
it { expect(subject.params).to eq('a' => '1') }
|
41
|
-
it { expect(subject.to_env(conn).url.to_s).to eq('http://
|
31
|
+
it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
|
42
32
|
end
|
43
33
|
|
44
34
|
context 'when setting the url on setup with a string path and params' do
|
@@ -46,7 +36,7 @@ RSpec.describe Faraday::Request do
|
|
46
36
|
|
47
37
|
it { expect(subject.path).to eq('foo.json') }
|
48
38
|
it { expect(subject.params).to eq('a' => 1) }
|
49
|
-
it { expect(subject.to_env(conn).url.to_s).to eq('http://
|
39
|
+
it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
|
50
40
|
end
|
51
41
|
|
52
42
|
context 'when setting the url on setup with a path including params' do
|
@@ -54,7 +44,7 @@ RSpec.describe Faraday::Request do
|
|
54
44
|
|
55
45
|
it { expect(subject.path).to eq('foo.json') }
|
56
46
|
it { expect(subject.params).to eq('a' => '1', 'b' => '2') }
|
57
|
-
it { expect(subject.to_env(conn).url.to_s).to eq('http://
|
47
|
+
it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1&b=2') }
|
58
48
|
end
|
59
49
|
|
60
50
|
context 'when setting a header on setup with []= syntax' do
|
@@ -76,12 +76,10 @@ RSpec.describe Faraday::Response::Json, type: :response do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'includes the response on the ParsingError instance' do
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
expect(e.response).to be_a(Faraday::Response)
|
84
|
-
end
|
79
|
+
process('{') { |env| env[:response] = Faraday::Response.new }
|
80
|
+
raise 'Parsing should have failed.'
|
81
|
+
rescue Faraday::ParsingError => e
|
82
|
+
expect(e.response).to be_a(Faraday::Response)
|
85
83
|
end
|
86
84
|
|
87
85
|
context 'HEAD responses' do
|
@@ -116,4 +114,93 @@ RSpec.describe Faraday::Response::Json, type: :response do
|
|
116
114
|
expect(response.body).to eq(result)
|
117
115
|
end
|
118
116
|
end
|
117
|
+
|
118
|
+
context 'with decoder' do
|
119
|
+
let(:decoder) do
|
120
|
+
double('Decoder').tap do |e|
|
121
|
+
allow(e).to receive(:load) { |s, opts| JSON.parse(s, opts) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
let(:body) { '{"a": 1}' }
|
126
|
+
let(:result) { { a: 1 } }
|
127
|
+
|
128
|
+
context 'when decoder is passed as object' do
|
129
|
+
let(:options) do
|
130
|
+
{
|
131
|
+
parser_options: {
|
132
|
+
decoder: decoder,
|
133
|
+
option: :option_value,
|
134
|
+
symbolize_names: true
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'passes relevant options to specified decoder\'s load method' do
|
140
|
+
expect(decoder).to receive(:load)
|
141
|
+
.with(body, { option: :option_value, symbolize_names: true })
|
142
|
+
.and_return(result)
|
143
|
+
|
144
|
+
response = process(body)
|
145
|
+
expect(response.body).to eq(result)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when decoder is passed as an object-method pair' do
|
150
|
+
let(:options) do
|
151
|
+
{
|
152
|
+
parser_options: {
|
153
|
+
decoder: [decoder, :load],
|
154
|
+
option: :option_value,
|
155
|
+
symbolize_names: true
|
156
|
+
}
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'passes relevant options to specified decoder\'s method' do
|
161
|
+
expect(decoder).to receive(:load)
|
162
|
+
.with(body, { option: :option_value, symbolize_names: true })
|
163
|
+
.and_return(result)
|
164
|
+
|
165
|
+
response = process(body)
|
166
|
+
expect(response.body).to eq(result)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when decoder is not passed' do
|
171
|
+
let(:options) do
|
172
|
+
{
|
173
|
+
parser_options: {
|
174
|
+
symbolize_names: true
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'passes relevant options to JSON parse' do
|
180
|
+
expect(JSON).to receive(:parse)
|
181
|
+
.with(body, { symbolize_names: true })
|
182
|
+
.and_return(result)
|
183
|
+
|
184
|
+
response = process(body)
|
185
|
+
expect(response.body).to eq(result)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'passes relevant options to JSON parse even when nil responds to :load' do
|
189
|
+
original_allow_message_expectations_on_nil = RSpec::Mocks.configuration.allow_message_expectations_on_nil
|
190
|
+
RSpec::Mocks.configuration.allow_message_expectations_on_nil = true
|
191
|
+
allow(nil).to receive(:respond_to?)
|
192
|
+
.with(:load)
|
193
|
+
.and_return(true)
|
194
|
+
|
195
|
+
expect(JSON).to receive(:parse)
|
196
|
+
.with(body, { symbolize_names: true })
|
197
|
+
.and_return(result)
|
198
|
+
|
199
|
+
response = process(body)
|
200
|
+
expect(response.body).to eq(result)
|
201
|
+
ensure
|
202
|
+
RSpec::Mocks.configuration.allow_message_expectations_on_nil = original_allow_message_expectations_on_nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
119
206
|
end
|
@@ -25,6 +25,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
25
25
|
stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
|
26
26
|
stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
|
27
27
|
stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] }
|
28
|
+
stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' }
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -54,6 +55,26 @@ RSpec.describe Faraday::Response::Logger do
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
context 'when logger with program name' do
|
59
|
+
let(:logger) { Logger.new(string_io, progname: 'my_best_program') }
|
60
|
+
|
61
|
+
it 'logs with program name' do
|
62
|
+
conn.get '/hello'
|
63
|
+
|
64
|
+
expect(string_io.string).to match('-- my_best_program: request:')
|
65
|
+
expect(string_io.string).to match('-- my_best_program: response:')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when logger without program name' do
|
70
|
+
it 'logs without program name' do
|
71
|
+
conn.get '/hello'
|
72
|
+
|
73
|
+
expect(string_io.string).to match('-- : request:')
|
74
|
+
expect(string_io.string).to match('-- : response:')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
57
78
|
context 'with default formatter' do
|
58
79
|
let(:formatter) { instance_double(Faraday::Logging::Formatter, request: true, response: true, filter: []) }
|
59
80
|
|
@@ -64,6 +85,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
64
85
|
expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
|
65
86
|
conn.get '/hello'
|
66
87
|
end
|
88
|
+
|
89
|
+
context 'when no route' do
|
90
|
+
it 'delegates logging to the formatter' do
|
91
|
+
expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
|
92
|
+
expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
|
93
|
+
|
94
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
95
|
+
end
|
96
|
+
end
|
67
97
|
end
|
68
98
|
|
69
99
|
context 'with custom formatter' do
|
@@ -94,6 +124,16 @@ RSpec.describe Faraday::Response::Logger do
|
|
94
124
|
expect(string_io.string).to match('GET http:/hello')
|
95
125
|
end
|
96
126
|
|
127
|
+
it 'logs status' do
|
128
|
+
conn.get '/hello', nil, accept: 'text/html'
|
129
|
+
expect(string_io.string).to match('Status 200')
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'does not log error message by default' do
|
133
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
134
|
+
expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
|
135
|
+
end
|
136
|
+
|
97
137
|
it 'logs request headers by default' do
|
98
138
|
conn.get '/hello', nil, accept: 'text/html'
|
99
139
|
expect(string_io.string).to match(%(Accept: "text/html))
|
@@ -149,7 +189,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
149
189
|
context 'when logging request body' do
|
150
190
|
let(:logger_options) { { bodies: { request: true } } }
|
151
191
|
|
152
|
-
it '
|
192
|
+
it 'logs only request body' do
|
153
193
|
conn.post '/ohyes', 'name=Tamago', accept: 'text/html'
|
154
194
|
expect(string_io.string).to match(%(name=Tamago))
|
155
195
|
expect(string_io.string).not_to match(%(pebbles))
|
@@ -159,7 +199,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
159
199
|
context 'when logging response body' do
|
160
200
|
let(:logger_options) { { bodies: { response: true } } }
|
161
201
|
|
162
|
-
it '
|
202
|
+
it 'logs only response body' do
|
163
203
|
conn.post '/ohyes', 'name=Hamachi', accept: 'text/html'
|
164
204
|
expect(string_io.string).to match(%(pebbles))
|
165
205
|
expect(string_io.string).not_to match(%(name=Hamachi))
|
@@ -169,13 +209,13 @@ RSpec.describe Faraday::Response::Logger do
|
|
169
209
|
context 'when logging request and response bodies' do
|
170
210
|
let(:logger_options) { { bodies: true } }
|
171
211
|
|
172
|
-
it '
|
212
|
+
it 'logs request and response body' do
|
173
213
|
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
174
214
|
expect(string_io.string).to match(%(name=Ebi))
|
175
215
|
expect(string_io.string).to match(%(pebbles))
|
176
216
|
end
|
177
217
|
|
178
|
-
it '
|
218
|
+
it 'logs response body object' do
|
179
219
|
conn.get '/rubbles', nil, accept: 'text/html'
|
180
220
|
expect(string_io.string).to match(%([\"Barney\", \"Betty\", \"Bam Bam\"]\n))
|
181
221
|
end
|
@@ -188,6 +228,39 @@ RSpec.describe Faraday::Response::Logger do
|
|
188
228
|
end
|
189
229
|
end
|
190
230
|
|
231
|
+
context 'when bodies are logged by default' do
|
232
|
+
before do
|
233
|
+
described_class.default_options = { bodies: true }
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'logs response body' do
|
237
|
+
conn.post '/ohai'
|
238
|
+
expect(string_io.string).to match(%(fred))
|
239
|
+
end
|
240
|
+
|
241
|
+
after do
|
242
|
+
described_class.default_options = { bodies: false }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when logging errors' do
|
247
|
+
let(:logger_options) { { errors: true } }
|
248
|
+
|
249
|
+
it 'logs error message' do
|
250
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
251
|
+
expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'when logging headers and errors' do
|
256
|
+
let(:logger_options) { { headers: true, errors: true } }
|
257
|
+
|
258
|
+
it 'logs error message' do
|
259
|
+
expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed)
|
260
|
+
expect(string_io.string).to match(%(Failed to open TCP connection))
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
191
264
|
context 'when using log_level' do
|
192
265
|
let(:logger_options) { { bodies: true, log_level: :debug } }
|
193
266
|
|
@@ -11,8 +11,10 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
11
11
|
stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
|
12
12
|
stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
|
13
13
|
stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
|
14
|
+
stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
|
14
15
|
stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
|
15
16
|
stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
|
17
|
+
stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] }
|
16
18
|
stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
|
17
19
|
stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
|
18
20
|
stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
|
@@ -79,6 +81,17 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
it 'raises Faraday::RequestTimeoutError for 408 responses' do
|
85
|
+
expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
|
86
|
+
expect(ex.message).to eq('the server responded with status 408')
|
87
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
88
|
+
expect(ex.response[:status]).to eq(408)
|
89
|
+
expect(ex.response_status).to eq(408)
|
90
|
+
expect(ex.response_body).to eq('keep looking')
|
91
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
82
95
|
it 'raises Faraday::ConflictError for 409 responses' do
|
83
96
|
expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
|
84
97
|
expect(ex.message).to eq('the server responded with status 409')
|
@@ -101,6 +114,17 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
117
|
+
it 'raises Faraday::TooManyRequestsError for 429 responses' do
|
118
|
+
expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex|
|
119
|
+
expect(ex.message).to eq('the server responded with status 429')
|
120
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
121
|
+
expect(ex.response[:status]).to eq(429)
|
122
|
+
expect(ex.response_status).to eq(429)
|
123
|
+
expect(ex.response_body).to eq('keep looking')
|
124
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
104
128
|
it 'raises Faraday::NilStatusError for nil status in response' do
|
105
129
|
expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex|
|
106
130
|
expect(ex.message).to eq('http status could not be derived from the server response')
|
@@ -137,21 +161,24 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
137
161
|
describe 'request info' do
|
138
162
|
let(:conn) do
|
139
163
|
Faraday.new do |b|
|
140
|
-
b.response :raise_error
|
164
|
+
b.response :raise_error, **middleware_options
|
141
165
|
b.adapter :test do |stub|
|
142
|
-
stub.post(
|
166
|
+
stub.post(url, request_body, request_headers) do
|
143
167
|
[400, { 'X-Reason' => 'because' }, 'keep looking']
|
144
168
|
end
|
145
169
|
end
|
146
170
|
end
|
147
171
|
end
|
172
|
+
let(:middleware_options) { {} }
|
148
173
|
let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
|
149
174
|
let(:request_headers) { { 'Authorization' => 'Basic 123' } }
|
175
|
+
let(:url_path) { 'request' }
|
176
|
+
let(:query_params) { 'full=true' }
|
177
|
+
let(:url) { "#{url_path}?#{query_params}" }
|
150
178
|
|
151
179
|
subject(:perform_request) do
|
152
|
-
conn.post
|
180
|
+
conn.post url do |req|
|
153
181
|
req.headers['Authorization'] = 'Basic 123'
|
154
|
-
req.params[:full] = true
|
155
182
|
req.body = request_body
|
156
183
|
end
|
157
184
|
end
|
@@ -159,11 +186,90 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
159
186
|
it 'returns the request info in the exception' do
|
160
187
|
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
161
188
|
expect(ex.response[:request][:method]).to eq(:post)
|
162
|
-
expect(ex.response[:request][:
|
189
|
+
expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
|
190
|
+
expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
|
163
191
|
expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
|
164
192
|
expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
|
165
193
|
expect(ex.response[:request][:body]).to eq(request_body)
|
166
194
|
end
|
167
195
|
end
|
196
|
+
|
197
|
+
describe 'DEFAULT_OPTION: include_request' do
|
198
|
+
before(:each) do
|
199
|
+
Faraday::Response::RaiseError.instance_variable_set(:@default_options, nil)
|
200
|
+
Faraday::Middleware.instance_variable_set(:@default_options, nil)
|
201
|
+
end
|
202
|
+
|
203
|
+
after(:all) do
|
204
|
+
Faraday::Response::RaiseError.instance_variable_set(:@default_options, nil)
|
205
|
+
Faraday::Middleware.instance_variable_set(:@default_options, nil)
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'when RaiseError DEFAULT_OPTION (include_request: true) is used' do
|
209
|
+
it 'includes request info in the exception' do
|
210
|
+
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
211
|
+
expect(ex.response.keys).to contain_exactly(
|
212
|
+
:status,
|
213
|
+
:headers,
|
214
|
+
:body,
|
215
|
+
:request
|
216
|
+
)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'when application sets default_options `include_request: false`' do
|
222
|
+
before(:each) do
|
223
|
+
Faraday::Response::RaiseError.default_options = { include_request: false }
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'and when include_request option is omitted' do
|
227
|
+
it 'does not include request info in the exception' do
|
228
|
+
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
229
|
+
expect(ex.response.keys).to contain_exactly(
|
230
|
+
:status,
|
231
|
+
:headers,
|
232
|
+
:body
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'and when include_request option is explicitly set for instance' do
|
239
|
+
let(:middleware_options) { { include_request: true } }
|
240
|
+
|
241
|
+
it 'includes request info in the exception' do
|
242
|
+
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
243
|
+
expect(ex.response.keys).to contain_exactly(
|
244
|
+
:status,
|
245
|
+
:headers,
|
246
|
+
:body,
|
247
|
+
:request
|
248
|
+
)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe 'allowing certain status codes' do
|
257
|
+
let(:conn) do
|
258
|
+
Faraday.new do |b|
|
259
|
+
b.response :raise_error, allowed_statuses: [404]
|
260
|
+
b.adapter :test do |stub|
|
261
|
+
stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] }
|
262
|
+
stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'raises an error for status codes that are not explicitly allowed' do
|
268
|
+
expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError)
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'does not raise an error for allowed status codes' do
|
272
|
+
expect { conn.get('not-found') }.not_to raise_error
|
273
|
+
end
|
168
274
|
end
|
169
275
|
end
|
@@ -4,7 +4,7 @@ RSpec.describe Faraday::Response do
|
|
4
4
|
subject { Faraday::Response.new(env) }
|
5
5
|
|
6
6
|
let(:env) do
|
7
|
-
Faraday::Env.from(status: 404, body: 'yikes',
|
7
|
+
Faraday::Env.from(status: 404, body: 'yikes', url: Faraday::Utils.URI('https://lostisland.github.io/faraday'),
|
8
8
|
response_headers: { 'Content-Type' => 'text/plain' })
|
9
9
|
end
|
10
10
|
|
@@ -30,6 +30,7 @@ RSpec.describe Faraday::Response do
|
|
30
30
|
it { expect(hash[:status]).to eq(subject.status) }
|
31
31
|
it { expect(hash[:response_headers]).to eq(subject.headers) }
|
32
32
|
it { expect(hash[:body]).to eq(subject.body) }
|
33
|
+
it { expect(hash[:url]).to eq(subject.env.url) }
|
33
34
|
end
|
34
35
|
|
35
36
|
describe 'marshal serialization support' do
|
@@ -45,6 +46,7 @@ RSpec.describe Faraday::Response do
|
|
45
46
|
it { expect(loaded.env[:body]).to eq(env[:body]) }
|
46
47
|
it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) }
|
47
48
|
it { expect(loaded.env[:status]).to eq(env[:status]) }
|
49
|
+
it { expect(loaded.env[:url]).to eq(env[:url]) }
|
48
50
|
end
|
49
51
|
|
50
52
|
describe '#on_complete' do
|