250 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			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()
 |