Files
nexus-claude-api/tests/test_logging_config.py

206 lines
6.6 KiB
Python
Raw Normal View History

from __future__ import annotations
from datetime import datetime, timedelta
import logging
from pathlib import Path
from nexus_claude_api.logging_config import configure_logging, resolve_log_file
FIXED_NOW = datetime(2026, 6, 27, 10, 30, 0)
def fixed_date_provider(timestamp: float | None = None) -> datetime:
if timestamp is None:
return FIXED_NOW
return datetime.fromtimestamp(timestamp)
def test_configure_logging_writes_app_logs_to_file_without_console(
tmp_path,
capsys,
) -> None:
log_file = tmp_path / "nexus-claude-api.log"
dated_log_file = tmp_path / "nexus-claude-api-2026-06-27.log"
logger = logging.getLogger("nexus_claude_api.routes.messages")
app_logger = logging.getLogger("nexus_claude_api")
original_handlers = app_logger.handlers[:]
original_level = app_logger.level
original_propagate = app_logger.propagate
try:
returned_log_file = configure_logging(
verbose=False,
log_file=log_file,
date_provider=fixed_date_provider,
)
logger.info("detailed app request")
logger.debug("debug details hidden without verbose")
output = capsys.readouterr()
log_text = dated_log_file.read_text(encoding="utf-8")
assert returned_log_file == dated_log_file
assert output.err == ""
assert "detailed app request" in log_text
assert "debug details hidden without verbose" not in log_text
finally:
app_logger.handlers.clear()
app_logger.handlers.extend(original_handlers)
app_logger.setLevel(original_level)
app_logger.propagate = original_propagate
def test_configure_logging_verbose_writes_debug_app_logs_to_file(
tmp_path,
) -> None:
log_file = tmp_path / "nexus-claude-api.log"
dated_log_file = tmp_path / "nexus-claude-api-2026-06-27.log"
logger = logging.getLogger("nexus_claude_api.routes.messages")
app_logger = logging.getLogger("nexus_claude_api")
original_handlers = app_logger.handlers[:]
original_level = app_logger.level
original_propagate = app_logger.propagate
try:
configure_logging(
verbose=True,
log_file=log_file,
date_provider=fixed_date_provider,
)
logger.debug("debug details stay in file")
assert (
"debug details stay in file"
in dated_log_file.read_text(encoding="utf-8")
)
finally:
app_logger.handlers.clear()
app_logger.handlers.extend(original_handlers)
app_logger.setLevel(original_level)
app_logger.propagate = original_propagate
def test_resolve_log_file_uses_user_config_dir_by_default(
tmp_path,
monkeypatch,
) -> None:
user_config_dir = tmp_path / ".config" / "nexus-claude-api"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_DIR", user_config_dir)
monkeypatch.setattr(
"nexus_claude_api.logging_config._local_datetime",
lambda timestamp=None: FIXED_NOW,
)
assert (
resolve_log_file()
== user_config_dir / "logs" / "nexus-claude-api-2026-06-27.log"
)
def test_resolve_log_file_uses_local_logs_in_dev_mode(monkeypatch) -> None:
monkeypatch.setattr(
"nexus_claude_api.logging_config._local_datetime",
lambda timestamp=None: FIXED_NOW,
)
assert resolve_log_file(dev=True) == Path("logs") / "nexus-claude-api-2026-06-27.log"
def test_configure_logging_prunes_logs_older_than_recent_seven_days(tmp_path) -> None:
for days_ago in range(10):
log_date = FIXED_NOW - timedelta(days=days_ago)
(tmp_path / f"nexus-claude-api-{log_date:%Y-%m-%d}.log").write_text(
f"log {days_ago}",
encoding="utf-8",
)
ignored_log = tmp_path / "nexus-claude-api-debug.log"
ignored_log.write_text("keep me", encoding="utf-8")
app_logger = logging.getLogger("nexus_claude_api")
original_handlers = app_logger.handlers[:]
original_level = app_logger.level
original_propagate = app_logger.propagate
try:
configure_logging(
verbose=False,
log_file=tmp_path / "nexus-claude-api.log",
date_provider=fixed_date_provider,
)
remaining_logs = sorted(
path.name for path in tmp_path.glob("nexus-claude-api-*.log")
)
assert remaining_logs == [
"nexus-claude-api-2026-06-21.log",
"nexus-claude-api-2026-06-22.log",
"nexus-claude-api-2026-06-23.log",
"nexus-claude-api-2026-06-24.log",
"nexus-claude-api-2026-06-25.log",
"nexus-claude-api-2026-06-26.log",
"nexus-claude-api-2026-06-27.log",
"nexus-claude-api-debug.log",
]
finally:
app_logger.handlers.clear()
app_logger.handlers.extend(original_handlers)
app_logger.setLevel(original_level)
app_logger.propagate = original_propagate
def test_configure_logging_switches_files_when_record_date_changes(tmp_path) -> None:
log_file = tmp_path / "nexus-claude-api.log"
logger = logging.getLogger("nexus_claude_api.routes.messages")
app_logger = logging.getLogger("nexus_claude_api")
original_handlers = app_logger.handlers[:]
original_level = app_logger.level
original_propagate = app_logger.propagate
try:
configure_logging(
verbose=False,
log_file=log_file,
date_provider=lambda timestamp=None: datetime.fromtimestamp(timestamp)
if timestamp is not None
else datetime(2026, 6, 27, 10, 30, 0),
)
before_record = logger.makeRecord(
logger.name,
logging.INFO,
__file__,
1,
"before midnight",
(),
None,
)
before_record.created = datetime(2026, 6, 27, 23, 59, 0).timestamp()
after_record = logger.makeRecord(
logger.name,
logging.INFO,
__file__,
1,
"after midnight",
(),
None,
)
after_record.created = datetime(2026, 6, 28, 0, 1, 0).timestamp()
for handler in app_logger.handlers:
handler.handle(before_record)
handler.handle(after_record)
assert "before midnight" in (
tmp_path / "nexus-claude-api-2026-06-27.log"
).read_text(encoding="utf-8")
assert "after midnight" in (
tmp_path / "nexus-claude-api-2026-06-28.log"
).read_text(encoding="utf-8")
finally:
app_logger.handlers.clear()
app_logger.handlers.extend(original_handlers)
app_logger.setLevel(original_level)
app_logger.propagate = original_propagate