mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 01:16:38 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from f12_route_chunk_manager import RouteChunkManager, ChunkHandle, ChunkConfig
|
||||
from f02_1_flight_lifecycle_manager import GPSPoint
|
||||
from f07_sequential_visual_odometry import RelativePose
|
||||
from f09_local_geospatial_anchoring import Sim3Transform
|
||||
|
||||
@pytest.fixture
|
||||
def mocks():
|
||||
return {
|
||||
"f03": Mock(),
|
||||
"f05": Mock(),
|
||||
"f08": Mock(),
|
||||
"f10": Mock()
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def rcm(mocks):
|
||||
return RouteChunkManager(
|
||||
f03=mocks["f03"],
|
||||
f05=mocks["f05"],
|
||||
f08=mocks["f08"],
|
||||
f10=mocks["f10"],
|
||||
config=ChunkConfig(min_frames_for_matching=5, max_frames_per_chunk=20)
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_relative_pose():
|
||||
return RelativePose(translation=np.array([1, 0, 0]), rotation=np.eye(3), confidence=0.9, inlier_count=50, total_matches=100, tracking_good=True)
|
||||
|
||||
class TestRouteChunkManager:
|
||||
|
||||
# --- 12.01 Chunk Lifecycle Management ---
|
||||
|
||||
def test_create_chunk(self, rcm, mocks):
|
||||
chunk = rcm.create_chunk("flight_1", 100)
|
||||
assert chunk.flight_id == "flight_1"
|
||||
assert chunk.start_frame_id == 100
|
||||
assert chunk.is_active is True
|
||||
assert chunk.chunk_id in rcm._chunks
|
||||
|
||||
mocks["f10"].create_chunk_subgraph.assert_called_once_with("flight_1", chunk.chunk_id, 100)
|
||||
|
||||
def test_add_frame_to_active_chunk(self, rcm, dummy_relative_pose, mocks):
|
||||
mocks["f10"].add_relative_factor_to_chunk.return_value = True
|
||||
chunk = rcm.create_chunk("flight_1", 100)
|
||||
|
||||
success = rcm.add_frame_to_chunk(chunk.chunk_id, 101, dummy_relative_pose)
|
||||
assert success is True
|
||||
assert 101 in chunk.frames
|
||||
assert chunk.end_frame_id == 101
|
||||
mocks["f10"].add_relative_factor_to_chunk.assert_called_once()
|
||||
|
||||
def test_add_frame_to_inactive_chunk_fails(self, rcm, dummy_relative_pose):
|
||||
chunk = rcm.create_chunk("flight_1", 100)
|
||||
rcm.deactivate_chunk(chunk.chunk_id)
|
||||
|
||||
success = rcm.add_frame_to_chunk(chunk.chunk_id, 101, dummy_relative_pose)
|
||||
assert success is False
|
||||
|
||||
def test_get_active_chunk(self, rcm):
|
||||
chunk1 = rcm.create_chunk("flight_1", 100)
|
||||
rcm.create_chunk("flight_2", 200) # Different flight
|
||||
|
||||
active = rcm.get_active_chunk("flight_1")
|
||||
assert active.chunk_id == chunk1.chunk_id
|
||||
|
||||
rcm.deactivate_chunk(chunk1.chunk_id)
|
||||
assert rcm.get_active_chunk("flight_1") is None
|
||||
|
||||
# --- 12.02 Chunk Data Retrieval ---
|
||||
|
||||
def test_get_chunk_frames_and_images(self, rcm, mocks):
|
||||
chunk = rcm.create_chunk("flight_1", 1)
|
||||
chunk.frames = [1, 2, 3]
|
||||
|
||||
assert rcm.get_chunk_frames(chunk.chunk_id) == [1, 2, 3]
|
||||
|
||||
mock_img = Mock(image=np.zeros((10, 10)))
|
||||
mocks["f05"].get_image_by_sequence.return_value = mock_img
|
||||
|
||||
images = rcm.get_chunk_images(chunk.chunk_id)
|
||||
assert len(images) == 3
|
||||
assert mocks["f05"].get_image_by_sequence.call_count == 3
|
||||
|
||||
def test_get_chunk_composite_descriptor(self, rcm, mocks):
|
||||
chunk = rcm.create_chunk("flight_1", 1)
|
||||
chunk.frames = [1, 2]
|
||||
mocks["f05"].get_image_by_sequence.return_value = Mock(image=np.zeros((10, 10)))
|
||||
mocks["f08"].compute_chunk_descriptor.return_value = np.ones(4096)
|
||||
|
||||
desc = rcm.get_chunk_composite_descriptor(chunk.chunk_id)
|
||||
assert desc is not None
|
||||
assert desc.shape == (4096,)
|
||||
mocks["f08"].compute_chunk_descriptor.assert_called_once()
|
||||
|
||||
def test_get_chunk_bounds(self, rcm, mocks):
|
||||
chunk = rcm.create_chunk("flight_1", 1)
|
||||
mocks["f10"].get_chunk_trajectory.return_value = {} # Returns dict, not mock object
|
||||
# Unanchored bounds
|
||||
bounds = rcm.get_chunk_bounds(chunk.chunk_id)
|
||||
assert bounds.confidence < 0.5
|
||||
|
||||
# Anchored bounds
|
||||
chunk.has_anchor = True
|
||||
chunk.anchor_gps = GPSPoint(lat=48.0, lon=37.0)
|
||||
bounds_anchored = rcm.get_chunk_bounds(chunk.chunk_id)
|
||||
assert bounds_anchored.confidence > 0.5
|
||||
assert bounds_anchored.estimated_center.lat == 48.0
|
||||
|
||||
# --- 12.03 Chunk Matching Coordination ---
|
||||
|
||||
def test_is_chunk_ready_for_matching(self, rcm):
|
||||
chunk = rcm.create_chunk("flight_1", 1)
|
||||
|
||||
# Too few frames (<5)
|
||||
chunk.frames = [1, 2, 3]
|
||||
assert rcm.is_chunk_ready_for_matching(chunk.chunk_id) is False
|
||||
|
||||
# Just right (5)
|
||||
chunk.frames = [1, 2, 3, 4, 5]
|
||||
assert rcm.is_chunk_ready_for_matching(chunk.chunk_id) is True
|
||||
|
||||
# Already matched
|
||||
chunk.matching_status = "anchored"
|
||||
assert rcm.is_chunk_ready_for_matching(chunk.chunk_id) is False
|
||||
|
||||
def test_mark_chunk_anchored_transactional(self, rcm, mocks):
|
||||
chunk = rcm.create_chunk("flight_1", 1)
|
||||
|
||||
# F10 fails
|
||||
mocks["f10"].add_chunk_anchor.return_value = False
|
||||
assert rcm.mark_chunk_anchored(chunk.chunk_id, 1, GPSPoint(lat=0, lon=0)) is False
|
||||
assert chunk.has_anchor is False
|
||||
|
||||
# F10 succeeds
|
||||
mocks["f10"].add_chunk_anchor.return_value = True
|
||||
assert rcm.mark_chunk_anchored(chunk.chunk_id, 1, GPSPoint(lat=0, lon=0)) is True
|
||||
assert chunk.has_anchor is True
|
||||
assert chunk.matching_status == "anchored"
|
||||
|
||||
def test_merge_chunks_transactional(self, rcm, mocks):
|
||||
main_chunk = rcm.create_chunk("flight_1", 1)
|
||||
new_chunk = rcm.create_chunk("flight_1", 10)
|
||||
new_chunk.frames = [10, 11]
|
||||
|
||||
transform = Sim3Transform(translation=np.zeros(3), rotation=np.eye(3), scale=1.0)
|
||||
|
||||
mocks["f10"].merge_chunk_subgraphs.return_value = True
|
||||
assert rcm.merge_chunks(main_chunk.chunk_id, new_chunk.chunk_id, transform) is True
|
||||
|
||||
assert new_chunk.is_active is False
|
||||
assert new_chunk.matching_status == "merged"
|
||||
assert 10 in main_chunk.frames
|
||||
assert 11 in main_chunk.frames
|
||||
|
||||
assert mocks["f03"].save_chunk_state.call_count == 2
|
||||
Reference in New Issue
Block a user