webdrop-bridge/tests/unit/test_logging.py

154 lines
4.9 KiB
Python

"""Unit tests for logging module."""
import logging
from pathlib import Path
from tempfile import TemporaryDirectory
import pytest
from webdrop_bridge.utils.logging import get_logger, setup_logging
class TestSetupLogging:
"""Test logging configuration."""
def test_setup_logging_console_only(self):
"""Test console-only logging setup."""
logger = setup_logging(name="test_console", level="DEBUG")
assert logger.name == "test_console"
assert logger.level == logging.DEBUG
assert len(logger.handlers) == 1
assert isinstance(logger.handlers[0], logging.StreamHandler)
def test_setup_logging_with_file(self, tmp_path):
"""Test logging setup with file handler."""
log_file = tmp_path / "test.log"
logger = setup_logging(
name="test_file",
level="INFO",
log_file=log_file,
)
assert logger.name == "test_file"
assert len(logger.handlers) == 2
# Find file handler
file_handler = None
for handler in logger.handlers:
if isinstance(handler, logging.handlers.RotatingFileHandler):
file_handler = handler
break
assert file_handler is not None
assert log_file.exists()
def test_setup_logging_invalid_level(self):
"""Test that invalid log level raises KeyError."""
with pytest.raises(KeyError, match="Invalid logging level"):
setup_logging(level="INVALID")
def test_setup_logging_invalid_file_path(self):
"""Test that inaccessible file path raises ValueError."""
# Use a path that can't be created (on Windows, CON is reserved)
if Path.cwd().drive: # Windows
invalid_path = Path("CON") / "invalid.log"
else: # Unix - use root-only directory
invalid_path = Path("/root") / "invalid.log"
with pytest.raises(ValueError, match="Cannot write to log file"):
setup_logging(log_file=invalid_path)
def test_setup_logging_custom_format(self, tmp_path):
"""Test logging with custom format string."""
log_file = tmp_path / "test.log"
custom_fmt = "%(levelname)s:%(name)s:%(message)s"
logger = setup_logging(
name="test_format",
level="INFO",
log_file=log_file,
fmt=custom_fmt,
)
# Log a test message
logger.info("test message")
# Check format in log file
content = log_file.read_text()
assert "INFO:test_format:test message" in content
def test_setup_logging_creates_parent_dirs(self, tmp_path):
"""Test that setup_logging creates parent directories."""
log_file = tmp_path / "nested" / "dir" / "test.log"
logger = setup_logging(
name="test_nested",
level="INFO",
log_file=log_file,
)
logger.info("test")
assert log_file.exists()
assert log_file.parent.exists()
def test_setup_logging_removes_duplicates(self):
"""Test that multiple setup calls don't duplicate handlers."""
logger_name = "test_duplicates"
# First setup
logger1 = setup_logging(name=logger_name, level="DEBUG")
initial_handler_count = len(logger1.handlers)
# Second setup (should clear old handlers)
logger2 = setup_logging(name=logger_name, level="INFO")
assert logger2 is logger1 # Same logger object
assert len(logger2.handlers) == initial_handler_count
class TestGetLogger:
"""Test get_logger convenience function."""
def test_get_logger(self):
"""Test getting a logger instance."""
logger = get_logger("test.module")
assert isinstance(logger, logging.Logger)
assert logger.name == "test.module"
def test_get_logger_default_name(self):
"""Test get_logger uses __name__ by default."""
logger = get_logger()
# Should return a logger (when no name provided, uses logging module __name__)
assert isinstance(logger, logging.Logger)
assert logger.name == "webdrop_bridge.utils.logging"
class TestLogRotation:
"""Test log file rotation."""
def test_rotating_file_handler_configured(self, tmp_path):
"""Test that file handler is configured for rotation."""
log_file = tmp_path / "test.log"
logger = setup_logging(
name="test_rotation",
level="INFO",
log_file=log_file,
)
# Find rotating file handler
rotating_handler = None
for handler in logger.handlers:
if isinstance(handler, logging.handlers.RotatingFileHandler):
rotating_handler = handler
break
assert rotating_handler is not None
# Default: 10 MB max, 5 backups
assert rotating_handler.maxBytes == 10 * 1024 * 1024
assert rotating_handler.backupCount == 5