This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Faraday::Response::Json, type: :response do
|
||||
let(:options) { {} }
|
||||
let(:headers) { {} }
|
||||
let(:middleware) do
|
||||
described_class.new(lambda { |env|
|
||||
Faraday::Response.new(env)
|
||||
}, **options)
|
||||
end
|
||||
|
||||
def process(body, content_type = 'application/json', options = {})
|
||||
env = {
|
||||
body: body, request: options,
|
||||
request_headers: Faraday::Utils::Headers.new,
|
||||
response_headers: Faraday::Utils::Headers.new(headers)
|
||||
}
|
||||
env[:response_headers]['content-type'] = content_type if content_type
|
||||
yield(env) if block_given?
|
||||
middleware.call(Faraday::Env.from(env))
|
||||
end
|
||||
|
||||
context 'no type matching' do
|
||||
it "doesn't change nil body" do
|
||||
expect(process(nil).body).to be_nil
|
||||
end
|
||||
|
||||
it 'nullifies empty body' do
|
||||
expect(process('').body).to be_nil
|
||||
end
|
||||
|
||||
it 'parses json body' do
|
||||
response = process('{"a":1}')
|
||||
expect(response.body).to eq('a' => 1)
|
||||
expect(response.env[:raw_body]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'with preserving raw' do
|
||||
let(:options) { { preserve_raw: true } }
|
||||
|
||||
it 'parses json body' do
|
||||
response = process('{"a":1}')
|
||||
expect(response.body).to eq('a' => 1)
|
||||
expect(response.env[:raw_body]).to eq('{"a":1}')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with default regexp type matching' do
|
||||
it 'parses json body of correct type' do
|
||||
response = process('{"a":1}', 'application/x-json')
|
||||
expect(response.body).to eq('a' => 1)
|
||||
end
|
||||
|
||||
it 'ignores json body of incorrect type' do
|
||||
response = process('{"a":1}', 'text/json-xml')
|
||||
expect(response.body).to eq('{"a":1}')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with array type matching' do
|
||||
let(:options) { { content_type: %w[a/b c/d] } }
|
||||
|
||||
it 'parses json body of correct type' do
|
||||
expect(process('{"a":1}', 'a/b').body).to be_a(Hash)
|
||||
expect(process('{"a":1}', 'c/d').body).to be_a(Hash)
|
||||
end
|
||||
|
||||
it 'ignores json body of incorrect type' do
|
||||
expect(process('{"a":1}', 'a/d').body).not_to be_a(Hash)
|
||||
end
|
||||
end
|
||||
|
||||
it 'chokes on invalid json' do
|
||||
expect { process('{!') }.to raise_error(Faraday::ParsingError)
|
||||
end
|
||||
|
||||
it 'includes the response on the ParsingError instance' do
|
||||
process('{') { |env| env[:response] = Faraday::Response.new }
|
||||
raise 'Parsing should have failed.'
|
||||
rescue Faraday::ParsingError => e
|
||||
expect(e.response).to be_a(Faraday::Response)
|
||||
end
|
||||
|
||||
context 'HEAD responses' do
|
||||
it "nullifies the body if it's only one space" do
|
||||
response = process(' ')
|
||||
expect(response.body).to be_nil
|
||||
end
|
||||
|
||||
it "nullifies the body if it's two spaces" do
|
||||
response = process(' ')
|
||||
expect(response.body).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'JSON options' do
|
||||
let(:body) { '{"a": 1}' }
|
||||
let(:result) { { a: 1 } }
|
||||
let(:options) do
|
||||
{
|
||||
parser_options: {
|
||||
symbolize_names: true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'passes relevant options to JSON parse' do
|
||||
expect(::JSON).to receive(:parse)
|
||||
.with(body, options[:parser_options])
|
||||
.and_return(result)
|
||||
|
||||
response = process(body)
|
||||
expect(response.body).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with decoder' do
|
||||
let(:decoder) do
|
||||
double('Decoder').tap do |e|
|
||||
allow(e).to receive(:load) { |s, opts| JSON.parse(s, opts) }
|
||||
end
|
||||
end
|
||||
|
||||
let(:body) { '{"a": 1}' }
|
||||
let(:result) { { a: 1 } }
|
||||
|
||||
context 'when decoder is passed as object' do
|
||||
let(:options) do
|
||||
{
|
||||
parser_options: {
|
||||
decoder: decoder,
|
||||
option: :option_value,
|
||||
symbolize_names: true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'passes relevant options to specified decoder\'s load method' do
|
||||
expect(decoder).to receive(:load)
|
||||
.with(body, { option: :option_value, symbolize_names: true })
|
||||
.and_return(result)
|
||||
|
||||
response = process(body)
|
||||
expect(response.body).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when decoder is passed as an object-method pair' do
|
||||
let(:options) do
|
||||
{
|
||||
parser_options: {
|
||||
decoder: [decoder, :load],
|
||||
option: :option_value,
|
||||
symbolize_names: true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'passes relevant options to specified decoder\'s method' do
|
||||
expect(decoder).to receive(:load)
|
||||
.with(body, { option: :option_value, symbolize_names: true })
|
||||
.and_return(result)
|
||||
|
||||
response = process(body)
|
||||
expect(response.body).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when decoder is not passed' do
|
||||
let(:options) do
|
||||
{
|
||||
parser_options: {
|
||||
symbolize_names: true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'passes relevant options to JSON parse' do
|
||||
expect(JSON).to receive(:parse)
|
||||
.with(body, { symbolize_names: true })
|
||||
.and_return(result)
|
||||
|
||||
response = process(body)
|
||||
expect(response.body).to eq(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,258 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'stringio'
|
||||
require 'logger'
|
||||
|
||||
RSpec.describe Faraday::Response::Logger do
|
||||
let(:string_io) { StringIO.new }
|
||||
let(:logger) { Logger.new(string_io) }
|
||||
let(:logger_options) { {} }
|
||||
let(:conn) do
|
||||
rubbles = ['Barney', 'Betty', 'Bam Bam']
|
||||
|
||||
Faraday.new do |b|
|
||||
b.response :logger, logger, logger_options do |logger|
|
||||
logger.filter(/(soylent green is) (.+)/, '\1 tasty')
|
||||
logger.filter(/(api_key:).*"(.+)."/, '\1[API_KEY]')
|
||||
logger.filter(/(password)=(.+)/, '\1=[HIDDEN]')
|
||||
end
|
||||
b.adapter :test do |stubs|
|
||||
stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
|
||||
stubs.post('/ohai') { [200, { 'Content-Type' => 'text/html' }, 'fred'] }
|
||||
stubs.post('/ohyes') { [200, { 'Content-Type' => 'text/html' }, 'pebbles'] }
|
||||
stubs.get('/rubbles') { [200, { 'Content-Type' => 'application/json' }, rubbles] }
|
||||
stubs.get('/filtered_body') { [200, { 'Content-Type' => 'text/html' }, 'soylent green is people'] }
|
||||
stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
|
||||
stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
|
||||
stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] }
|
||||
stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
logger.level = Logger::DEBUG
|
||||
end
|
||||
|
||||
it 'still returns output' do
|
||||
resp = conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(resp.body).to eq('hello')
|
||||
end
|
||||
|
||||
context 'without configuration' do
|
||||
let(:conn) do
|
||||
Faraday.new do |b|
|
||||
b.response :logger
|
||||
b.adapter :test do |stubs|
|
||||
stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'defaults to stdout' do
|
||||
expect(Logger).to receive(:new).with($stdout).and_return(Logger.new(nil))
|
||||
conn.get('/hello')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with default formatter' do
|
||||
let(:formatter) { instance_double(Faraday::Logging::Formatter, request: true, response: true, filter: []) }
|
||||
|
||||
before { allow(Faraday::Logging::Formatter).to receive(:new).and_return(formatter) }
|
||||
|
||||
it 'delegates logging to the formatter' do
|
||||
expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
|
||||
expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
|
||||
conn.get '/hello'
|
||||
end
|
||||
|
||||
context 'when no route' do
|
||||
it 'delegates logging to the formatter' do
|
||||
expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
|
||||
expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
|
||||
|
||||
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with custom formatter' do
|
||||
let(:formatter_class) do
|
||||
Class.new(Faraday::Logging::Formatter) do
|
||||
def request(_env)
|
||||
info 'Custom log formatter request'
|
||||
end
|
||||
|
||||
def response(_env)
|
||||
info 'Custom log formatter response'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:logger_options) { { formatter: formatter_class } }
|
||||
|
||||
it 'logs with custom formatter' do
|
||||
conn.get '/hello'
|
||||
|
||||
expect(string_io.string).to match('Custom log formatter request')
|
||||
expect(string_io.string).to match('Custom log formatter response')
|
||||
end
|
||||
end
|
||||
|
||||
it 'logs method and url' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match('GET http:/hello')
|
||||
end
|
||||
|
||||
it 'logs status' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match('Status 200')
|
||||
end
|
||||
|
||||
it 'does not log error message by default' do
|
||||
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
||||
expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
|
||||
end
|
||||
|
||||
it 'logs request headers by default' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%(Accept: "text/html))
|
||||
end
|
||||
|
||||
it 'logs response headers by default' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%(Content-Type: "text/html))
|
||||
end
|
||||
|
||||
it 'does not log request body by default' do
|
||||
conn.post '/ohai', 'name=Unagi', accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(name=Unagi))
|
||||
end
|
||||
|
||||
it 'does not log response body by default' do
|
||||
conn.post '/ohai', 'name=Toro', accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(fred))
|
||||
end
|
||||
|
||||
it 'logs filter headers' do
|
||||
conn.headers = { 'api_key' => 'ABC123' }
|
||||
conn.get '/filtered_headers', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%(api_key:))
|
||||
expect(string_io.string).to match(%([API_KEY]))
|
||||
expect(string_io.string).not_to match(%(ABC123))
|
||||
end
|
||||
|
||||
it 'logs filter url' do
|
||||
conn.get '/filtered_url?password=hunter2', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%([HIDDEN]))
|
||||
expect(string_io.string).not_to match(%(hunter2))
|
||||
end
|
||||
|
||||
context 'when not logging request headers' do
|
||||
let(:logger_options) { { headers: { request: false } } }
|
||||
|
||||
it 'does not log request headers if option is false' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(Accept: "text/html))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not logging response headers' do
|
||||
let(:logger_options) { { headers: { response: false } } }
|
||||
|
||||
it 'does not log response headers if option is false' do
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(Content-Type: "text/html))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logging request body' do
|
||||
let(:logger_options) { { bodies: { request: true } } }
|
||||
|
||||
it 'log only request body' do
|
||||
conn.post '/ohyes', 'name=Tamago', accept: 'text/html'
|
||||
expect(string_io.string).to match(%(name=Tamago))
|
||||
expect(string_io.string).not_to match(%(pebbles))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logging response body' do
|
||||
let(:logger_options) { { bodies: { response: true } } }
|
||||
|
||||
it 'log only response body' do
|
||||
conn.post '/ohyes', 'name=Hamachi', accept: 'text/html'
|
||||
expect(string_io.string).to match(%(pebbles))
|
||||
expect(string_io.string).not_to match(%(name=Hamachi))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logging request and response bodies' do
|
||||
let(:logger_options) { { bodies: true } }
|
||||
|
||||
it 'log request and response body' do
|
||||
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
||||
expect(string_io.string).to match(%(name=Ebi))
|
||||
expect(string_io.string).to match(%(pebbles))
|
||||
end
|
||||
|
||||
it 'log response body object' do
|
||||
conn.get '/rubbles', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%([\"Barney\", \"Betty\", \"Bam Bam\"]\n))
|
||||
end
|
||||
|
||||
it 'logs filter body' do
|
||||
conn.get '/filtered_body', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%(soylent green is))
|
||||
expect(string_io.string).to match(%(tasty))
|
||||
expect(string_io.string).not_to match(%(people))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logging errors' do
|
||||
let(:logger_options) { { errors: true } }
|
||||
|
||||
it 'logs error message' do
|
||||
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
||||
expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when logging headers and errors' do
|
||||
let(:logger_options) { { headers: true, errors: true } }
|
||||
|
||||
it 'logs error message' do
|
||||
expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed)
|
||||
expect(string_io.string).to match(%(Failed to open TCP connection))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when using log_level' do
|
||||
let(:logger_options) { { bodies: true, log_level: :debug } }
|
||||
|
||||
it 'logs request/request body on the specified level (debug)' do
|
||||
logger.level = Logger::DEBUG
|
||||
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
||||
expect(string_io.string).to match(%(name=Ebi))
|
||||
expect(string_io.string).to match(%(pebbles))
|
||||
end
|
||||
|
||||
it 'logs headers on the debug level' do
|
||||
logger.level = Logger::DEBUG
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).to match(%(Content-Type: "text/html))
|
||||
end
|
||||
|
||||
it 'does not log request/response body on the info level' do
|
||||
logger.level = Logger::INFO
|
||||
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(name=Ebi))
|
||||
expect(string_io.string).not_to match(%(pebbles))
|
||||
end
|
||||
|
||||
it 'does not log headers on the info level' do
|
||||
logger.level = Logger::INFO
|
||||
conn.get '/hello', nil, accept: 'text/html'
|
||||
expect(string_io.string).not_to match(%(Content-Type: "text/html))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,211 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Faraday::Response::RaiseError do
|
||||
let(:conn) do
|
||||
Faraday.new do |b|
|
||||
b.response :raise_error
|
||||
b.adapter :test do |stub|
|
||||
stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
|
||||
stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('unauthorized') { [401, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
|
||||
stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
|
||||
stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises no exception for 200 responses' do
|
||||
expect { conn.get('ok') }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'raises Faraday::BadRequestError for 400 responses' do
|
||||
expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 400')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(400)
|
||||
expect(ex.response_status).to eq(400)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::UnauthorizedError for 401 responses' do
|
||||
expect { conn.get('unauthorized') }.to raise_error(Faraday::UnauthorizedError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 401')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(401)
|
||||
expect(ex.response_status).to eq(401)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ForbiddenError for 403 responses' do
|
||||
expect { conn.get('forbidden') }.to raise_error(Faraday::ForbiddenError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 403')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(403)
|
||||
expect(ex.response_status).to eq(403)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ResourceNotFound for 404 responses' do
|
||||
expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 404')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(404)
|
||||
expect(ex.response_status).to eq(404)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ProxyAuthError for 407 responses' do
|
||||
expect { conn.get('proxy-error') }.to raise_error(Faraday::ProxyAuthError) do |ex|
|
||||
expect(ex.message).to eq('407 "Proxy Authentication Required"')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(407)
|
||||
expect(ex.response_status).to eq(407)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::RequestTimeoutError for 408 responses' do
|
||||
expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 408')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(408)
|
||||
expect(ex.response_status).to eq(408)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ConflictError for 409 responses' do
|
||||
expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 409')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(409)
|
||||
expect(ex.response_status).to eq(409)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::UnprocessableEntityError for 422 responses' do
|
||||
expect { conn.get('unprocessable-entity') }.to raise_error(Faraday::UnprocessableEntityError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 422')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(422)
|
||||
expect(ex.response_status).to eq(422)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::TooManyRequestsError for 429 responses' do
|
||||
expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 429')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(429)
|
||||
expect(ex.response_status).to eq(429)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::NilStatusError for nil status in response' do
|
||||
expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex|
|
||||
expect(ex.message).to eq('http status could not be derived from the server response')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('nil')
|
||||
expect(ex.response[:status]).to be_nil
|
||||
expect(ex.response_status).to be_nil
|
||||
expect(ex.response_body).to eq('fail')
|
||||
expect(ex.response_headers['X-Reason']).to eq('nil')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ClientError for other 4xx responses' do
|
||||
expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 499')
|
||||
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
||||
expect(ex.response[:status]).to eq(499)
|
||||
expect(ex.response_status).to eq(499)
|
||||
expect(ex.response_body).to eq('keep looking')
|
||||
expect(ex.response_headers['X-Reason']).to eq('because')
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises Faraday::ServerError for 500 responses' do
|
||||
expect { conn.get('server-error') }.to raise_error(Faraday::ServerError) do |ex|
|
||||
expect(ex.message).to eq('the server responded with status 500')
|
||||
expect(ex.response[:headers]['X-Error']).to eq('bailout')
|
||||
expect(ex.response[:status]).to eq(500)
|
||||
expect(ex.response_status).to eq(500)
|
||||
expect(ex.response_body).to eq('fail')
|
||||
expect(ex.response_headers['X-Error']).to eq('bailout')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'request info' do
|
||||
let(:conn) do
|
||||
Faraday.new do |b|
|
||||
b.response :raise_error, **middleware_options
|
||||
b.adapter :test do |stub|
|
||||
stub.post(url, request_body, request_headers) do
|
||||
[400, { 'X-Reason' => 'because' }, 'keep looking']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
let(:middleware_options) { {} }
|
||||
let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
|
||||
let(:request_headers) { { 'Authorization' => 'Basic 123' } }
|
||||
let(:url_path) { 'request' }
|
||||
let(:query_params) { 'full=true' }
|
||||
let(:url) { "#{url_path}?#{query_params}" }
|
||||
|
||||
subject(:perform_request) do
|
||||
conn.post url do |req|
|
||||
req.headers['Authorization'] = 'Basic 123'
|
||||
req.body = request_body
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the request info in the exception' do
|
||||
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
||||
expect(ex.response[:request][:method]).to eq(:post)
|
||||
expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
|
||||
expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
|
||||
expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
|
||||
expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
|
||||
expect(ex.response[:request][:body]).to eq(request_body)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the include_request option is set to false' do
|
||||
let(:middleware_options) { { include_request: false } }
|
||||
|
||||
it 'does not include request info in the exception' do
|
||||
expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
|
||||
expect(ex.response.keys).to contain_exactly(
|
||||
:status,
|
||||
:headers,
|
||||
:body
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user