Skip to content

Commit bf2ccce

Browse files
committed
test(logging): add tests for centralized logging helpers
Add parametrized tests for resolve_log_level() covering valid levels, invalid fallback, and unset default. Add tests for create_log_handler() verifying TTY returns RichHandler, non-TTY returns StreamHandler with the correct format. Update test_uvicorn_runner.py to import resolve_log_level from log instead of the deleted private _resolve_log_level from runners.uvicorn. Signed-off-by: Major Hayden <major@redhat.com>
1 parent c1eb55b commit bf2ccce

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

tests/unit/runners/test_uvicorn_runner.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
from pytest_mock import MockerFixture
88

99
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR
10+
from log import resolve_log_level
1011
from models.config import ServiceConfiguration, TLSConfiguration
11-
from runners.uvicorn import _resolve_log_level, start_uvicorn
12+
from runners.uvicorn import start_uvicorn
1213

1314

1415
def test_start_uvicorn(mocker: MockerFixture) -> None:
@@ -146,17 +147,17 @@ def test_start_uvicorn_with_root_path(mocker: MockerFixture) -> None:
146147
def test_resolve_log_level_from_env(
147148
monkeypatch: pytest.MonkeyPatch, env_value: str, expected_level: int
148149
) -> None:
149-
"""Test that _resolve_log_level resolves env var values to logging constants."""
150+
"""Test that resolve_log_level resolves env var values to logging constants."""
150151
monkeypatch.setenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, env_value)
151-
assert _resolve_log_level() == expected_level
152+
assert resolve_log_level() == expected_level
152153

153154

154155
def test_resolve_log_level_defaults_to_info(
155156
monkeypatch: pytest.MonkeyPatch,
156157
) -> None:
157-
"""Test that _resolve_log_level falls back to INFO when the env var is unset."""
158+
"""Test that resolve_log_level falls back to INFO when the env var is unset."""
158159
monkeypatch.delenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, raising=False)
159-
assert _resolve_log_level() == logging.INFO
160+
assert resolve_log_level() == logging.INFO
160161

161162

162163
def test_start_uvicorn_respects_debug_log_level(

tests/unit/test_log.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""Unit tests for functions defined in src/log.py."""
22

33
import logging
4+
45
import pytest
6+
from pytest_mock import MockerFixture
7+
from rich.logging import RichHandler
58

6-
from log import get_logger
7-
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR
9+
from log import get_logger, resolve_log_level, create_log_handler
10+
from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_FORMAT
811

912

1013
def test_get_logger() -> None:
@@ -57,3 +60,59 @@ def test_get_logger_default_log_level(monkeypatch: pytest.MonkeyPatch) -> None:
5760

5861
logger = get_logger("test_default")
5962
assert logger.level == logging.INFO
63+
64+
65+
@pytest.mark.parametrize(
66+
("level_name", "expected_level"),
67+
[
68+
("DEBUG", logging.DEBUG),
69+
("debug", logging.DEBUG),
70+
("INFO", logging.INFO),
71+
("WARNING", logging.WARNING),
72+
("ERROR", logging.ERROR),
73+
("CRITICAL", logging.CRITICAL),
74+
("critical", logging.CRITICAL),
75+
],
76+
)
77+
def test_resolve_log_level(
78+
monkeypatch: pytest.MonkeyPatch, level_name: str, expected_level: int
79+
) -> None:
80+
"""Test that resolve_log_level correctly resolves valid level names."""
81+
monkeypatch.setenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, level_name)
82+
assert resolve_log_level() == expected_level
83+
84+
85+
def test_resolve_log_level_invalid_fallback(monkeypatch: pytest.MonkeyPatch) -> None:
86+
"""Test that resolve_log_level falls back to INFO for invalid values."""
87+
monkeypatch.setenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, "BOGUS")
88+
assert resolve_log_level() == logging.INFO
89+
90+
91+
def test_resolve_log_level_default(monkeypatch: pytest.MonkeyPatch) -> None:
92+
"""Test that resolve_log_level defaults to INFO when env var is unset."""
93+
monkeypatch.delenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, raising=False)
94+
assert resolve_log_level() == logging.INFO
95+
96+
97+
def test_create_log_handler_tty(mocker: MockerFixture) -> None:
98+
"""Test that create_log_handler returns RichHandler when TTY is available."""
99+
mocker.patch("sys.stderr.isatty", return_value=True)
100+
handler = create_log_handler()
101+
assert isinstance(handler, RichHandler)
102+
103+
104+
def test_create_log_handler_non_tty(mocker: MockerFixture) -> None:
105+
"""Test that create_log_handler returns StreamHandler when no TTY."""
106+
mocker.patch("sys.stderr.isatty", return_value=False)
107+
handler = create_log_handler()
108+
assert isinstance(handler, logging.StreamHandler)
109+
assert not isinstance(handler, RichHandler)
110+
111+
112+
def test_create_log_handler_non_tty_format(mocker: MockerFixture) -> None:
113+
"""Test that non-TTY handler uses DEFAULT_LOG_FORMAT."""
114+
mocker.patch("sys.stderr.isatty", return_value=False)
115+
handler = create_log_handler()
116+
assert handler.formatter is not None
117+
# pylint: disable=protected-access
118+
assert handler.formatter._fmt == DEFAULT_LOG_FORMAT

0 commit comments

Comments
 (0)