This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user