Refactor: PHASE 8: Testing & Integration
This commit is contained in:
parent
af34f4fd08
commit
9e8c6804a7
32 changed files with 17128 additions and 0 deletions
276
tests/conftest.py
Normal file
276
tests/conftest.py
Normal file
|
@ -0,0 +1,276 @@
|
|||
"""
|
||||
Pytest configuration and shared fixtures for detector worker tests.
|
||||
"""
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from unittest.mock import Mock, MagicMock, patch
|
||||
from typing import Dict, Any, Generator
|
||||
|
||||
# Add the project root to the path so we can import detector_worker
|
||||
import sys
|
||||
from pathlib import Path
|
||||
project_root = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from detector_worker.core.config import get_config_manager, ConfigurationManager
|
||||
from detector_worker.core.dependency_injection import get_container, DetectorWorkerContainer
|
||||
from detector_worker.core.singleton_managers import (
|
||||
ModelStateManager, StreamStateManager, SessionStateManager,
|
||||
CacheStateManager, CameraStateManager, PipelineStateManager
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir():
|
||||
"""Create a temporary directory for tests."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
yield tmpdir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config():
|
||||
"""Mock configuration data for tests."""
|
||||
return {
|
||||
"poll_interval_ms": 100,
|
||||
"max_streams": 5,
|
||||
"target_fps": 10,
|
||||
"reconnect_interval_sec": 5,
|
||||
"max_retries": 3,
|
||||
"heartbeat_interval": 2,
|
||||
"session_timeout": 600,
|
||||
"models_dir": "models",
|
||||
"log_level": "INFO",
|
||||
"database": {
|
||||
"enabled": False,
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"database": "test_db",
|
||||
"username": "test_user",
|
||||
"password": "test_pass",
|
||||
"schema": "public"
|
||||
},
|
||||
"redis": {
|
||||
"enabled": False,
|
||||
"host": "localhost",
|
||||
"port": 6379,
|
||||
"password": None,
|
||||
"db": 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_detection_result():
|
||||
"""Mock detection result for tests."""
|
||||
return {
|
||||
"class": "car",
|
||||
"confidence": 0.85,
|
||||
"bbox": [100, 200, 300, 400],
|
||||
"id": 12345,
|
||||
"branch_results": {}
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_frame():
|
||||
"""Mock frame data for tests."""
|
||||
import numpy as np
|
||||
return np.zeros((480, 640, 3), dtype=np.uint8)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_model_tree():
|
||||
"""Mock model tree structure for tests."""
|
||||
return {
|
||||
"modelId": "test_model_v1",
|
||||
"modelFile": "test_model.pt",
|
||||
"multiClass": True,
|
||||
"expectedClasses": ["car", "truck"],
|
||||
"triggerClasses": ["car"],
|
||||
"minConfidence": 0.8,
|
||||
"branches": [],
|
||||
"actions": []
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_pipeline_context():
|
||||
"""Mock pipeline context for tests."""
|
||||
return {
|
||||
"camera_id": "test_camera_001",
|
||||
"display_id": "display_001",
|
||||
"session_id": "session_12345",
|
||||
"timestamp": 1640995200000,
|
||||
"subscription_id": "sub_001"
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_singletons():
|
||||
"""Reset singleton managers before each test."""
|
||||
# Clear all singleton state before each test
|
||||
yield
|
||||
|
||||
# Cleanup after test
|
||||
try:
|
||||
ModelStateManager().clear_all()
|
||||
StreamStateManager().clear_all()
|
||||
SessionStateManager().clear_all()
|
||||
CacheStateManager().clear_all()
|
||||
CameraStateManager().clear_all()
|
||||
PipelineStateManager().clear_all()
|
||||
except Exception:
|
||||
pass # Ignore cleanup errors
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def isolated_config_manager(temp_dir, mock_config):
|
||||
"""Create an isolated configuration manager for testing."""
|
||||
config_file = os.path.join(temp_dir, "test_config.json")
|
||||
|
||||
import json
|
||||
with open(config_file, 'w') as f:
|
||||
json.dump(mock_config, f)
|
||||
|
||||
# Create a fresh ConfigurationManager for testing
|
||||
from detector_worker.core.config import JsonFileProvider, EnvironmentProvider
|
||||
|
||||
manager = ConfigurationManager()
|
||||
manager._providers.clear() # Remove default providers
|
||||
manager.add_provider(JsonFileProvider(config_file))
|
||||
|
||||
return manager
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_websocket():
|
||||
"""Mock WebSocket for testing."""
|
||||
mock_ws = Mock()
|
||||
mock_ws.accept = Mock()
|
||||
mock_ws.send_text = Mock()
|
||||
mock_ws.send_json = Mock()
|
||||
mock_ws.receive_text = Mock()
|
||||
mock_ws.receive_json = Mock()
|
||||
mock_ws.close = Mock()
|
||||
mock_ws.client_state = Mock()
|
||||
mock_ws.client_state.DISCONNECTED = False
|
||||
return mock_ws
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_redis_client():
|
||||
"""Mock Redis client for testing."""
|
||||
mock_redis = Mock()
|
||||
mock_redis.get = Mock(return_value=None)
|
||||
mock_redis.set = Mock(return_value=True)
|
||||
mock_redis.delete = Mock(return_value=1)
|
||||
mock_redis.exists = Mock(return_value=0)
|
||||
mock_redis.expire = Mock(return_value=True)
|
||||
mock_redis.publish = Mock(return_value=1)
|
||||
return mock_redis
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_database_connection():
|
||||
"""Mock database connection for testing."""
|
||||
mock_conn = Mock()
|
||||
mock_cursor = Mock()
|
||||
|
||||
mock_cursor.execute = Mock()
|
||||
mock_cursor.fetchone = Mock(return_value=None)
|
||||
mock_cursor.fetchall = Mock(return_value=[])
|
||||
mock_cursor.fetchmany = Mock(return_value=[])
|
||||
mock_cursor.rowcount = 1
|
||||
|
||||
mock_conn.cursor = Mock(return_value=mock_cursor)
|
||||
mock_conn.commit = Mock()
|
||||
mock_conn.rollback = Mock()
|
||||
mock_conn.close = Mock()
|
||||
|
||||
return mock_conn
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_yolo_model():
|
||||
"""Mock YOLO model for testing."""
|
||||
mock_model = Mock()
|
||||
|
||||
# Mock results with boxes
|
||||
mock_result = Mock()
|
||||
mock_result.boxes = Mock()
|
||||
mock_result.boxes.data = Mock()
|
||||
mock_result.boxes.conf = Mock()
|
||||
mock_result.boxes.cls = Mock()
|
||||
mock_result.boxes.id = Mock()
|
||||
|
||||
# Mock track method
|
||||
mock_model.track = Mock(return_value=[mock_result])
|
||||
mock_model.predict = Mock(return_value=[mock_result])
|
||||
|
||||
return mock_model
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_detection_data():
|
||||
"""Sample detection data for testing."""
|
||||
return [
|
||||
{
|
||||
"class": "car",
|
||||
"confidence": 0.92,
|
||||
"bbox": [100, 150, 250, 300],
|
||||
"id": 1001,
|
||||
"branch_results": {}
|
||||
},
|
||||
{
|
||||
"class": "truck",
|
||||
"confidence": 0.87,
|
||||
"bbox": [300, 200, 450, 350],
|
||||
"id": 1002,
|
||||
"branch_results": {}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_session_data():
|
||||
"""Sample session data for testing."""
|
||||
return {
|
||||
"session_id": "session_test_001",
|
||||
"display_id": "display_test_001",
|
||||
"camera_id": "camera_test_001",
|
||||
"created_at": 1640995200.0,
|
||||
"last_activity": 1640995200.0,
|
||||
"detection_data": {
|
||||
"car_brand": "Toyota",
|
||||
"car_model": "Camry",
|
||||
"license_plate": "ABC-123"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Helper functions for tests
|
||||
def create_mock_detection_result(class_name: str = "car", confidence: float = 0.85, track_id: int = 1001):
|
||||
"""Helper function to create mock detection results."""
|
||||
return {
|
||||
"class": class_name,
|
||||
"confidence": confidence,
|
||||
"bbox": [100, 200, 300, 400],
|
||||
"id": track_id,
|
||||
"branch_results": {}
|
||||
}
|
||||
|
||||
|
||||
def create_mock_regions_dict(detections: list = None):
|
||||
"""Helper function to create mock regions dictionary."""
|
||||
if detections is None:
|
||||
detections = [create_mock_detection_result()]
|
||||
|
||||
regions = {}
|
||||
for det in detections:
|
||||
regions[det["class"]] = {
|
||||
"bbox": det["bbox"],
|
||||
"confidence": det["confidence"],
|
||||
"detection": det
|
||||
}
|
||||
return regions
|
Loading…
Add table
Add a link
Reference in a new issue