hackathon / tests /core /test_logger.py
mekosotto's picture
fix(core): apply level + propagate every call; tolerate pre-attached handlers
ed5752e
"""Unit tests for the shared structured logger."""
from __future__ import annotations
import logging
from src.core.logger import get_logger
def test_get_logger_returns_logger_instance() -> None:
logger = get_logger("neurobridge.test")
assert isinstance(logger, logging.Logger)
assert logger.name == "neurobridge.test"
def test_get_logger_attaches_single_handler() -> None:
"""Repeated calls must not duplicate handlers (idempotence)."""
name = "neurobridge.idempotent"
first = get_logger(name)
second = get_logger(name)
assert first is second
assert len(first.handlers) == 1
def test_get_logger_default_level_is_info() -> None:
logger = get_logger("neurobridge.level_check")
assert logger.level == logging.INFO
def test_get_logger_emits_record_to_handler_stream() -> None:
"""The logger writes records through its StreamHandler."""
import io
logger = get_logger("neurobridge.emit_capture")
handler = logger.handlers[0]
buf = io.StringIO()
original_stream = handler.stream
handler.stream = buf
try:
logger.info("hello-world")
finally:
handler.stream = original_stream
output = buf.getvalue()
assert "hello-world" in output
def test_get_logger_format_includes_level_and_name() -> None:
"""Format string must include level and logger name (per AGENTS.md §3 traceability)."""
import io
logger = get_logger("neurobridge.format_check")
handler = logger.handlers[0]
buf = io.StringIO()
original_stream = handler.stream
handler.stream = buf
try:
logger.info("payload")
finally:
handler.stream = original_stream
output = buf.getvalue()
assert "INFO" in output
assert "neurobridge.format_check" in output
assert "payload" in output
def test_get_logger_respects_subsequent_level_change() -> None:
"""The most recent call wins on level — fixes a silent no-op regression."""
name = "neurobridge.level_change"
first = get_logger(name, level=logging.INFO)
assert first.level == logging.INFO
second = get_logger(name, level=logging.DEBUG)
assert second is first # still the same singleton
assert second.level == logging.DEBUG
def test_get_logger_does_not_clobber_pre_attached_handlers() -> None:
"""If a framework pre-attached a handler, we still apply our config."""
name = "neurobridge.pre_attached"
pre_existing = logging.NullHandler()
logging.getLogger(name).addHandler(pre_existing)
logger = get_logger(name)
# Our stdout StreamHandler was added alongside the pre-existing handler.
assert pre_existing in logger.handlers
assert any(
isinstance(h, logging.StreamHandler) and getattr(h, "stream", None) is not None
and h is not pre_existing
for h in logger.handlers
)
# And our config (level + propagate) actually took effect.
assert logger.level == logging.INFO
assert logger.propagate is False