Implement configuration management, drag-and-drop functionality, and logging utilities for WebDrop Bridge
This commit is contained in:
parent
04ef84cf9a
commit
6bef2f6119
9 changed files with 1154 additions and 0 deletions
154
tests/unit/test_logging.py
Normal file
154
tests/unit/test_logging.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
"""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
|
||||
Loading…
Add table
Add a link
Reference in a new issue