Skip to content

Commit accfc02

Browse files
authored
Merge pull request #45 from GabrielSalla/add-log-tests
Add log tests
2 parents 3672a5e + 0335027 commit accfc02

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

.coveragerc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ omit =
44
src/_monitors_load/*
55
src/tmp/*
66
src/main.py
7-
src/utils/log.py
87
exclude_lines =
98
pragma: no cover
109
if TYPE_CHECKING:

configs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ logging:
1818
timestamp: created
1919
level: levelname
2020
file_path: pathname
21-
logger_name: name
2221
function_name: funcName
2322
line_number: lineno
23+
logger_name: name
2424
message: message
2525

2626
# Application database pool settings

src/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Still missing tests for main.py, so it's been ignored in the .coveragerc file
2+
13
import asyncio
24
import logging
35
import sys

src/utils/log.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ def format(self, record: logging.LogRecord) -> str:
4848
key: getattr(record, record_field) for key, record_field in self.fields.items()
4949
}
5050

51-
if record.exc_info:
51+
if record.exc_info: # pragma: no cover
5252
message_dict["exception"] = self.formatException(record.exc_info)
5353

54-
if record.stack_info:
54+
if record.stack_info: # pragma: no cover
5555
message_dict["stack_info"] = self.formatStack(record.stack_info)
5656

5757
return json.dumps(message_dict, default=str)

tests/utils/test_log.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import json
2+
import logging
3+
import re
4+
import time
5+
6+
import pytest
7+
8+
import utils.log as log
9+
from configs import FriendlyLogConfig, JsonLogConfig, configs
10+
11+
12+
def set_friendly_formatter(monkeypatch, log_format: str | None) -> None:
13+
"""Set the friendly formatter for the logging configuration"""
14+
monkeypatch.setattr(logging.root, "handlers", [])
15+
monkeypatch.setattr(configs, "logging", FriendlyLogConfig(mode="friendly", format=log_format))
16+
log.setup()
17+
18+
19+
def set_json_formatter(monkeypatch, fields: dict[str, str] | None) -> None:
20+
"""Set the JSON formatter for the logging configuration"""
21+
monkeypatch.setattr(logging.root, "handlers", [])
22+
monkeypatch.setattr(configs, "logging", JsonLogConfig(mode="json", fields=fields))
23+
log.setup()
24+
25+
26+
@pytest.mark.parametrize(
27+
"log_format",
28+
[
29+
"%(asctime)s %(levelname)s: %(message)s",
30+
"%(asctime)s %(levelname)s %(message)s",
31+
"%(levelname)s %(message)s",
32+
],
33+
)
34+
@pytest.mark.parametrize("level", ["info", "warning", "error"])
35+
def test_friendly_formatter(capsys, monkeypatch, log_format, level):
36+
"""'friendly' formatter should format the log message in a friendly way using the provided log
37+
format"""
38+
set_friendly_formatter(monkeypatch, log_format)
39+
40+
logger = logging.getLogger("test_friendly_formatter")
41+
message = f"message for '{level}' level"
42+
getattr(logger, level)(message)
43+
44+
captured_message = capsys.readouterr().err.strip()
45+
46+
expected_content = log_format.replace("%(asctime)s", r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d*")
47+
expected_content = expected_content.replace("%(levelname)s", level.upper())
48+
expected_content = expected_content.replace("%(message)s", message)
49+
expected_pattern = "\x1b" + r".*m" + expected_content + "\x1b" + r"\[0m"
50+
51+
match = re.match(expected_pattern, captured_message)
52+
assert match is not None
53+
54+
55+
def test_friendly_formatter_no_log_format(capsys, monkeypatch):
56+
"""'friendly' formatter should format the log message in a friendly way using a default log
57+
format if none was provided"""
58+
set_friendly_formatter(monkeypatch, None)
59+
60+
logger = logging.getLogger("test_friendly_formatter_no_log_format")
61+
message = "message for 'info' level"
62+
logger.info(message)
63+
64+
captured_message = capsys.readouterr().err.strip()
65+
66+
log_format = "%(asctime)s \\[%(levelname)s\\]: %(message)s"
67+
expected_content = log_format.replace("%(asctime)s", r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d*")
68+
expected_content = expected_content.replace("%(levelname)s", "INFO")
69+
expected_content = expected_content.replace("%(message)s", message)
70+
expected_pattern = "\x1b" + r".*m" + expected_content + "\x1b" + r"\[0m"
71+
72+
match = re.match(expected_pattern, captured_message)
73+
assert match is not None
74+
75+
76+
@pytest.mark.parametrize(
77+
"fields",
78+
[
79+
{"message": "message"},
80+
{"some_message": "message"},
81+
{"message": "message", "level": "levelname"},
82+
{"some_message": "message", "log_level": "levelname"},
83+
{"message": "message", "level": "levelname", "time": "created"},
84+
{"some_message": "message", "log_level": "levelname", "timestamp": "created"},
85+
],
86+
)
87+
@pytest.mark.parametrize("level", ["info", "warning", "error"])
88+
def test_json_formatter(capsys, monkeypatch, fields, level):
89+
"""'json' formatter should format the log message as a JSON object using the provided fields"""
90+
set_json_formatter(monkeypatch, fields)
91+
92+
logger = logging.getLogger("test_json_formatter")
93+
message = f"message for '{level}' level"
94+
getattr(logger, level)(message)
95+
96+
captured_message = capsys.readouterr().err.strip()
97+
message_dict = json.loads(captured_message)
98+
99+
for key, value in message_dict.items():
100+
if key in ("message", "some_message"):
101+
assert value == message
102+
elif key in ("level", "log_level"):
103+
assert value == level.upper()
104+
elif key in ("time", "timestamp"):
105+
assert isinstance(value, float)
106+
assert value > time.time() - 0.001
107+
else:
108+
assert False, "Unexpected field in log"
109+
110+
111+
def test_json_formatter_no_fields(capsys, monkeypatch):
112+
"""'json' formatter should format the log message as a JSON object only with the 'message' field
113+
if no fields were provided"""
114+
set_json_formatter(monkeypatch, None)
115+
116+
logger = logging.getLogger("test_json_formatter_no_fields")
117+
message = "message for 'info' level"
118+
logger.info(message)
119+
120+
captured_message = capsys.readouterr().err.strip()
121+
message_dict = json.loads(captured_message)
122+
123+
assert message_dict == {"message": "message for 'info' level"}

0 commit comments

Comments
 (0)