import pytest pytest.skip("Obsolete test file replaced by component-specific unit tests", allow_module_level=True) import numpy as np import cv2 from unittest.mock import Mock, MagicMock from datetime import datetime # Import components from f05_image_input_pipeline import ImageInputPipeline, ImageBatch from f11_failure_recovery_coordinator import ( FailureRecoveryCoordinator, GPSPoint, TileCandidate, UserAnchor, ChunkHandle ) @pytest.fixture def mock_dependencies(): """Mocks the external dependencies for the FailureRecoveryCoordinator.""" return { "satellite_data_manager": Mock(), "image_rotation_manager": Mock(), "global_place_recognition": Mock(), "metric_refinement": Mock(), "factor_graph_optimizer": Mock(), "route_chunk_manager": Mock() } @pytest.fixture def coordinator(mock_dependencies): return FailureRecoveryCoordinator(mock_dependencies) @pytest.fixture def pipeline(tmp_path): """Creates a temporary image pipeline.""" return ImageInputPipeline(storage_dir=str(tmp_path)) def create_dummy_image_bytes(): """Helper to create valid JPEG byte data for the F05 pipeline.""" img = np.zeros((480, 640, 3), dtype=np.uint8) cv2.putText(img, "Test", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) _, buffer = cv2.imencode('.jpg', img) return buffer.tobytes() def test_zero_overlap_triggers_user_recovery(pipeline, coordinator, mock_dependencies): """ Tests the integration pipeline: 1. Ingest images via F05. 2. Simulate VO tracking loss (0% overlap). 3. Simulate automatic chunk recovery failure. 4. Verify the system successfully engages the User Input hooks. """ flight_id = "test_flight_001" # 1. Ingest dummy batch of images dummy_bytes = create_dummy_image_bytes() batch = ImageBatch( images=[dummy_bytes, dummy_bytes], filenames=["AD000001.jpg", "AD000002.jpg"], start_sequence=1, end_sequence=2, batch_number=1 ) assert pipeline.queue_batch(flight_id, batch) == True processed_images = pipeline.process_next_batch(flight_id) assert len(processed_images) == 2 # Simulate Frame 1 (Success) frame_1 = processed_images[0] # 2. Simulate Frame 2 (0% Overlap -> VO Tracking Loss) frame_2 = processed_images[1] # The Engine would normally call create_chunk_on_tracking_loss here mock_chunk = ChunkHandle( chunk_id="chunk_test_1", flight_id=flight_id, start_frame_id=2, end_frame_id=None, frames=[2], is_active=True, has_anchor=False, anchor_frame_id=None, anchor_gps=None, matching_status="unanchored" ) mock_dependencies["route_chunk_manager"].create_chunk.return_value = mock_chunk created_chunk = coordinator.create_chunk_on_tracking_loss(flight_id, frame_2.sequence) assert created_chunk.chunk_id == "chunk_test_1" # 3. Simulate automatic chunk recovery failure # (e.g. over a featureless lake, DINOv2 returns no candidates) mock_dependencies["global_place_recognition"].retrieve_candidate_tiles_for_chunk.return_value = [] candidates = coordinator.try_chunk_semantic_matching(created_chunk.chunk_id, [frame_2.image]) assert candidates is None # Automatic recovery failed # 4. Verify User Input hooks correctly engage # Because candidates is None, the engine triggers the UI request mock_candidate_tiles = [ TileCandidate(tile_id="tile_A", score=0.8, gps=GPSPoint(lat=48.1, lon=37.1)) ] user_request = coordinator.create_user_input_request( flight_id=flight_id, frame_id=frame_2.sequence, uav_image=frame_2.image, candidate_tiles=mock_candidate_tiles ) assert user_request.flight_id == flight_id assert user_request.frame_id == 2 assert "Tracking lost and automatic recovery failed" in user_request.message assert len(user_request.candidate_tiles) == 1 def test_apply_user_anchor_resumes_processing(coordinator, mock_dependencies): """Tests that a provided user anchor correctly bounds to the factor graph.""" flight_id = "test_flight_001" frame_id = 2 # Setup mock to return a valid chunk ID for the frame mock_dependencies["route_chunk_manager"].get_chunk_for_frame.return_value = "chunk_test_1" user_anchor = UserAnchor( uav_pixel=(512.0, 384.0), satellite_gps=GPSPoint(lat=48.123, lon=37.123, altitude_m=400.0) ) assert coordinator.apply_user_anchor(flight_id, frame_id, user_anchor) == True mock_dependencies["factor_graph_optimizer"].add_chunk_anchor.assert_called_once()