Initial commit

This commit is contained in:
Denys Zaitsev
2026-04-03 23:25:54 +03:00
parent 531a1301d5
commit d7e1066c60
3843 changed files with 1554468 additions and 0 deletions
+234
View File
@@ -0,0 +1,234 @@
import pytest
import time
from unittest.mock import Mock, patch
from datetime import datetime, timedelta
from f02_1_flight_lifecycle_manager import GPSPoint
from f03_flight_database import FrameResult as F03FrameResult
from f14_result_manager import ResultManager, FrameResult, RefinedFrameResult
@pytest.fixture
def f03():
db = Mock()
store = {}
def mock_execute(ops):
for op in ops:
op()
return True
db.execute_transaction.side_effect = mock_execute
def save_fr(fid, fr):
store[fr.frame_id] = fr
return True
db.save_frame_result.side_effect = save_fr
def get_fr(fid):
return list(store.values())
db.get_frame_results.side_effect = get_fr
return db
@pytest.fixture
def f15():
return Mock()
@pytest.fixture
def rm(f03, f15):
return ResultManager(f03_database=f03, f15_streamer=f15)
@pytest.fixture
def sample_result():
return FrameResult(
frame_id=10,
gps_center=GPSPoint(lat=48.0, lon=37.0),
altitude=400.0,
heading=90.0,
confidence=0.8,
timestamp=datetime.utcnow()
)
class TestResultManager:
# --- 14.01 Feature: Frame Result Persistence ---
def test_update_frame_result_new_frame(self, rm, f03, sample_result):
res = rm.update_frame_result("flight_1", 10, sample_result)
assert res is True
f03.save_frame_result.assert_called_once()
def test_update_frame_result_updates_waypoint(self, rm, f03, sample_result):
rm.update_frame_result("flight_1", 10, sample_result)
f03.insert_waypoint.assert_called_once()
def test_update_frame_result_transaction_atomic(self, rm, f03, f15, sample_result):
f03.execute_transaction.side_effect = None
f03.execute_transaction.return_value = False
res = rm.update_frame_result("flight_1", 10, sample_result)
assert res is False # Because atomic transaction failed
f15.send_frame_result.assert_not_called()
def test_update_frame_result_triggers_sse(self, rm, f15, sample_result):
rm.update_frame_result("flight_1", 10, sample_result)
f15.send_frame_result.assert_called_once()
def test_update_frame_result_refined_flag(self, rm, f03, sample_result):
sample_result.refined = True
rm.update_frame_result("flight_1", 10, sample_result)
# Grab the saved F03 object
args, _ = f03.save_frame_result.call_args
assert args[1].refined is True
def test_publish_waypoint_fetches_latest(self, rm, f03, f15, sample_result):
rm.update_frame_result("flight_1", 10, sample_result)
rm.publish_waypoint_update("flight_1", 10)
f03.get_frame_results.assert_called()
f15.send_frame_result.assert_called()
def test_publish_waypoint_handles_transient_error(self, rm, f03, f15, sample_result):
rm.update_frame_result("flight_1", 10, sample_result)
# Fail twice, succeed third time
f15.send_frame_result.side_effect = [Exception("Net Err"), Exception("Net Err"), True]
assert rm.publish_waypoint_update("flight_1", 10) is True
assert f15.send_frame_result.call_count == 4 # 1 from update + 3 retries
def test_publish_waypoint_logs_on_db_unavailable(self, rm, f03):
f03.get_frame_results.side_effect = Exception("DB Down")
assert rm.publish_waypoint_update("flight_1", 10) is False
# --- 14.03 Feature: Batch Refinement Updates ---
def test_mark_refined_updates_all_frames(self, rm, f03, sample_result):
rm.update_frame_result("flight_ref", 10, sample_result)
ref = RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=48.1, lon=37.1), confidence=0.99)
assert rm.mark_refined("flight_ref", [ref]) is True
# Verify it was updated in the DB
f03_res = f03.get_frame_results("flight_ref")[0]
assert f03_res.gps_center.lat == 48.1
assert f03_res.confidence == 0.99
def test_mark_refined_sets_refined_flag(self, rm, f03, sample_result):
rm.update_frame_result("flight_ref", 10, sample_result)
rm.mark_refined("flight_ref", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
assert f03.get_frame_results("flight_ref")[0].refined is True
def test_mark_refined_updates_gps_coordinates(self, rm, f03, sample_result):
rm.update_frame_result("flight_ref", 10, sample_result)
rm.mark_refined("flight_ref", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=99.0, lon=99.0), confidence=0.9)])
assert f03.get_frame_results("flight_ref")[0].gps_center.lat == 99.0
def test_mark_refined_triggers_sse_per_frame(self, rm, f15, sample_result):
rm.update_frame_result("flight_ref", 10, sample_result)
f15.reset_mock()
rm.mark_refined("flight_ref", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
f15.send_refinement.assert_called_once()
def test_mark_refined_updates_waypoints(self, rm, f03, sample_result):
rm.update_frame_result("flight_ref", 10, sample_result)
f03.insert_waypoint.reset_mock()
rm.mark_refined("flight_ref", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
f03.insert_waypoint.assert_called_once()
def test_chunk_merge_updates_all_frames(self, rm, f03, sample_result):
rm.update_frame_result("flight_chk", 10, sample_result)
ref = RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=48.5, lon=37.5), confidence=0.9)
assert rm.update_results_after_chunk_merge("flight_chk", [ref]) is True
assert f03.get_frame_results("flight_chk")[0].gps_center.lat == 48.5
def test_chunk_merge_sets_refined_flag(self, rm, f03, sample_result):
rm.update_frame_result("flight_chk", 10, sample_result)
ref = RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=48.5, lon=37.5), confidence=0.9)
rm.update_results_after_chunk_merge("flight_chk", [ref])
assert f03.get_frame_results("flight_chk")[0].refined is True
def test_chunk_merge_triggers_sse(self, rm, f15, sample_result):
rm.update_frame_result("flight_chk", 10, sample_result)
f15.reset_mock()
rm.update_results_after_chunk_merge("flight_chk", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
f15.send_refinement.assert_called_once()
def test_batch_transaction_atomic(self, rm, f03, sample_result):
rm.update_frame_result("flight_chk", 10, sample_result)
f03.execute_transaction.side_effect = None
f03.execute_transaction.return_value = False
res = rm.mark_refined("flight_chk", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
assert res is False
# --- 14.02 Feature: Result Retrieval ---
def test_get_flight_results_returns_all_frames(self, rm, sample_result):
rm.update_frame_result("flight_all", 10, sample_result)
res2 = sample_result.model_copy(update={'frame_id': 11})
rm.update_frame_result("flight_all", 11, res2)
results = rm.get_flight_results("flight_all")
assert len(results.frames) == 2
def test_get_flight_results_includes_statistics(self, rm, sample_result):
rm.update_frame_result("flight_stats", 10, sample_result)
results = rm.get_flight_results("flight_stats")
assert results.statistics.total_frames == 1
assert results.statistics.mean_confidence == 0.8
def test_get_flight_results_empty_flight(self, rm):
results = rm.get_flight_results("flight_empty")
assert len(results.frames) == 0
assert results.statistics.total_frames == 0
def test_get_flight_results_performance(self, rm, f03):
f03.get_frame_results.side_effect = None
f03.get_frame_results.return_value = [F03FrameResult(frame_id=i, gps_center=GPSPoint(lat=0, lon=0), altitude=0.0, heading=0.0, confidence=1.0, timestamp=datetime.utcnow(), updated_at=datetime.utcnow()) for i in range(2000)]
start = time.time()
res = rm.get_flight_results("flight_perf")
assert time.time() - start < 0.200
assert len(res.frames) == 2000
def test_get_changed_frames_returns_modified(self, rm, sample_result):
rm.update_frame_result("flight_change", 10, sample_result)
t1 = datetime.utcnow()
time.sleep(0.01)
res2 = sample_result.model_copy(update={'frame_id': 11, 'updated_at': datetime.utcnow()})
rm.update_frame_result("flight_change", 11, res2)
changed = rm.get_changed_frames("flight_change", t1)
assert len(changed) == 1
assert changed[0] == 11
def test_get_changed_frames_empty_result(self, rm, sample_result):
rm.update_frame_result("flight_change", 10, sample_result)
changed = rm.get_changed_frames("flight_change", datetime.utcnow() + timedelta(days=1))
assert len(changed) == 0
def test_get_changed_frames_includes_refined(self, rm, sample_result):
rm.update_frame_result("flight_change", 10, sample_result)
t1 = datetime.utcnow()
time.sleep(0.01)
rm.mark_refined("flight_change", [RefinedFrameResult(frame_id=10, gps_center=GPSPoint(lat=0, lon=0), confidence=0.9)])
changed = rm.get_changed_frames("flight_change", t1)
assert len(changed) == 1
def test_export_results_json(self, rm, sample_result):
rm.update_frame_result("flight_exp", 10, sample_result)
out = rm.export_results("flight_exp", "json")
assert "flight_exp" in out
assert "48.0" in out
def test_export_results_csv(self, rm, sample_result):
rm.update_frame_result("flight_exp", 10, sample_result)
out = rm.export_results("flight_exp", "csv")
assert "image,sequence,lat,lon" in out
assert "AD000010.jpg,10,48.0,37.0" in out
def test_export_results_kml(self, rm, sample_result):
out = rm.export_results("flight_exp", "kml")
assert "<kml" in out and "</kml>" in out