File indexing completed on 2026-04-27 07:41:41
0001 import pytest
0002 import logging
0003 from unittest.mock import patch, MagicMock
0004 import requests
0005 from pythonjsonlogger.json import JsonFormatter
0006
0007 from swf_common_lib.logging_utils import setup_rest_logging, RestLogHandler
0008
0009
0010 @patch('swf_common_lib.logging_utils.requests.post')
0011 def test_rest_log_handler_emit(mock_post):
0012 """Test that the REST handler sends log records to the API endpoint."""
0013
0014 mock_response = MagicMock()
0015 mock_response.status_code = 200
0016 mock_post.return_value = mock_response
0017
0018 handler = RestLogHandler('http://localhost:8002/api/logs/', token='test-token')
0019
0020
0021 log_format = '%(asctime)s %(name)s %(levelname)s %(module)s %(funcName)s %(lineno)d %(message)s'
0022 formatter = JsonFormatter(log_format, rename_fields={'funcName': 'funcname'})
0023 handler.setFormatter(formatter)
0024
0025 logger = logging.getLogger('rest_test')
0026 logger.handlers.clear()
0027 logger.addHandler(handler)
0028 logger.setLevel(logging.INFO)
0029
0030
0031 logger.info("This is a test message")
0032
0033
0034 mock_post.assert_called_once()
0035 call_args = mock_post.call_args
0036
0037
0038 assert call_args[0][0] == 'http://localhost:8002/api/logs/'
0039
0040
0041 expected_headers = {
0042 'Content-type': 'application/json',
0043 'Authorization': 'Token test-token'
0044 }
0045 assert call_args[1]['headers'] == expected_headers
0046
0047
0048 log_data = call_args[1]['data']
0049 assert 'This is a test message' in log_data
0050 assert 'INFO' in log_data
0051
0052
0053 @patch('swf_common_lib.logging_utils.requests.post')
0054 def test_rest_log_handler_no_token(mock_post):
0055 """Test that the handler works without authentication token."""
0056
0057 mock_response = MagicMock()
0058 mock_response.status_code = 200
0059 mock_post.return_value = mock_response
0060
0061 handler = RestLogHandler('http://localhost:8002/api/logs/')
0062
0063 log_format = '%(asctime)s %(name)s %(levelname)s %(message)s'
0064 formatter = JsonFormatter(log_format)
0065 handler.setFormatter(formatter)
0066
0067 logger = logging.getLogger('no_token_test')
0068 logger.handlers.clear()
0069 logger.addHandler(handler)
0070 logger.setLevel(logging.INFO)
0071
0072
0073 logger.info("Test without token")
0074
0075
0076 mock_post.assert_called_once()
0077 call_args = mock_post.call_args
0078
0079
0080 expected_headers = {'Content-type': 'application/json'}
0081 assert call_args[1]['headers'] == expected_headers
0082
0083
0084 @patch('swf_common_lib.logging_utils.requests.post')
0085 def test_rest_log_handler_request_exception(mock_post, capsys):
0086 """Test that request exceptions are handled gracefully."""
0087
0088 mock_post.side_effect = requests.RequestException("Connection failed")
0089
0090 handler = RestLogHandler('http://localhost:8002/api/logs/')
0091 formatter = JsonFormatter('%(message)s')
0092 handler.setFormatter(formatter)
0093
0094 logger = logging.getLogger('exception_test')
0095 logger.handlers.clear()
0096 logger.addHandler(handler)
0097 logger.setLevel(logging.INFO)
0098
0099
0100 logger.info("This should fail to send")
0101
0102
0103 captured = capsys.readouterr()
0104 assert "Failed to send log to http://localhost:8002/api/logs/: Connection failed" in captured.err
0105
0106
0107 def test_setup_rest_logging():
0108 """Test that setup_rest_logging creates a properly configured logger."""
0109
0110 logger = setup_rest_logging(
0111 app_name='test_app',
0112 instance_name='test_instance',
0113 base_url='http://localhost:8002',
0114 token='test-token',
0115 level=logging.DEBUG
0116 )
0117
0118
0119 assert logger.name == 'test_app.test_instance'
0120 assert logger.level == logging.DEBUG
0121 assert len(logger.handlers) == 1
0122 assert isinstance(logger.handlers[0], RestLogHandler)
0123
0124
0125 handler = logger.handlers[0]
0126 assert handler.url == 'http://localhost:8002/api/logs/'
0127 assert handler.token == 'test-token'
0128
0129
0130 formatter = handler.formatter
0131 assert isinstance(formatter, JsonFormatter)
0132
0133
0134 @patch('swf_common_lib.logging_utils.requests.post')
0135 def test_setup_rest_logging_integration(mock_post):
0136 """Test the complete setup_rest_logging integration."""
0137
0138 mock_response = MagicMock()
0139 mock_response.status_code = 200
0140 mock_post.return_value = mock_response
0141
0142
0143 logger = setup_rest_logging(
0144 app_name='integration_test',
0145 instance_name='instance_1',
0146 base_url='http://localhost:8002'
0147 )
0148
0149 logger.info("Integration test message", extra={'custom_field': 'custom_value'})
0150
0151
0152 mock_post.assert_called_once()
0153 call_args = mock_post.call_args
0154
0155
0156 log_data = call_args[1]['data']
0157 assert 'Integration test message' in log_data
0158 assert 'integration_test.instance_1' in log_data
0159 assert 'custom_field' in log_data
0160 assert 'funcname' in log_data