130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
import logging
|
|
from datetime import UTC, datetime
|
|
from io import StringIO
|
|
|
|
from EvoScientist.logging_config import (
|
|
DailyLogFileHandler,
|
|
configure_console_logging,
|
|
configure_daily_file_logging,
|
|
configure_logging,
|
|
default_log_dir,
|
|
resolve_log_level,
|
|
)
|
|
|
|
|
|
def test_daily_log_file_handler_uses_dated_active_file(tmp_path):
|
|
handler = DailyLogFileHandler(tmp_path, prefix="evoscientist", retention_days=30)
|
|
logger = logging.getLogger("tests.daily_log_file_handler")
|
|
logger.handlers.clear()
|
|
logger.propagate = False
|
|
logger.setLevel(logging.INFO)
|
|
logger.addHandler(handler)
|
|
|
|
logger.info("hello")
|
|
handler.close()
|
|
|
|
today = datetime.now().strftime("%Y-%m-%d")
|
|
assert (tmp_path / f"evoscientist-{today}.log").read_text(encoding="utf-8").strip()
|
|
|
|
|
|
def test_daily_log_file_handler_keeps_latest_retention_days(tmp_path):
|
|
for day in range(1, 33):
|
|
(tmp_path / f"evoscientist-2026-01-{day:02d}.log").write_text(
|
|
"x", encoding="utf-8"
|
|
)
|
|
|
|
handler = DailyLogFileHandler(tmp_path, prefix="evoscientist", retention_days=30)
|
|
handler._delete_expired_logs()
|
|
handler.close()
|
|
|
|
remaining = sorted(path.name for path in tmp_path.glob("evoscientist-*.log"))
|
|
assert len(remaining) == 30
|
|
assert remaining[0] == "evoscientist-2026-01-03.log"
|
|
|
|
|
|
def test_configure_daily_file_logging_replaces_matching_handler(tmp_path):
|
|
logger = logging.getLogger("tests.configure_daily_file_logging")
|
|
logger.handlers.clear()
|
|
logger.propagate = False
|
|
|
|
first = configure_daily_file_logging(logger, log_dir=tmp_path)
|
|
second = configure_daily_file_logging(logger, log_dir=tmp_path)
|
|
|
|
try:
|
|
handlers = [h for h in logger.handlers if isinstance(h, DailyLogFileHandler)]
|
|
assert handlers == [second]
|
|
assert first.stream is None
|
|
finally:
|
|
for handler in logger.handlers[:]:
|
|
logger.removeHandler(handler)
|
|
handler.close()
|
|
|
|
|
|
def test_configure_logging_replaces_only_managed_handlers(tmp_path):
|
|
logger = logging.getLogger("tests.configure_logging")
|
|
logger.handlers.clear()
|
|
logger.propagate = False
|
|
external = logging.NullHandler()
|
|
logger.addHandler(external)
|
|
|
|
configure_logging(logger, log_dir=tmp_path, level="debug")
|
|
configure_logging(logger, log_dir=tmp_path, level="info")
|
|
|
|
try:
|
|
daily_handlers = [h for h in logger.handlers if isinstance(h, DailyLogFileHandler)]
|
|
stream_handlers = [
|
|
h
|
|
for h in logger.handlers
|
|
if isinstance(h, logging.StreamHandler)
|
|
and not isinstance(h, DailyLogFileHandler)
|
|
]
|
|
assert external in logger.handlers
|
|
assert len(daily_handlers) == 1
|
|
assert len(stream_handlers) == 1
|
|
assert logger.level == logging.INFO
|
|
finally:
|
|
for handler in logger.handlers[:]:
|
|
logger.removeHandler(handler)
|
|
handler.close()
|
|
|
|
|
|
def test_configure_console_logging_emits_to_stream():
|
|
logger = logging.getLogger("tests.configure_console_logging")
|
|
logger.handlers.clear()
|
|
logger.propagate = False
|
|
stream = StringIO()
|
|
|
|
configure_console_logging(logger, level="INFO", stream=stream)
|
|
try:
|
|
logger.info("hello")
|
|
assert "tests.configure_console_logging: hello" in stream.getvalue()
|
|
finally:
|
|
for handler in logger.handlers[:]:
|
|
logger.removeHandler(handler)
|
|
handler.close()
|
|
|
|
|
|
def test_resolve_log_level_accepts_alias_numeric_and_fallback():
|
|
assert resolve_log_level("warn") == logging.WARNING
|
|
assert resolve_log_level("10") == logging.DEBUG
|
|
assert resolve_log_level("", default=logging.ERROR) == logging.ERROR
|
|
assert resolve_log_level("not-a-level", default=logging.CRITICAL) == logging.CRITICAL
|
|
|
|
|
|
def test_daily_log_file_handler_supports_utc(tmp_path):
|
|
handler = DailyLogFileHandler(tmp_path, utc=True)
|
|
try:
|
|
today_utc = datetime.now(UTC).strftime("%Y-%m-%d")
|
|
assert handler.active_log_path.name == f"evoscientist-{today_utc}.log"
|
|
finally:
|
|
handler.close()
|
|
|
|
|
|
def test_default_log_dir_uses_current_data_dir(monkeypatch, tmp_path):
|
|
import EvoScientist.paths as paths
|
|
|
|
monkeypatch.delenv("EVOSCIENTIST_LOG_DIR", raising=False)
|
|
monkeypatch.setattr(paths, "DATA_DIR", tmp_path / "data")
|
|
|
|
assert default_log_dir() == tmp_path / "data" / "logs"
|