scam / tests /unit /test_logger.py
Gankit12's picture
Upload 129 files
31f0e50 verified
"""
Unit Tests for Logging Module.
Tests logging configuration and logger classes.
"""
import pytest
import logging
from unittest.mock import MagicMock, patch
from app.utils.logger import (
LOG_FORMAT,
LOG_DATE_FORMAT,
setup_logging,
get_logger,
RequestLogger,
DetectionLogger,
AuditLogger,
request_logger,
detection_logger,
audit_logger,
)
class TestLoggingConstants:
"""Tests for logging constants."""
def test_log_format_defined(self):
"""Test LOG_FORMAT is defined."""
assert LOG_FORMAT is not None
assert isinstance(LOG_FORMAT, str)
assert len(LOG_FORMAT) > 0
def test_log_format_contains_placeholders(self):
"""Test LOG_FORMAT contains standard placeholders."""
assert "%(asctime)s" in LOG_FORMAT or "asctime" in LOG_FORMAT.lower()
assert "%(levelname)" in LOG_FORMAT or "levelname" in LOG_FORMAT.lower()
def test_date_format_defined(self):
"""Test LOG_DATE_FORMAT is defined."""
assert LOG_DATE_FORMAT is not None
assert isinstance(LOG_DATE_FORMAT, str)
class TestSetupLogging:
"""Tests for setup_logging function."""
def test_sets_default_level(self):
"""Test default log level is INFO."""
setup_logging()
logger = logging.getLogger()
# The level should be set (can be INFO=20 or WARNING=30 depending on config)
assert logger.level in [logging.INFO, logging.DEBUG, logging.NOTSET, logging.WARNING]
def test_sets_custom_level(self):
"""Test custom log level can be set."""
setup_logging(level="DEBUG")
# Should not raise
def test_accepts_custom_format(self):
"""Test custom format can be provided."""
custom_format = "%(message)s"
setup_logging(log_format=custom_format)
# Should not raise
def test_handles_invalid_level(self):
"""Test handles invalid log level gracefully."""
# Should default to INFO for invalid level
setup_logging(level="INVALID")
# Should not raise
class TestGetLogger:
"""Tests for get_logger function."""
def test_returns_logger(self):
"""Test returns Logger instance."""
logger = get_logger("test")
assert isinstance(logger, logging.Logger)
def test_returns_named_logger(self):
"""Test returns logger with given name."""
logger = get_logger("my.module.name")
assert logger.name == "my.module.name"
def test_same_name_same_logger(self):
"""Test same name returns same logger instance."""
logger1 = get_logger("same.name")
logger2 = get_logger("same.name")
assert logger1 is logger2
class TestRequestLogger:
"""Tests for RequestLogger class."""
def test_initialization(self):
"""Test RequestLogger initializes correctly."""
logger = RequestLogger()
assert logger.logger is not None
assert logger.logger.name == "scamshield.request"
def test_log_request(self):
"""Test log_request method."""
logger = RequestLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_request(
method="POST",
path="/api/v1/honeypot/engage",
client_ip="127.0.0.1",
request_id="req-123"
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "REQUEST" in call_args
assert "POST" in call_args
assert "/api/v1/honeypot/engage" in call_args
def test_log_request_minimal(self):
"""Test log_request with minimal parameters."""
logger = RequestLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_request(method="GET", path="/health")
mock_info.assert_called_once()
def test_log_response(self):
"""Test log_response method."""
logger = RequestLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_response(
status_code=200,
duration_ms=150,
request_id="req-123"
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "RESPONSE" in call_args
assert "200" in call_args
assert "150" in call_args
class TestDetectionLogger:
"""Tests for DetectionLogger class."""
def test_initialization(self):
"""Test DetectionLogger initializes correctly."""
logger = DetectionLogger()
assert logger.logger is not None
assert logger.logger.name == "scamshield.detection"
def test_log_detection_scam(self):
"""Test log_detection for scam detection."""
logger = DetectionLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_detection(
session_id="sess-123",
scam_detected=True,
confidence=0.95,
language="en",
indicators=["lottery", "urgent"]
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "DETECTION" in call_args
assert "sess-123" in call_args
assert "SCAM" in call_args
assert "0.95" in call_args
def test_log_detection_legitimate(self):
"""Test log_detection for legitimate message."""
logger = DetectionLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_detection(
session_id="sess-456",
scam_detected=False,
confidence=0.1,
language="en"
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "LEGITIMATE" in call_args
def test_log_extraction(self):
"""Test log_extraction method."""
logger = DetectionLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_extraction(
session_id="sess-789",
intel_summary={"upi_ids": 2, "phone_numbers": 1},
confidence=0.85
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "EXTRACTION" in call_args
assert "sess-789" in call_args
class TestAuditLogger:
"""Tests for AuditLogger class."""
def test_initialization(self):
"""Test AuditLogger initializes correctly."""
logger = AuditLogger()
assert logger.logger is not None
assert logger.logger.name == "scamshield.audit"
def test_log_event(self):
"""Test log_event method."""
logger = AuditLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_event(
event_type="session_created",
details={"message_count": 5},
session_id="sess-audit-123"
)
mock_info.assert_called_once()
call_args = mock_info.call_args[0][0]
assert "AUDIT" in call_args
assert "session_created" in call_args
assert "sess-audit-123" in call_args
def test_log_event_without_session(self):
"""Test log_event without session_id."""
logger = AuditLogger()
with patch.object(logger.logger, 'info') as mock_info:
logger.log_event(
event_type="system_startup",
details={"version": "1.0.0"}
)
mock_info.assert_called_once()
class TestModuleLevelLoggers:
"""Tests for module-level logger instances."""
def test_request_logger_exists(self):
"""Test request_logger is defined."""
assert request_logger is not None
assert isinstance(request_logger, RequestLogger)
def test_detection_logger_exists(self):
"""Test detection_logger is defined."""
assert detection_logger is not None
assert isinstance(detection_logger, DetectionLogger)
def test_audit_logger_exists(self):
"""Test audit_logger is defined."""
assert audit_logger is not None
assert isinstance(audit_logger, AuditLogger)
class TestLoggerIntegration:
"""Integration tests for logger module."""
def test_full_request_lifecycle(self):
"""Test logging a full request lifecycle."""
with patch.object(request_logger.logger, 'info'):
request_logger.log_request(
method="POST",
path="/api/v1/honeypot/engage",
client_ip="192.168.1.1",
request_id="req-full-test"
)
request_logger.log_response(
status_code=200,
duration_ms=250,
request_id="req-full-test"
)
def test_detection_and_extraction_flow(self):
"""Test detection and extraction logging flow."""
with patch.object(detection_logger.logger, 'info'):
detection_logger.log_detection(
session_id="sess-flow-test",
scam_detected=True,
confidence=0.9,
language="en",
indicators=["prize", "otp"]
)
detection_logger.log_extraction(
session_id="sess-flow-test",
intel_summary={"upi_ids": 1, "phone_numbers": 2},
confidence=0.85
)