spec/lib/http_log_spec.rb in httplog-1.1.1 vs spec/lib/http_log_spec.rb in httplog-1.2.0

- old
+ new

@@ -1,17 +1,60 @@ # frozen_string_literal: true require 'spec_helper' describe HttpLog do - let(:host) { 'localhost' } - let(:port) { 9292 } - let(:path) { '/index.html' } + subject { log } # see spec_helper + + let(:host) { 'localhost' } + let(:port) { 9292 } + let(:path) { '/index.html' } let(:headers) { { 'accept' => '*/*', 'foo' => 'bar' } } - let(:data) { 'foo=bar&bar=foo' } - let(:params) { { 'foo' => 'bar:form-data', 'bar' => 'foo' } } + let(:data) { 'foo=bar&bar=foo' } + let(:params) { { 'foo' => 'bar:form-data', 'bar' => 'foo' } } + let(:html) { File.read('./spec/support/index.html') } + let(:json) { JSON.parse(log.match(/\[httplog\]\s(.*)/).captures.first) } + # Configuration + let(:enabled) { HttpLog.configuration.enabled } + let(:severity) { HttpLog.configuration.severity } + let(:log_headers) { HttpLog.configuration.log_headers } + let(:log_request) { HttpLog.configuration.log_request } + let(:log_response) { HttpLog.configuration.log_response } + let(:log_data) { HttpLog.configuration.log_data } + let(:log_connect) { HttpLog.configuration.log_connect } + let(:log_benchmark) { HttpLog.configuration.log_benchmark } + let(:color) { HttpLog.configuration.color } + let(:prefix) { HttpLog.configuration.prefix } + let(:prefix_response_lines) { HttpLog.configuration.prefix_response_lines } + let(:prefix_line_numbers) { HttpLog.configuration.prefix_line_numbers } + let(:json_log) { HttpLog.configuration.json_log } + let(:compact_log) { HttpLog.configuration.compact_log } + let(:url_blacklist_pattern) { HttpLog.configuration.url_blacklist_pattern } + let(:url_whitelist_pattern) { HttpLog.configuration.url_whitelist_pattern } + + def configure + HttpLog.configure do |c| + c.enabled = enabled + c.severity = severity + c.log_headers = log_headers + c.log_request = log_request + c.log_response = log_response + c.log_data = log_data + c.log_connect = log_connect + c.log_benchmark = log_benchmark + c.color = color + c.prefix = prefix + c.prefix_response_lines = prefix_response_lines + c.prefix_line_numbers = prefix_line_numbers + c.json_log = json_log + c.compact_log = compact_log + c.url_blacklist_pattern = url_blacklist_pattern + c.url_whitelist_pattern = url_whitelist_pattern + end + end + ADAPTERS = [ NetHTTPAdapter, OpenUriAdapter, HTTPClientAdapter, HTTPartyAdapter, @@ -23,309 +66,245 @@ ].freeze ADAPTERS.each do |adapter_class| context adapter_class, adapter: adapter_class.to_s do let(:adapter) { adapter_class.new(host: host, port: port, path: path, headers: headers, data: data, params: params) } + before { configure } context 'with default configuration' do - connection_test_method = adapter_class.is_libcurl? ? :to_not : :to + describe 'GET requests' do + let!(:res) { adapter.send_get_request } - if adapter_class.method_defined? :send_get_request - it 'should log GET requests' do - res = adapter.send_get_request + it_behaves_like 'logs request', 'GET' + it_behaves_like 'logs data' + it_behaves_like 'logs expected response' + it_behaves_like 'logs status', 200 + it_behaves_like 'logs benchmark' - expect(log).send(connection_test_method, include(HttpLog::LOG_PREFIX + "Connecting: #{host}:#{port}")) + it { is_expected.to_not include('Header:') } + it { is_expected.to_not include("\e[0") } - expect(log).to include(HttpLog::LOG_PREFIX + "Sending: GET http://#{host}:#{port}#{path}") - expect(log).to include(HttpLog::LOG_PREFIX + 'Data:') - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Header:') - expect(log).to include(HttpLog::LOG_PREFIX + 'Status: 200') - expect(log).to include(HttpLog::LOG_PREFIX + 'Benchmark: ') - expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}") - - expect(log).to_not include("\e[0") - - expect(res).to be_a adapter.response if adapter.respond_to? :response + unless adapter_class.is_libcurl? + it { is_expected.to include("Connecting: #{host}:#{port}") } end + it { expect(res).to be_a adapter.response if adapter.respond_to? :response } + context 'with gzip encoding' do let(:path) { '/index.html.gz' } let(:data) { nil } - it 'decompresses gzipped response body' do - adapter.send_get_request - expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}") - end + it_behaves_like 'logs expected response' if adapter_class.method_defined? :send_head_request it "doesn't try to decompress body for HEAD requests" do - adapter.send_head_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Response:') + expect(log).to include('Response:') end end end context 'with UTF-8 response body' do let(:path) { '/utf8.html' } let(:data) { nil } - it 'works' do - adapter.send_get_request - expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}") - if adapter.logs_data? - expect(log).to include(' <title>Блог Яндекса</title>') - end - end + it_behaves_like 'logs expected response' + it { is_expected.to include(' <title>Блог Яндекса</title>') if adapter.logs_data? } end context 'with binary response body' do - let(:path) { '/test.bin' } - let(:data) { nil } + %w[/test.bin /test.pdf].each do |response_file_name| + let(:path) { response_file_name } + let(:data) { nil } - it "doesn't log response" do - adapter.send_get_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Response: (not showing binary data)') + it { is_expected.to include('Response: (not showing binary data)') } + + context 'and JSON logging' do + let(:json_log) { true } + it { expect(json['response_body']).to eq '(not showing binary data)' } + end end end end - if adapter_class.method_defined? :send_post_request - it 'logs POST requests' do - res = adapter.send_post_request + describe 'POST requests' do + if adapter_class.method_defined? :send_post_request + let!(:res) { adapter.send_post_request } - expect(log).send(connection_test_method, include(HttpLog::LOG_PREFIX + "Connecting: #{host}:#{port}")) + unless adapter_class.is_libcurl? + it { is_expected.to include("Connecting: #{host}:#{port}") } + end - expect(log).to include(HttpLog::LOG_PREFIX + "Sending: POST http://#{host}:#{port}#{path}") - expect(log).to include(HttpLog::LOG_PREFIX + 'Data: foo=bar&bar=foo') - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Header:') - expect(log).to include(HttpLog::LOG_PREFIX + 'Status: 200') - expect(log).to include(HttpLog::LOG_PREFIX + 'Benchmark: ') - expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}") + it_behaves_like 'logs request', 'POST' + it_behaves_like 'logs expected response' + it_behaves_like 'logs data', 'foo=bar&bar=foo' + it_behaves_like 'logs status', 200 + it_behaves_like 'logs benchmark' - expect(res).to be_a adapter.response if adapter.respond_to? :response - end + it { is_expected.to_not include('Header:') } - context 'with non-UTF request data' do - let(:data) { "a UTF-8 striñg with an 8BIT-ASCII character: \xC3" } - it 'does not raise and error' do - expect { adapter.send_post_request }.to_not raise_error - expect(log).to include(HttpLog::LOG_PREFIX + 'Response:') + it { expect(res).to be_a adapter.response if adapter.respond_to? :response } + + context 'with non-UTF request data' do + let(:data) { "a UTF-8 striñg with an 8BIT-ASCII character: \xC3" } + it_behaves_like 'logs expected response' # == doesn't throw exception end - end - context 'with URI encoded non-UTF data' do - let(:data) { 'a UTF-8 striñg with a URI encoded 8BIT-ASCII character: %c3' } - it 'does not raise and error' do - expect { adapter.send_post_request }.to_not raise_error - expect(log).to include(HttpLog::LOG_PREFIX + 'Response:') + context 'with URI encoded non-UTF data' do + let(:data) { 'a UTF-8 striñg with a URI encoded 8BIT-ASCII character: %c3' } + it_behaves_like 'logs expected response' # == doesn't throw exception end end end end context 'with custom configuration' do context 'GET requests' do - it 'should not log anything unless enabled is set' do - HttpLog.configure { |c| c.enabled = false } - adapter.send_get_request - expect(log).to eq('') - end + before { adapter.send_get_request } - it 'should log at other levels' do - HttpLog.configure { |c| c.severity = Logger::Severity::INFO } - adapter.send_get_request - expect(log).to include('INFO') + context 'when disabled' do + let(:enabled) { false } + it_behaves_like 'logs nothing' end - it 'should log headers if enabled' do - HttpLog.configure { |c| c.log_headers = true } - adapter.send_get_request - # request header - expect(log.downcase).to include(HttpLog::LOG_PREFIX + 'Header: accept: */*'.downcase) - # response header - expect(log.downcase).to include(HttpLog::LOG_PREFIX + 'Header: server: thin'.downcase) + context 'with different log level' do + let(:severity) { Logger::Severity::INFO } + it { is_expected.to include('INFO') } end - it 'should not log headers if disabled' do - HttpLog.configure { |c| c.log_headers = false } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Header:') + context 'with headers logging' do + let(:log_headers) { true } + it { is_expected.to match(%r{Header: accept: */*}i) } # request + it { is_expected.to match(/Header: Server: thin/i) } # response end - it 'should log the request if url does not match blacklist pattern' do - HttpLog.configure { |c| c.url_blacklist_pattern = /example.com/ } - adapter.send_get_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Sending: GET') + context 'with blacklist hit' do + let(:url_blacklist_pattern) { /#{host}:#{port}/ } + it_behaves_like 'logs nothing' end - it 'should log the request if url matches whitelist pattern and not the blacklist pattern' do - HttpLog.configure { |c| c.url_blacklist_pattern = /example.com/ } - HttpLog.configure { |c| c.url_whitelist_pattern = /#{host}:#{port}/ } - adapter.send_get_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Sending: GET') + context 'with blacklist miss' do + let(:url_blacklist_pattern) { /example.com/ } + it_behaves_like 'logs request', 'GET' end - it 'should not log the request if url matches blacklist pattern' do - HttpLog.configure { |c| c.url_blacklist_pattern = /#{host}:#{port}/ } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Sending: GET') - end + context 'with whitelist hit' do + let(:url_whitelist_pattern) { /#{host}:#{port}/ } + it_behaves_like 'logs request', 'GET' - it 'should not log the request if url does not match whitelist pattern' do - HttpLog.configure { |c| c.url_whitelist_pattern = /example.com/ } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Sending: GET') + context 'and blacklist hit' do + let(:url_blacklist_pattern) { /#{host}:#{port}/ } + it_behaves_like 'logs nothing' + end end - it 'should not log the request if url matches blacklist pattern and the whitelist pattern' do - HttpLog.configure { |c| c.url_blacklist_pattern = /#{host}:#{port}/ } - HttpLog.configure { |c| c.url_whitelist_pattern = /#{host}:#{port}/ } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Sending: GET') + context 'with whitelist miss' do + let(:url_whitelist_pattern) { /example.com/ } + it_behaves_like 'logs nothing' end - it 'should not log the request if disabled' do - HttpLog.configure { |c| c.log_request = false } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Sending: GET') - end + it_behaves_like 'with request logging disabled' + it_behaves_like 'with connection logging disabled' + it_behaves_like 'data logging disabled' + it_behaves_like 'response logging disabled' + it_behaves_like 'benchmark logging disabled' - it 'should not log the connection if disabled' do - HttpLog.configure { |c| c.log_connect = false } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + "Connecting: #{host}:#{port}") + context 'with single color' do + let(:color) { :red } + it { is_expected.to include("\e[31m") } end - it 'should not log data if disabled' do - HttpLog.configure { |c| c.log_data = false } - adapter.send_get_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Data:') + context 'with color hash' do + let(:color) { { color: :black, background: :yellow } } + it { is_expected.to include("\e[30m\e[43m") } end - it 'should colorized output with single color' do - HttpLog.configure { |c| c.color = :red } - adapter.send_get_request - expect(log).to include("\e[31m") + context 'with custom prefix' do + let(:prefix) { '[my logger]' } + it { is_expected.to include('[my logger]') } + it { is_expected.to_not include(HttpLog::LOG_PREFIX) } end - it 'should colorized output with color hash' do - HttpLog.configure { |c| c.color = { color: :black, background: :yellow } } - adapter.send_get_request - expect(log).to include("\e[30m\e[43m") + context 'with custom lambda prefix' do + let(:prefix) { -> { '[custom prefix]' } } + it { is_expected.to include('[custom prefix]') } + it { is_expected.to_not include(HttpLog::LOG_PREFIX) } end - it 'should log with custom string prefix' do - HttpLog.configure { |c| c.prefix = '[my logger]' } - adapter.send_get_request - expect(log).to include('[my logger]') - expect(log).to_not include(HttpLog::LOG_PREFIX) + context 'with compact config' do + let(:compact_log) { true } + it { is_expected.to match(%r{\[httplog\] GET http://#{host}:#{port}#{path}(\?.*)? completed with status code \d{3} in (\d|\.)+}) } + it { is_expected.to_not include("Connecting: #{host}:#{port}") } + it { is_expected.to_not include('Response:') } + it { is_expected.to_not include('Data:') } + it { is_expected.to_not include('Benchmark: ') } end - - it 'should log with custom lambda prefix' do - HttpLog.configure { |c| c.prefix = -> { '[custom prefix]' } } - adapter.send_get_request - expect(log).to include('[custom prefix]') - expect(log).to_not include(HttpLog::LOG_PREFIX) - end end context 'POST requests' do if adapter_class.method_defined? :send_post_request - it 'should not log data if disabled' do - HttpLog.configure { |c| c.log_data = false } - adapter.send_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Data:') - end + before { adapter.send_post_request } - it 'should not log the response if disabled' do - HttpLog.configure { |c| c.log_response = false } - adapter.send_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Reponse:') - end - - it 'should prefix all response lines' do - HttpLog.configure { |c| c.prefix_response_lines = true } - - adapter.send_post_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Response:') - expect(log).to include(HttpLog::LOG_PREFIX + '<html>') - end - - it 'should prefix all response lines with line numbers' do - HttpLog.configure { |c| c.prefix_response_lines = true } - HttpLog.configure { |c| c.prefix_line_numbers = true } - - adapter.send_post_request - expect(log).to include(HttpLog::LOG_PREFIX + 'Response:') - expect(log).to include(HttpLog::LOG_PREFIX + '1: <html>') - end - - it 'should not log the benchmark if disabled' do - HttpLog.configure { |c| c.log_benchmark = false } - adapter.send_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Benchmark:') - end + it_behaves_like 'data logging disabled' + it_behaves_like 'response logging disabled' + it_behaves_like 'benchmark logging disabled' + it_behaves_like 'with prefix response lines' + it_behaves_like 'with line numbers' end end context 'POST form data requests' do if adapter_class.method_defined? :send_post_form_request - it 'should not log data if disabled' do - HttpLog.configure { |c| c.log_data = false } - adapter.send_post_form_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Data:') - end + before { adapter.send_post_form_request } - it 'should not log the response if disabled' do - HttpLog.configure { |c| c.log_response = false } - adapter.send_post_form_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Reponse:') - end - - it 'should not log the benchmark if disabled' do - HttpLog.configure { |c| c.log_benchmark = false } - adapter.send_post_form_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Benchmark:') - end + it_behaves_like 'data logging disabled' + it_behaves_like 'response logging disabled' + it_behaves_like 'benchmark logging disabled' + it_behaves_like 'with prefix response lines' + it_behaves_like 'with line numbers' end end context 'POST multi-part requests (file upload)' do let(:upload) { Tempfile.new('http-log') } let(:params) { { 'foo' => 'bar', 'file' => upload } } if adapter_class.method_defined? :send_multipart_post_request - it 'should not log data if disabled' do - HttpLog.configure { |c| c.log_data = false } - adapter.send_multipart_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Data:') - end + before { adapter.send_multipart_post_request } - it 'should not log the response if disabled' do - HttpLog.configure { |c| c.log_response = false } - adapter.send_multipart_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Reponse:') - end - - it 'should not log the benchmark if disabled' do - HttpLog.configure { |c| c.log_benchmark = false } - adapter.send_multipart_post_request - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Benchmark:') - end + it_behaves_like 'data logging disabled' + it_behaves_like 'response logging disabled' + it_behaves_like 'benchmark logging disabled' + it_behaves_like 'with prefix response lines' + it_behaves_like 'with line numbers' end end end - context 'with compact config' do - before(:each) { HttpLog.configure { |c| c.compact_log = true } } + context 'with JSON config' do + let(:json_log) { true } - it 'should log a single line with status and benchmark' do - adapter.send_get_request - expect(log).to match(%r{\[httplog\] GET http://#{host}:#{port}#{path}(\?.*)? completed with status code \d{3} in (\d|\.)+}) - expect(log).to_not include(HttpLog::LOG_PREFIX + "Connecting: #{host}:#{port}") - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Response:') - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Data:') - expect(log).to_not include(HttpLog::LOG_PREFIX + 'Benchmark: ') + if adapter_class.method_defined? :send_post_request + before { adapter.send_post_request } + + it { expect(json['method']).to eq('POST') } + it { expect(json['request_body']).to eq(data) } + it { expect(json['request_headers']).to be_a(Hash) } + it { expect(json['response_headers']).to be_a(Hash) } + it { expect(json['response_code']).to eq(200) } + it { expect(json['response_body']).to eq(html) } + it { expect(json['benchmark']).to be_a(Numeric) } + + context 'and compact config' do + let(:compact_log) { true } + + it { expect(json['method']).to eq('POST') } + it { expect(json['request_body']).to be_nil } + it { expect(json['request_headers']).to be_nil } + it { expect(json['response_headers']).to be_nil } + it { expect(json['response_code']).to eq(200) } + it { expect(json['response_body']).to be_nil } + it { expect(json['benchmark']).to be_a(Numeric) } + end end end end end end