diff options
Diffstat (limited to 'shared/tests')
| -rw-r--r-- | shared/tests/test_logging.py | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/shared/tests/test_logging.py b/shared/tests/test_logging.py new file mode 100644 index 0000000..4abd254 --- /dev/null +++ b/shared/tests/test_logging.py @@ -0,0 +1,106 @@ +"""Tests for shared structured logging module.""" +import io +import json +import logging + +import pytest +import structlog + + +@pytest.fixture(autouse=True) +def _reset_structlog(): + """Reset structlog configuration between tests.""" + structlog.reset_defaults() + # Remove all handlers from root logger to avoid cross-test leakage + root = logging.getLogger() + root.handlers.clear() + yield + structlog.reset_defaults() + root.handlers.clear() + + +def test_setup_logging_returns_logger(): + """setup_logging should return a bound structlog logger.""" + from shared.logging import setup_logging + + logger = setup_logging(service_name="test-svc") + assert logger is not None + # Should be usable as a logger (has info, debug, etc.) + assert callable(getattr(logger, "info", None)) + assert callable(getattr(logger, "error", None)) + + +def test_service_name_bound_in_context(): + """The returned logger should have service=service_name bound.""" + from shared.logging import setup_logging + + logger = setup_logging(service_name="my-service", log_format="json") + + # Capture output via a stream handler on the root logger + stream = io.StringIO() + handler = logging.StreamHandler(stream) + handler.setLevel(logging.DEBUG) + # Use the same formatter structlog sets up + root = logging.getLogger() + handler.setFormatter(root.handlers[0].formatter) + root.addHandler(handler) + + logger.info("hello") + + output = stream.getvalue() + parsed = json.loads(output) + assert parsed["service"] == "my-service" + + +def test_log_level_set_correctly(): + """setup_logging should set the stdlib root logger level.""" + from shared.logging import setup_logging + + setup_logging(service_name="test", log_level="WARNING") + root = logging.getLogger() + assert root.level == logging.WARNING + + +def test_json_format_produces_json(): + """log_format='json' should produce JSON output.""" + from shared.logging import setup_logging + + logger = setup_logging(service_name="json-svc", log_format="json") + + stream = io.StringIO() + handler = logging.StreamHandler(stream) + handler.setLevel(logging.DEBUG) + root = logging.getLogger() + handler.setFormatter(root.handlers[0].formatter) + root.addHandler(handler) + + logger.info("test-json") + + output = stream.getvalue().strip() + parsed = json.loads(output) + assert "event" in parsed + assert parsed["event"] == "test-json" + assert "timestamp" in parsed + assert "level" in parsed + + +def test_console_format_produces_output(): + """log_format='console' should produce human-readable output (not JSON).""" + from shared.logging import setup_logging + + logger = setup_logging(service_name="console-svc", log_format="console") + + stream = io.StringIO() + handler = logging.StreamHandler(stream) + handler.setLevel(logging.DEBUG) + root = logging.getLogger() + handler.setFormatter(root.handlers[0].formatter) + root.addHandler(handler) + + logger.info("test-console") + + output = stream.getvalue().strip() + assert len(output) > 0 + # Console output should NOT be valid JSON + with pytest.raises(json.JSONDecodeError): + json.loads(output) |
