Files
gps-denied-onboard/test_integration_f05_f11.py
T
Denys Zaitsev d7e1066c60 Initial commit
2026-04-03 23:25:54 +03:00

127 lines
4.6 KiB
Python

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()