summaryrefslogtreecommitdiff
path: root/shared/tests
diff options
context:
space:
mode:
Diffstat (limited to 'shared/tests')
-rw-r--r--shared/tests/test_logging.py106
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)