"""Tests for core logging utilities""" import json import logging from io import StringIO from apps.core.logging import ( ContextLogger, JSONFormatter, get_json_logging_config, ) from django.test import TestCase class JSONFormatterTest(TestCase): """Tests for JSONFormatter""" def setUp(self): self.formatter = JSONFormatter() self.logger = logging.getLogger("test_json") self.logger.setLevel(logging.DEBUG) # Remove existing handlers self.logger.handlers = [] # Add handler with JSONFormatter self.stream = StringIO() handler = logging.StreamHandler(self.stream) handler.setFormatter(self.formatter) self.logger.addHandler(handler) def test_output_is_valid_json(self): """Test that output is valid JSON""" self.logger.info("Test message") output = self.stream.getvalue() # Should not raise parsed = json.loads(output) self.assertIsInstance(parsed, dict) def test_contains_required_fields(self): """Test that output contains required fields""" self.logger.info("Test message") output = self.stream.getvalue() parsed = json.loads(output) self.assertIn("timestamp", parsed) self.assertIn("level", parsed) self.assertIn("logger", parsed) self.assertIn("message", parsed) def test_level_is_correct(self): """Test that log level is correct""" self.logger.warning("Warning message") output = self.stream.getvalue() parsed = json.loads(output) self.assertEqual(parsed["level"], "WARNING") def test_message_is_correct(self): """Test that message is correct""" self.logger.info("My test message") output = self.stream.getvalue() parsed = json.loads(output) self.assertEqual(parsed["message"], "My test message") def test_extra_fields_included(self): """Test that extra fields are included""" self.logger.info("Test message", extra={"user_id": 42, "action": "login"}) output = self.stream.getvalue() parsed = json.loads(output) self.assertIn("extra", parsed) self.assertEqual(parsed["extra"]["user_id"], 42) self.assertEqual(parsed["extra"]["action"], "login") def test_exception_info_included(self): """Test that exception info is included""" try: raise ValueError("Test error") except ValueError: self.logger.exception("An error occurred") output = self.stream.getvalue() parsed = json.loads(output) self.assertIn("exception", parsed) self.assertEqual(parsed["exception"]["type"], "ValueError") self.assertIn("Test error", parsed["exception"]["message"]) class ContextLoggerTest(TestCase): """Tests for ContextLogger""" def setUp(self): self.context_logger = ContextLogger("test_context") def test_set_context(self): """Test context is stored""" self.context_logger.set_context(user_id=42, action="test") self.assertEqual(self.context_logger._context["user_id"], 42) self.assertEqual(self.context_logger._context["action"], "test") def test_clear_context(self): """Test context is cleared""" self.context_logger.set_context(user_id=42) self.context_logger.clear_context() self.assertEqual(self.context_logger._context, {}) def test_context_updated_not_replaced(self): """Test that set_context updates rather than replaces""" self.context_logger.set_context(user_id=42) self.context_logger.set_context(action="test") self.assertEqual(self.context_logger._context["user_id"], 42) self.assertEqual(self.context_logger._context["action"], "test") class GetJsonLoggingConfigTest(TestCase): """Tests for get_json_logging_config function""" def test_returns_dict(self): """Test function returns a dictionary""" config = get_json_logging_config() self.assertIsInstance(config, dict) def test_has_required_keys(self): """Test config has required keys""" config = get_json_logging_config() self.assertIn("version", config) self.assertIn("formatters", config) self.assertIn("handlers", config) self.assertIn("loggers", config) def test_json_formatter_configured(self): """Test JSON formatter is configured""" config = get_json_logging_config() self.assertIn("json", config["formatters"]) self.assertEqual( config["formatters"]["json"]["()"], "apps.core.logging.JSONFormatter", ) def test_log_level_applied(self): """Test log level is applied""" config = get_json_logging_config(log_level="DEBUG") self.assertEqual(config["root"]["level"], "DEBUG") def test_file_handler_added_when_path_provided(self): """Test file handler is added when path is provided""" config = get_json_logging_config(log_file="/var/log/test.log") self.assertIn("file", config["handlers"]) self.assertEqual( config["handlers"]["file"]["filename"], "/var/log/test.log", )