Skip to content

Commit bfa7ab3

Browse files
committed
Added unit test for the 'forward_logs' API endpoint
1 parent d7bdd8f commit bfa7ab3

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ developer = [
5252
"ipykernel", # Enable interactive coding with VS Code and Jupyter Notebook
5353
"pre-commit", # Formatting, linting, type checking, etc.
5454
"pytest", # Test code functionality
55+
"pytest-asyncio", # For testing async functions
5556
"pytest-mock", # Additional mocking tools for unit tests
5657
]
5758
server = [

tests/server/api/test_logging.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import json
2+
import logging
3+
import time
4+
from datetime import datetime
5+
from typing import Any
6+
from unittest.mock import AsyncMock, MagicMock
7+
8+
import pytest
9+
from pytest_mock import MockerFixture
10+
11+
import murfey
12+
from murfey.server.api.logging import forward_logs
13+
14+
15+
@pytest.mark.asyncio
16+
async def test_forward_logs(
17+
mocker: MockerFixture,
18+
):
19+
# Create example log messages
20+
message_list = [
21+
json.dumps(
22+
{
23+
"name": f"murfey.{module_name}",
24+
"msg": "Starting Murfey server version {murfey.__version__}, listening on 0.0.0.0:8000",
25+
"args": [],
26+
"levelname": levelname,
27+
"levelno": levelno,
28+
"pathname": f"{murfey.__file__}/{module_name}/__init__.py",
29+
"filename": "__init__.py",
30+
"module": "__init__",
31+
"exc_info": None,
32+
"exc_text": None,
33+
"stack_info": None,
34+
"lineno": 76,
35+
"funcName": f"start_{module_name}",
36+
"created": time.time(),
37+
"msecs": 930.0,
38+
"relativeCreated": 1379.8329830169678,
39+
"thread": time.time_ns(),
40+
"threadName": "MainThread",
41+
"processName": "MainProcess",
42+
"process": time.time_ns(),
43+
"message": f"Starting Murfey server version {murfey.__version__}, listening on 0.0.0.0:8000",
44+
"type": "log",
45+
}
46+
)
47+
for module_name, levelname, levelno in (
48+
("module_1", "DEBUG", logging.DEBUG),
49+
("module_2", "INFO", logging.INFO),
50+
("module_3", "WARNING", logging.WARNING),
51+
("module_4", "ERROR", logging.ERROR),
52+
)
53+
]
54+
55+
# Create a mock request to pass to the function
56+
mock_request = MagicMock()
57+
mock_request.json = AsyncMock(return_value=message_list)
58+
59+
# Mock the logging module
60+
mock_logging = mocker.patch("murfey.server.api.logging.logging")
61+
62+
# Mock the 'getLogger()' and 'handle()' functions
63+
mock_logger = MagicMock()
64+
mock_logger.handle.return_value = None
65+
mock_logging.getLogger.return_value = mock_logger
66+
67+
# Run the function and check that the results are as expected
68+
await forward_logs(mock_request)
69+
70+
# Check that the correct logger name was called.
71+
for i, message in enumerate(message_list):
72+
# Process the message as in the actual function
73+
log_data: dict[str, Any] = json.loads(message)
74+
logger_name = log_data["name"]
75+
log_data.pop("msecs", None)
76+
log_data.pop("relativeCreated", None)
77+
client_timestamp = log_data.pop("created", 0)
78+
if client_timestamp:
79+
log_data["client_time"] = datetime.fromtimestamp(
80+
client_timestamp
81+
).isoformat()
82+
log_data["client_host"] = None # No host, as function is being tested directly
83+
84+
# Check that messages are unpacked and handled in sequence
85+
mock_logging.getLogger.call_args_list[i][0][0] == logger_name
86+
mock_logger.handle.call_args_list[i][0][0] == logging.makeLogRecord(log_data)
87+
88+
# Check that 'handle' was called for each message
89+
assert mock_logger.handle.call_count == len(message_list)

0 commit comments

Comments
 (0)