aegisai / backend / tests / test_video_processor.py
test_video_processor.py
Raw
import pytest
import numpy as np
from unittest.mock import MagicMock, patch, AsyncMock
from services.video_processor import VideoProcessor, DemoScenarioRunner

@pytest.fixture
def mock_frame():
    return np.zeros((720, 1280, 3), dtype=np.uint8)

@pytest.mark.asyncio
async def test_video_processor_full_loop(mock_frame):
    processor = VideoProcessor(source=0)
    
    # Use AsyncMock for the agents since they are awaited
    processor.vision_agent._safe_process = AsyncMock(return_value={
        "incident": True, 
        "type": "theft", 
        "severity": "high",
        "confidence": 95
    })
    processor.planner_agent._safe_process = AsyncMock(return_value=[{"action": "test"}])
    
    # We use patch.multiple or patch specifically for the awaited executor
    with patch("services.video_processor.cv2") as mock_cv2, \
         patch("services.video_processor.db_service") as mock_db, \
         patch("services.video_processor.action_executor", new_callable=AsyncMock) as mock_executor:
        
        mock_cap = MagicMock()
        mock_cap.isOpened.return_value = True
        mock_cap.read.return_value = (True, mock_frame)
        mock_cv2.VideoCapture.return_value = mock_cap
        
        # Stop the loop after one iteration
        async def stop_after_one(*args, **kwargs):
            processor.running = False
            return {"incident": True}
        
        processor.vision_agent._safe_process.side_effect = stop_after_one

        await processor.process_stream(display=True)
        
        assert mock_cv2.imshow.called
        assert mock_db.save_incident.called
        # Now this will pass because mock_executor is an AsyncMock
        assert mock_executor.execute_plan.called

@pytest.mark.asyncio
async def test_demo_scenario_runner():
    runner = DemoScenarioRunner()
    runner.vision_agent._safe_process = AsyncMock(return_value={"incident": False})
    
    # Properly close the agents in the runner to clear warnings
    with patch("builtins.print"), \
         patch.object(runner.vision_agent, 'close', new_callable=AsyncMock), \
         patch.object(runner.planner_agent, 'close', new_callable=AsyncMock):
        await runner._run_scenario("Test", "Test Desc", (255, 0, 0))