mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 16:51:13 +00:00
[AZ-595] Batch 75: sitl_observer FDR-replay + scenario probe cleanup
Implement all 11 `sitl_observer` public surfaces as an offline
FDR-replay strategy (reads JSON fixtures under `${E2E_SITL_REPLAY_DIR}`
instead of live pymavlink/yamspy). Replace 12 per-scenario
`_harness_helpers_implemented` probes with one shared session-scoped
`sitl_replay_ready` fixture in `e2e/tests/conftest.py`.
Net: -636 LoC of duplicated scenario gating, +17 LoC shared fixture,
+38 new unit tests (596 total, up from 558). Includes K=3 cumulative
review for batches 73-75 (PASS).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,40 +22,6 @@ from fixtures.injectors.outlier import OutlierInjectionReport
|
||||
from runner.helpers import outlier_tolerance_evaluator as ote
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def _harness_helpers_implemented() -> bool:
|
||||
from runner.helpers import fdr_reader, imu_replay
|
||||
from runner.helpers.frame_source_replay import FrameSourceReplayer
|
||||
|
||||
try:
|
||||
replayer = FrameSourceReplayer(sink=_NullSink()) # type: ignore[arg-type]
|
||||
try:
|
||||
replayer.replay_video(Path("/tmp/non-existent.mp4"))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(fdr_reader.iter_records(Path("/tmp/non-existent")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
imu_replay.ImuReplayer(emitter=_NullImuEmitter()).replay(Path("/tmp/non-existent.csv")) # type: ignore[arg-type]
|
||||
except NotImplementedError:
|
||||
return False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class _NullSink:
|
||||
def write_frame(self, jpeg_bytes: bytes, timestamp_ms: int) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class _NullImuEmitter:
|
||||
def emit(self, sample: object) -> None:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"outlier_injection_derkachi",
|
||||
[{"density": "medium", "seed": 0}],
|
||||
@@ -69,14 +35,13 @@ def test_ft_n_01_outlier_tolerance(
|
||||
evidence_dir, # type: ignore[no-untyped-def]
|
||||
run_id: str,
|
||||
nfr_recorder, # type: ignore[no-untyped-def]
|
||||
_harness_helpers_implemented: bool,
|
||||
sitl_replay_ready: bool,
|
||||
) -> None:
|
||||
if not _harness_helpers_implemented:
|
||||
if not sitl_replay_ready:
|
||||
pytest.skip(
|
||||
"FT-N-01 full replay requires runner.helpers.{frame_source_replay,"
|
||||
"fdr_reader,imu_replay} — currently AZ-441 / AZ-407 leftovers. "
|
||||
"AC-1/AC-2/AC-3 helper logic covered by "
|
||||
"e2e/_unit_tests/helpers/test_outlier_tolerance_evaluator.py."
|
||||
"FT-N-01 full replay requires `E2E_SITL_REPLAY_DIR` to point at a "
|
||||
"prepared SITL replay fixture (AZ-595). AC-1/AC-2/AC-3 helper logic "
|
||||
"covered by e2e/_unit_tests/helpers/test_outlier_tolerance_evaluator.py."
|
||||
)
|
||||
|
||||
from runner.helpers import fdr_reader
|
||||
|
||||
@@ -35,40 +35,6 @@ DERKACHI_IMU_CSV = DERKACHI_DIR / "data_imu.csv"
|
||||
DERKACHI_MP4 = DERKACHI_DIR / "flight_derkachi.mp4"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def _harness_helpers_implemented() -> bool:
|
||||
from runner.helpers import fdr_reader, imu_replay
|
||||
from runner.helpers.frame_source_replay import FrameSourceReplayer
|
||||
|
||||
try:
|
||||
replayer = FrameSourceReplayer(sink=_NullSink()) # type: ignore[arg-type]
|
||||
try:
|
||||
replayer.replay_video(Path("/tmp/non-existent.mp4"))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(fdr_reader.iter_records(Path("/tmp/non-existent")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
imu_replay.ImuReplayer(emitter=_NullImuEmitter()).replay(Path("/tmp/non-existent.csv")) # type: ignore[arg-type]
|
||||
except NotImplementedError:
|
||||
return False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class _NullSink:
|
||||
def write_frame(self, jpeg_bytes: bytes, timestamp_ms: int) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class _NullImuEmitter:
|
||||
def emit(self, sample: object) -> None:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.traces_to("AC-3.2,AC-1,AC-2,AC-3,AC-7")
|
||||
def test_ft_n_02_sharp_turn_failure(
|
||||
fc_adapter: str,
|
||||
@@ -76,14 +42,13 @@ def test_ft_n_02_sharp_turn_failure(
|
||||
evidence_dir, # type: ignore[no-untyped-def]
|
||||
run_id: str,
|
||||
nfr_recorder, # type: ignore[no-untyped-def]
|
||||
_harness_helpers_implemented: bool,
|
||||
sitl_replay_ready: bool,
|
||||
) -> None:
|
||||
if not _harness_helpers_implemented:
|
||||
if not sitl_replay_ready:
|
||||
pytest.skip(
|
||||
"FT-N-02 full replay requires runner.helpers.{frame_source_replay,"
|
||||
"imu_replay,fdr_reader} — currently AZ-441 / AZ-407 leftovers. "
|
||||
"AC-2/AC-3 helper logic covered by "
|
||||
"e2e/_unit_tests/helpers/test_sharp_turn_detector.py."
|
||||
"FT-N-02 full replay requires `E2E_SITL_REPLAY_DIR` to point at a "
|
||||
"prepared SITL replay fixture (AZ-595). AC-2/AC-3 helper logic "
|
||||
"covered by e2e/_unit_tests/helpers/test_sharp_turn_detector.py."
|
||||
)
|
||||
|
||||
from runner.helpers import fdr_reader
|
||||
|
||||
@@ -31,39 +31,6 @@ DERKACHI_DIR = (
|
||||
DERKACHI_MP4 = DERKACHI_DIR / "flight_derkachi.mp4"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def _harness_helpers_implemented() -> bool:
|
||||
from runner.helpers import fdr_reader, mavproxy_tlog_reader, sitl_observer
|
||||
from runner.helpers.frame_source_replay import FrameSourceReplayer
|
||||
|
||||
try:
|
||||
replayer = FrameSourceReplayer(sink=_NullSink()) # type: ignore[arg-type]
|
||||
try:
|
||||
replayer.replay_video(Path("/tmp/non-existent.mp4"))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(fdr_reader.iter_records(Path("/tmp/non-existent")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(mavproxy_tlog_reader.iter_messages(Path("/tmp/non-existent.tlog")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
sitl_observer.read_ekf_divergence_events() # type: ignore[attr-defined]
|
||||
except (AttributeError, NotImplementedError):
|
||||
return False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class _NullSink:
|
||||
def write_frame(self, jpeg_bytes: bytes, timestamp_ms: int) -> None:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.traces_to("AC-3.4,AC-1,AC-2,AC-3,AC-4,AC-5")
|
||||
def test_ft_n_03_outage_reloc(
|
||||
fc_adapter: str,
|
||||
@@ -71,13 +38,12 @@ def test_ft_n_03_outage_reloc(
|
||||
evidence_dir, # type: ignore[no-untyped-def]
|
||||
run_id: str,
|
||||
nfr_recorder, # type: ignore[no-untyped-def]
|
||||
_harness_helpers_implemented: bool,
|
||||
sitl_replay_ready: bool,
|
||||
) -> None:
|
||||
if not _harness_helpers_implemented:
|
||||
if not sitl_replay_ready:
|
||||
pytest.skip(
|
||||
"FT-N-03 full replay requires runner.helpers.{frame_source_replay,"
|
||||
"fdr_reader,mavproxy_tlog_reader,sitl_observer} — currently "
|
||||
"AZ-441 / AZ-407 / AZ-416 leftovers. AC-1..AC-4 evaluator logic "
|
||||
"FT-N-03 full replay requires `E2E_SITL_REPLAY_DIR` to point at a "
|
||||
"prepared SITL replay fixture (AZ-595). AC-1..AC-4 evaluator logic "
|
||||
"covered by e2e/_unit_tests/helpers/test_outage_request_evaluator.py."
|
||||
)
|
||||
|
||||
|
||||
@@ -26,40 +26,6 @@ from runner.helpers import blackout_spoof_evaluator as bse
|
||||
_WINDOW_LADDER_S = (5.0, 15.0, 35.0)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def _harness_helpers_implemented() -> bool:
|
||||
from runner.helpers import fdr_reader, mavproxy_tlog_reader, sitl_observer
|
||||
from runner.helpers.frame_source_replay import FrameSourceReplayer
|
||||
|
||||
try:
|
||||
replayer = FrameSourceReplayer(sink=_NullSink()) # type: ignore[arg-type]
|
||||
try:
|
||||
replayer.replay_video(Path("/tmp/non-existent.mp4"))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(fdr_reader.iter_records(Path("/tmp/non-existent")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
list(mavproxy_tlog_reader.iter_messages(Path("/tmp/non-existent.tlog")))
|
||||
except NotImplementedError:
|
||||
return False
|
||||
try:
|
||||
sitl_observer.read_gps_health_samples() # type: ignore[attr-defined]
|
||||
sitl_observer.read_consistency_check_events() # type: ignore[attr-defined]
|
||||
except (AttributeError, NotImplementedError):
|
||||
return False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class _NullSink:
|
||||
def write_frame(self, jpeg_bytes: bytes, timestamp_ms: int) -> None:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"blackout_spoof_derkachi",
|
||||
[{"window_seconds": s, "seed": 0} for s in _WINDOW_LADDER_S],
|
||||
@@ -76,14 +42,14 @@ def test_ft_n_04_blackout_spoof(
|
||||
evidence_dir, # type: ignore[no-untyped-def]
|
||||
run_id: str,
|
||||
nfr_recorder, # type: ignore[no-untyped-def]
|
||||
_harness_helpers_implemented: bool,
|
||||
sitl_replay_ready: bool,
|
||||
) -> None:
|
||||
if not _harness_helpers_implemented:
|
||||
if not sitl_replay_ready:
|
||||
pytest.skip(
|
||||
"FT-N-04 full replay requires runner.helpers.{frame_source_replay,"
|
||||
"fdr_reader,mavproxy_tlog_reader,sitl_observer,fc_proxy} — currently "
|
||||
"AZ-441 / AZ-407 / AZ-416 leftovers. AC-1..AC-8 evaluator logic "
|
||||
"covered by e2e/_unit_tests/helpers/test_blackout_spoof_evaluator.py."
|
||||
"FT-N-04 full replay requires `E2E_SITL_REPLAY_DIR` to point at a "
|
||||
"prepared SITL replay fixture (AZ-595) AND a runtime fc_proxy "
|
||||
"driver. AC-1..AC-8 evaluator logic covered by "
|
||||
"e2e/_unit_tests/helpers/test_blackout_spoof_evaluator.py."
|
||||
)
|
||||
|
||||
from runner.helpers import fdr_reader, mavproxy_tlog_reader, sitl_observer
|
||||
|
||||
Reference in New Issue
Block a user