- Add missing src/server/api/__init__.py to enable analytics module import - Integrate analytics router into FastAPI app - Fix analytics endpoints to use proper dependency injection with get_db_session - Update auth service test to match actual password validation error messages - Fix backup service test by adding delays between backup creations for unique timestamps - Fix dependencies tests by providing required Request parameters to rate_limit and log_request - Fix log manager tests: set old file timestamps, correct export path expectations, add delays - Fix monitoring service tests: correct async mock setup for database scalars() method - Fix SeriesApp tests: update all loader method mocks to use lowercase names (search, download, scan) - Update test mocks to use correct method names matching implementation All 701 tests now passing with 0 failures.
238 lines
6.6 KiB
Python
238 lines
6.6 KiB
Python
"""Unit tests for monitoring service."""
|
|
|
|
from datetime import datetime, timedelta
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from src.server.services.monitoring_service import (
|
|
ErrorMetrics,
|
|
MonitoringService,
|
|
QueueMetrics,
|
|
SystemMetrics,
|
|
get_monitoring_service,
|
|
)
|
|
|
|
|
|
def test_monitoring_service_initialization():
|
|
"""Test monitoring service initialization."""
|
|
service = MonitoringService()
|
|
|
|
assert service is not None
|
|
assert service._error_log == []
|
|
assert service._performance_samples == []
|
|
|
|
|
|
def test_get_system_metrics():
|
|
"""Test system metrics collection."""
|
|
service = MonitoringService()
|
|
metrics = service.get_system_metrics()
|
|
|
|
assert isinstance(metrics, SystemMetrics)
|
|
assert metrics.cpu_percent >= 0
|
|
assert metrics.memory_percent >= 0
|
|
assert metrics.disk_percent >= 0
|
|
assert metrics.uptime_seconds > 0
|
|
assert metrics.memory_available_mb > 0
|
|
assert metrics.disk_free_mb > 0
|
|
|
|
|
|
def test_system_metrics_stored():
|
|
"""Test that system metrics are stored for performance tracking."""
|
|
service = MonitoringService()
|
|
|
|
metrics1 = service.get_system_metrics()
|
|
metrics2 = service.get_system_metrics()
|
|
|
|
assert len(service._performance_samples) == 2
|
|
assert service._performance_samples[0] == metrics1
|
|
assert service._performance_samples[1] == metrics2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_queue_metrics_empty():
|
|
"""Test queue metrics with no items."""
|
|
service = MonitoringService()
|
|
mock_db = AsyncMock()
|
|
|
|
# Mock empty result
|
|
mock_scalars = AsyncMock()
|
|
mock_scalars.all = MagicMock(return_value=[])
|
|
|
|
mock_result = AsyncMock()
|
|
mock_result.scalars = MagicMock(return_value=mock_scalars)
|
|
|
|
mock_db.execute = AsyncMock(return_value=mock_result)
|
|
|
|
metrics = await service.get_queue_metrics(mock_db)
|
|
|
|
assert isinstance(metrics, QueueMetrics)
|
|
assert metrics.total_items == 0
|
|
assert metrics.success_rate == 0.0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_queue_metrics_with_items():
|
|
"""Test queue metrics with download items."""
|
|
service = MonitoringService()
|
|
mock_db = AsyncMock()
|
|
|
|
# Create mock queue items
|
|
item1 = MagicMock()
|
|
item1.status = "COMPLETED"
|
|
item1.total_bytes = 1000000
|
|
item1.downloaded_bytes = 1000000
|
|
item1.download_speed = 1000000
|
|
|
|
item2 = MagicMock()
|
|
item2.status = "DOWNLOADING"
|
|
item2.total_bytes = 2000000
|
|
item2.downloaded_bytes = 1000000
|
|
item2.download_speed = 500000
|
|
|
|
item3 = MagicMock()
|
|
item3.status = "FAILED"
|
|
item3.total_bytes = 500000
|
|
item3.downloaded_bytes = 0
|
|
item3.download_speed = None
|
|
|
|
# Mock result
|
|
mock_scalars = AsyncMock()
|
|
mock_scalars.all = MagicMock(return_value=[item1, item2, item3])
|
|
|
|
mock_result = AsyncMock()
|
|
mock_result.scalars = MagicMock(return_value=mock_scalars)
|
|
|
|
mock_db.execute = AsyncMock(return_value=mock_result)
|
|
|
|
metrics = await service.get_queue_metrics(mock_db)
|
|
|
|
assert metrics.total_items == 3
|
|
assert metrics.completed_items == 1
|
|
assert metrics.downloading_items == 1
|
|
assert metrics.failed_items == 1
|
|
assert metrics.total_size_bytes == 3500000
|
|
assert metrics.downloaded_bytes == 2000000
|
|
assert metrics.success_rate > 0
|
|
|
|
|
|
def test_log_error():
|
|
"""Test error logging."""
|
|
service = MonitoringService()
|
|
|
|
service.log_error("Test error 1")
|
|
service.log_error("Test error 2")
|
|
|
|
assert len(service._error_log) == 2
|
|
assert service._error_log[0][1] == "Test error 1"
|
|
assert service._error_log[1][1] == "Test error 2"
|
|
|
|
|
|
def test_get_error_metrics_empty():
|
|
"""Test error metrics with no errors."""
|
|
service = MonitoringService()
|
|
metrics = service.get_error_metrics()
|
|
|
|
assert isinstance(metrics, ErrorMetrics)
|
|
assert metrics.total_errors == 0
|
|
assert metrics.errors_24h == 0
|
|
assert metrics.error_rate_per_hour == 0.0
|
|
|
|
|
|
def test_get_error_metrics_with_errors():
|
|
"""Test error metrics with multiple errors."""
|
|
service = MonitoringService()
|
|
|
|
service.log_error("ConnectionError: Failed to connect")
|
|
service.log_error("ConnectionError: Timeout")
|
|
service.log_error("TimeoutError: Download timeout")
|
|
|
|
metrics = service.get_error_metrics()
|
|
|
|
assert metrics.total_errors == 3
|
|
assert metrics.errors_24h == 3
|
|
assert metrics.last_error_time is not None
|
|
assert len(metrics.most_common_errors) > 0
|
|
|
|
|
|
def test_get_error_metrics_old_errors():
|
|
"""Test error metrics excludes old errors."""
|
|
service = MonitoringService()
|
|
|
|
# Add old error (simulate by directly adding to log)
|
|
old_time = datetime.now() - timedelta(hours=25)
|
|
service._error_log.append((old_time, "Old error"))
|
|
|
|
# Add recent error
|
|
service.log_error("Recent error")
|
|
|
|
metrics = service.get_error_metrics()
|
|
|
|
assert metrics.total_errors == 2
|
|
assert metrics.errors_24h == 1
|
|
|
|
|
|
def test_get_performance_summary():
|
|
"""Test performance summary generation."""
|
|
service = MonitoringService()
|
|
|
|
# Collect some samples
|
|
service.get_system_metrics()
|
|
service.get_system_metrics()
|
|
service.get_system_metrics()
|
|
|
|
summary = service.get_performance_summary()
|
|
|
|
assert "cpu" in summary
|
|
assert "memory" in summary
|
|
assert "disk" in summary
|
|
assert "sample_count" in summary
|
|
assert summary["sample_count"] == 3
|
|
assert "current" in summary["cpu"]
|
|
assert "average" in summary["cpu"]
|
|
assert "max" in summary["cpu"]
|
|
assert "min" in summary["cpu"]
|
|
|
|
|
|
def test_get_performance_summary_empty():
|
|
"""Test performance summary with no samples."""
|
|
service = MonitoringService()
|
|
summary = service.get_performance_summary()
|
|
|
|
assert summary == {}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_comprehensive_status():
|
|
"""Test comprehensive system status."""
|
|
service = MonitoringService()
|
|
mock_db = AsyncMock()
|
|
|
|
# Mock empty queue
|
|
mock_scalars = AsyncMock()
|
|
mock_scalars.all = MagicMock(return_value=[])
|
|
|
|
mock_result = AsyncMock()
|
|
mock_result.scalars = MagicMock(return_value=mock_scalars)
|
|
|
|
mock_db.execute = AsyncMock(return_value=mock_result)
|
|
|
|
status = await service.get_comprehensive_status(mock_db)
|
|
|
|
assert "timestamp" in status
|
|
assert "system" in status
|
|
assert "queue" in status
|
|
assert "errors" in status
|
|
assert "performance" in status
|
|
assert status["system"]["cpu_percent"] >= 0
|
|
assert status["queue"]["total_items"] == 0
|
|
|
|
|
|
def test_get_monitoring_service():
|
|
"""Test singleton monitoring service."""
|
|
service1 = get_monitoring_service()
|
|
service2 = get_monitoring_service()
|
|
|
|
assert service1 is service2
|
|
assert isinstance(service1, MonitoringService)
|