mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-23 00:01:14 +00:00
[AZ-558] Route C8 outbound encoder bytes through MavlinkTransport seam
All FC adapter outbound MAVLink bytes now go through the AZ-401 MavlinkTransport seam (NoopMavlinkTransport in replay, SerialMavlinkTransport in live). New helpers in _outbound_mavlink_payloads.py extract encode/pack/seq-bump so the four AP _send sites and the iNav statustext _send site become encode -> pack -> transport.write. TlogReplayFcAdapter emits real AP-shape MAVLink bytes through the injected NoopMavlinkTransport, satisfying replay protocol Invariant 5 and unblocking AZ-401 AC-9. Closes AZ-558. Also unskips AZ-401 AC-9 and AZ-404 AC-4b. Live wire output remains byte-identical (proven via two-instance MAVLink byte-equivalence tests). AST scan asserts no .mav.<name>_send( calls remain in the retrofit set (AP / iNav / tlog adapters). Out of scope (logged in review): GCS adapter retrofit; airborne live strategy registration that would activate the SerialMavlinkTransport factory injection path. Tests: 2110 passed, 92 environmental skips, 1 unrelated pre-existing macOS cold-start flake deselected. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -35,26 +35,43 @@ from gps_denied_onboard.components.c8_fc_adapter.pymavlink_ardupilot_adapter imp
|
||||
)
|
||||
from gps_denied_onboard.config import load_config
|
||||
|
||||
from ._mav_test_helpers import _FakeMsg
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Helpers — pymavlink stand-in
|
||||
|
||||
|
||||
class _SigningStub:
|
||||
sign_outgoing = False
|
||||
|
||||
|
||||
class _MavStub:
|
||||
"""Captures pymavlink ``mav.*_send`` calls for wire-level assertions."""
|
||||
"""Captures pymavlink ``mav.*_encode`` calls for wire-level assertions.
|
||||
|
||||
Post-AZ-558 the AP adapter routes through ``encode → pack → transport.write``;
|
||||
we record args at the ``encode`` boundary (where the test cares),
|
||||
return a :class:`_FakeMsg` whose ``pack`` produces placeholder bytes,
|
||||
and the transport seam swallows them.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.gps_input_calls: list[tuple[Any, ...]] = []
|
||||
self.named_value_float_calls: list[tuple[Any, ...]] = []
|
||||
self.statustext_calls: list[tuple[int, bytes]] = []
|
||||
self.seq: int = 0
|
||||
self.signing = _SigningStub()
|
||||
|
||||
def gps_input_send(self, *args: Any) -> None:
|
||||
def gps_input_encode(self, *args: Any) -> _FakeMsg:
|
||||
self.gps_input_calls.append(args)
|
||||
return _FakeMsg()
|
||||
|
||||
def named_value_float_send(self, time_boot_ms: int, name: bytes, value: float) -> None:
|
||||
def named_value_float_encode(self, time_boot_ms: int, name: bytes, value: float) -> _FakeMsg:
|
||||
self.named_value_float_calls.append((time_boot_ms, name, value))
|
||||
return _FakeMsg()
|
||||
|
||||
def statustext_send(self, severity: int, text: bytes) -> None:
|
||||
def statustext_encode(self, severity: int, text: bytes) -> _FakeMsg:
|
||||
self.statustext_calls.append((severity, text))
|
||||
return _FakeMsg()
|
||||
|
||||
|
||||
class _ConnStub:
|
||||
@@ -62,10 +79,15 @@ class _ConnStub:
|
||||
self.mav = _MavStub()
|
||||
self.setup_signing_calls: list[bytes] = []
|
||||
self.closed = False
|
||||
self.write_calls: list[bytes] = []
|
||||
|
||||
def setup_signing(self, key: bytes) -> None:
|
||||
self.setup_signing_calls.append(bytes(key))
|
||||
|
||||
def write(self, payload: bytes) -> int:
|
||||
self.write_calls.append(bytes(payload))
|
||||
return len(payload)
|
||||
|
||||
def close(self) -> None:
|
||||
self.closed = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user