mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-23 02:21:12 +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:
@@ -23,16 +23,16 @@ What this file does NOT own:
|
||||
(still a stub; AZ-408 was about the synthetic-injection injectors,
|
||||
not the video replayer); the scenario is marked
|
||||
``@pytest.mark.deferred_ac(reason=...)`` until that helper lands.
|
||||
* The FDR-archive iteration → ``runner.helpers.fdr_reader`` (owned by
|
||||
AZ-441); same skip gate.
|
||||
* The FDR-archive iteration → ``runner.helpers.fdr_reader`` (AZ-594,
|
||||
landed in batch 74) — the scenario still depends on a prepared SITL
|
||||
replay fixture (AZ-595) that produces the per-run FDR archive.
|
||||
* The MAVLink ``GLOBAL_POSITION_INT`` GT replay → handled by the
|
||||
``imu_replay`` helper which currently raises NotImplementedError
|
||||
(owned by AZ-407 in spec, but the helper file was not touched by
|
||||
the AZ-407 batch).
|
||||
``imu_replay`` helper (AZ-594, landed in batch 74).
|
||||
|
||||
When all three upstream helpers land, this file's runtime path activates
|
||||
automatically — the skip is keyed off the ``NotImplementedError`` from
|
||||
the helper imports, not off a hard-coded marker.
|
||||
When ``E2E_SITL_REPLAY_DIR`` is set and points at a prepared SITL
|
||||
replay fixture, this file's runtime path activates automatically; until
|
||||
then the scenario skips via the shared `sitl_replay_ready` fixture
|
||||
(AZ-595).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -44,53 +44,6 @@ import pytest
|
||||
from runner.helpers import anchor_pair_detector as apd
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def _harness_helpers_implemented() -> bool:
|
||||
"""True iff every upstream helper FT-P-02 needs has a real impl.
|
||||
|
||||
Used to gate the full-replay scenarios. Helper-level NotImplementedError
|
||||
is the signal — we don't hard-code a "deferred until task X" marker
|
||||
because then a developer who lands the helper would have to also
|
||||
remember to flip the marker. The auto-detect pattern is also what
|
||||
other downstream scenarios will reuse.
|
||||
"""
|
||||
from runner.helpers import fdr_reader, frame_source_replay, imu_replay
|
||||
from runner.helpers.frame_source_replay import FrameSourceReplayer
|
||||
try:
|
||||
# The cheapest sentinel for each helper:
|
||||
# - FrameSourceReplayer.replay_video raises NotImplementedError
|
||||
# - fdr_reader.iter_records raises NotImplementedError
|
||||
# - ImuReplayer.replay raises NotImplementedError
|
||||
# We check by inspecting __doc__ / source rather than calling, so
|
||||
# the gate stays cheap.
|
||||
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-1.3,AC-1,AC-2,AC-3,AC-4,AC-5")
|
||||
def test_ft_p_02_derkachi_drift(
|
||||
fc_adapter: str,
|
||||
@@ -98,7 +51,7 @@ def test_ft_p_02_derkachi_drift(
|
||||
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:
|
||||
"""Full FT-P-02 scenario (AC-1.3). See module docstring.
|
||||
|
||||
@@ -110,11 +63,11 @@ def test_ft_p_02_derkachi_drift(
|
||||
AC-4: bin medians monotonic with age — covered by check_monotonic().
|
||||
AC-5: parametrized across (fc_adapter, vio_strategy).
|
||||
"""
|
||||
if not _harness_helpers_implemented:
|
||||
if not sitl_replay_ready:
|
||||
pytest.skip(
|
||||
"FT-P-02 full replay requires runner.helpers.{frame_source_replay,"
|
||||
"fdr_reader,imu_replay} — currently AZ-441 / AZ-407 leftovers. "
|
||||
"Pure-logic ACs covered by e2e/_unit_tests/helpers/test_anchor_pair_detector.py."
|
||||
"FT-P-02 full replay requires `E2E_SITL_REPLAY_DIR` to point at a "
|
||||
"prepared SITL replay fixture (AZ-595). Pure-logic ACs covered by "
|
||||
"e2e/_unit_tests/helpers/test_anchor_pair_detector.py."
|
||||
)
|
||||
|
||||
# Once the helpers land, the body below activates. We keep it
|
||||
|
||||
Reference in New Issue
Block a user