from unittest.mock import MagicMock from flask import Response from api.logging import RequestResponseLogging, log_request_body_and_headers, log_response_body_and_headers from api.logging.logger import DefaultLogger import logging def test_logger_level_prod(): """ Given a DefaultLogger When not running local It should set log level to INFO """ logger = DefaultLogger(is_running_local=False) assert logger.logger.getEffectiveLevel() == logging.INFO def test_logger_level_dev(): """ Given a DefaultLogger When is running local It should set log level to DEBUG """ logger = DefaultLogger(is_running_local=True) assert logger.logger.getEffectiveLevel() == logging.DEBUG def test_request_response_logging_extension(app): """ Given a Flask app when using the RequestResponseLogging extension it should present a log_request before func and a log_response after_func """ RequestResponseLogging(app) before_func_names = __get_function_name_list(app.before_request_funcs) after_func_names = __get_function_name_list(app.after_request_funcs) assert 'log_request' in before_func_names assert 'log_response' in after_func_names def test_request_response_logging_execution_urls_deny_list(app, mocker): """ Given a Flask app when using the RequestResponseLogging extension when invoking a path from the specified no_logs_path it should not call the log_request_body_and_headers and log_response_body_and_headers functions """ mock_log_request = mocker.patch('api.logging.http_info.log_request_body_and_headers') mock_log_response = mocker.patch('api.logging.http_info.log_response_body_and_headers') RequestResponseLogging(app) with app.test_request_context('/logs'): app.preprocess_request() app.process_response(Response('fake-response')) mock_log_request.assert_not_called() mock_log_response.assert_not_called() def test_request_response_logging_execution(app, mocker): """ Given a Flask app when using the RequestResponseLogging extension when invoking a path it should call the log_request_body_and_headers and log_response_body_and_headers functions """ mock_log_request = mocker.patch('api.logging.log_request_body_and_headers') mock_log_response = mocker.patch('api.logging.log_response_body_and_headers') RequestResponseLogging(app) with app.test_request_context('/'): app.preprocess_request() app.process_response(Response('fake-response')) mock_log_request.assert_called_once() mock_log_response.assert_called_once() def __get_function_name_list(functions): return list(fun.__name__ for app_name, funcs in functions.items() for fun in funcs) class MockRequest: headers = {'int_value': 100} args = {'region': 'eu-west-1'} json = {'username': 'user@email.com'} path = '/fake-path' environ = { 'serverless.event': { 'requestContext': { 'requestId': 'apigw-request-id' } } } def test_log_request_body_and_headers(): mock_logger = MagicMock(wraps=DefaultLogger(True)) log_request_body_and_headers(mock_logger, MockRequest()) expected_details = { 'headers': {'int_value': 100}, 'body': {'username': 'user@email.com'}, 'path': '/fake-path', 'params': {'region': 'eu-west-1'}, 'apigw-request-id': 'apigw-request-id' } mock_logger.info.assert_called_once_with(expected_details) def test_log_response_body_and_headers(): mock_logger = MagicMock(wraps=DefaultLogger(True)) log_response_body_and_headers(mock_logger, MockRequest()) expected_details = { 'headers': {'int_value': 100}, 'body': {'username': 'user@email.com'} } mock_logger.info.assert_called_once_with(expected_details)