forensic-trails/tests/test_logging.py
overcuriousity 86359ec850 updates
2025-10-08 21:49:39 +02:00

250 lines
8.9 KiB
Python

"""Unit tests for the logging module."""
import unittest
import tempfile
import os
import logging
from pathlib import Path
from unittest.mock import patch, MagicMock
# Add the src directory to the path
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))
from forensictrails.utils.logging import setup_logging
class TestSetupLogging(unittest.TestCase):
"""Test cases for setup_logging function."""
def setUp(self):
"""Set up test fixtures."""
self.temp_dir = tempfile.mkdtemp()
self.test_log_path = os.path.join(self.temp_dir, 'test.log')
# Clear any existing handlers
logger = logging.getLogger()
for handler in logger.handlers[:]:
logger.removeHandler(handler)
def tearDown(self):
"""Clean up test fixtures."""
# Clear handlers after test
logger = logging.getLogger()
for handler in logger.handlers[:]:
handler.close()
logger.removeHandler(handler)
if os.path.exists(self.test_log_path):
os.remove(self.test_log_path)
# Clean up any nested directories
if os.path.exists(self.temp_dir):
for root, dirs, files in os.walk(self.temp_dir, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
os.rmdir(self.temp_dir)
@patch('forensictrails.utils.logging.config')
def test_setup_logging_creates_log_file(self, mock_config):
"""Test that setup_logging creates the log file."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'DEBUG'
self.assertFalse(os.path.exists(self.test_log_path))
setup_logging(self.test_log_path)
self.assertTrue(os.path.exists(self.test_log_path))
@patch('forensictrails.utils.logging.config')
def test_setup_logging_creates_nested_directories(self, mock_config):
"""Test that setup_logging creates nested directories."""
nested_log_path = os.path.join(self.temp_dir, 'logs', 'nested', 'test.log')
mock_config.log_path = nested_log_path
mock_config.log_level = 'INFO'
self.assertFalse(os.path.exists(nested_log_path))
setup_logging(nested_log_path)
self.assertTrue(os.path.exists(nested_log_path))
self.assertTrue(os.path.isfile(nested_log_path))
@patch('forensictrails.utils.logging.config')
def test_setup_logging_adds_handlers(self, mock_config):
"""Test that setup_logging adds file and stream handlers."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'DEBUG'
logger = logging.getLogger()
initial_handler_count = len(logger.handlers)
setup_logging(self.test_log_path)
# Should add 2 handlers: FileHandler and StreamHandler
self.assertEqual(len(logger.handlers), initial_handler_count + 2)
# Check handler types
handler_types = [type(h).__name__ for h in logger.handlers]
self.assertIn('FileHandler', handler_types)
self.assertIn('StreamHandler', handler_types)
@patch('forensictrails.utils.logging.config')
def test_setup_logging_sets_correct_log_level(self, mock_config):
"""Test that setup_logging sets the correct log level."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'WARNING'
setup_logging(self.test_log_path)
logger = logging.getLogger()
self.assertEqual(logger.level, logging.WARNING)
@patch('forensictrails.utils.logging.config')
def test_setup_logging_logs_messages(self, mock_config):
"""Test that setup_logging enables logging messages."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'DEBUG'
setup_logging(self.test_log_path)
# Log a test message
test_message = "Test logging message"
logging.info(test_message)
# Force flush
for handler in logging.getLogger().handlers:
handler.flush()
# Check that message was written to file
with open(self.test_log_path, 'r') as f:
log_content = f.read()
self.assertIn(test_message, log_content)
self.assertIn('INFO', log_content)
@patch('forensictrails.utils.logging.config')
def test_setup_logging_formatter(self, mock_config):
"""Test that setup_logging uses correct formatter."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'DEBUG'
setup_logging(self.test_log_path)
# Log a message
logging.info("Formatter test")
# Force flush
for handler in logging.getLogger().handlers:
handler.flush()
# Check log format
with open(self.test_log_path, 'r') as f:
log_content = f.read()
# Should contain timestamp, level, and message
self.assertIn('INFO', log_content)
self.assertIn('Formatter test', log_content)
# Check for timestamp pattern (YYYY-MM-DD HH:MM:SS)
import re
timestamp_pattern = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'
self.assertTrue(re.search(timestamp_pattern, log_content))
@patch('forensictrails.utils.logging.config')
def test_setup_logging_uses_config_when_no_path_provided(self, mock_config):
"""Test that setup_logging uses config.log_path when no path is provided."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'INFO'
setup_logging() # No path provided
# Should create file at config.log_path
self.assertTrue(os.path.exists(self.test_log_path))
@patch('forensictrails.utils.logging.config')
def test_setup_logging_different_log_levels(self, mock_config):
"""Test setup_logging with different log levels."""
mock_config.log_path = self.test_log_path
for level_name, level_value in [
('DEBUG', logging.DEBUG),
('INFO', logging.INFO),
('WARNING', logging.WARNING),
('ERROR', logging.ERROR),
('CRITICAL', logging.CRITICAL)
]:
with self.subTest(level=level_name):
# Clear handlers
logger = logging.getLogger()
for handler in logger.handlers[:]:
handler.close()
logger.removeHandler(handler)
mock_config.log_level = level_name
setup_logging(self.test_log_path)
self.assertEqual(logger.level, level_value)
class TestLoggingIntegration(unittest.TestCase):
"""Integration tests for logging functionality."""
def setUp(self):
"""Set up test fixtures."""
self.temp_dir = tempfile.mkdtemp()
self.test_log_path = os.path.join(self.temp_dir, 'integration.log')
# Clear any existing handlers
logger = logging.getLogger()
for handler in logger.handlers[:]:
logger.removeHandler(handler)
def tearDown(self):
"""Clean up test fixtures."""
# Clear handlers after test
logger = logging.getLogger()
for handler in logger.handlers[:]:
handler.close()
logger.removeHandler(handler)
if os.path.exists(self.test_log_path):
os.remove(self.test_log_path)
os.rmdir(self.temp_dir)
@patch('forensictrails.utils.logging.config')
def test_logging_multiple_messages(self, mock_config):
"""Test logging multiple messages of different levels."""
mock_config.log_path = self.test_log_path
mock_config.log_level = 'DEBUG'
setup_logging(self.test_log_path)
# Log messages at different levels
logging.debug("Debug message")
logging.info("Info message")
logging.warning("Warning message")
logging.error("Error message")
# Force flush
for handler in logging.getLogger().handlers:
handler.flush()
# Verify all messages are in the log
with open(self.test_log_path, 'r') as f:
log_content = f.read()
self.assertIn("Debug message", log_content)
self.assertIn("Info message", log_content)
self.assertIn("Warning message", log_content)
self.assertIn("Error message", log_content)
self.assertIn("DEBUG", log_content)
self.assertIn("INFO", log_content)
self.assertIn("WARNING", log_content)
self.assertIn("ERROR", log_content)
if __name__ == '__main__':
unittest.main()