Preserve RRD preview frames and clarify onboard K1 status
This commit is contained in:
@@ -1702,3 +1702,21 @@ def test_exact_session_invalidation_does_not_clear_new_scan_handle() -> None:
|
||||
) is not None
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platform,present", [("linux", True), ("linux", False), ("darwin", False)])
|
||||
def test_status_read_native_cache_check_is_linux_only(monkeypatch, platform, present):
|
||||
from types import SimpleNamespace
|
||||
|
||||
calls = []
|
||||
device = BLEDevice("AA:BB:CC:DD:EE:FF", "synthetic", {"path": "/synthetic/bluez"})
|
||||
|
||||
async def retrieve(address, details):
|
||||
calls.append((address, details))
|
||||
return device if present else None
|
||||
|
||||
monkeypatch.setattr(scanner_module, "sys", SimpleNamespace(platform=platform))
|
||||
monkeypatch.setattr(scanner_module, "_retrieve_bluez_device", retrieve)
|
||||
assert asyncio.run(scanner_module.status_read_device_is_current(device)) is (
|
||||
present or platform == "darwin")
|
||||
assert len(calls) == (1 if platform == "linux" else 0)
|
||||
|
||||
@@ -4,7 +4,7 @@ import queue
|
||||
import pytest
|
||||
from aiortc import RTCConfiguration, RTCPeerConnection, RTCSessionDescription
|
||||
|
||||
from k1link.viewer.node_media import NodeMediaPeers, admit_sdp
|
||||
from k1link.viewer.node_media import MEDIA_PROTOCOL, NodeMediaPeers, admit_sdp
|
||||
|
||||
SDP_HEADER = "v=0\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
|
||||
|
||||
@@ -51,7 +51,7 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
|
||||
class Subscription:
|
||||
def __init__(self):
|
||||
self.output = queue.Queue()
|
||||
self.output.put(b"RRF2-transport-fixture")
|
||||
self.output.put(payload)
|
||||
|
||||
def read(self):
|
||||
try:
|
||||
@@ -68,7 +68,16 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
|
||||
|
||||
class Camera:
|
||||
def snapshot(self):
|
||||
return {"generation": None}
|
||||
return {"generation": None, "phase": "error"}
|
||||
|
||||
# The old test's sub-16KB fake payload missed the actual fragmentation bug.
|
||||
import numpy as np
|
||||
import rerun as rr
|
||||
recording = rr.RecordingStream("synthetic-node-media")
|
||||
binary = recording.binary_stream()
|
||||
recording.log("points", rr.Points3D(np.random.default_rng(42).random((5000, 3))))
|
||||
payload = binary.read()
|
||||
assert payload.startswith(b"RRF2") and len(payload) > 16384
|
||||
|
||||
async def run():
|
||||
peers = NodeMediaPeers(Hub(), Camera())
|
||||
@@ -82,7 +91,8 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
|
||||
@channel.on("message")
|
||||
def message(data):
|
||||
payloads.append(data)
|
||||
received.set()
|
||||
if len(payloads) > 1 and sum(map(len, payloads[1:])) == len(payload):
|
||||
received.set()
|
||||
|
||||
try:
|
||||
await client.setLocalDescription(await client.createOffer())
|
||||
@@ -91,7 +101,10 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
|
||||
RTCSessionDescription(sdp=answer["sdp"], type="answer")
|
||||
)
|
||||
await asyncio.wait_for(received.wait(), timeout=8)
|
||||
assert payloads == [b"RRF2-transport-fixture"]
|
||||
assert answer["media_protocol"] == MEDIA_PROTOCOL
|
||||
assert payloads[0] == b"MCF1" + len(payload).to_bytes(4, "big")
|
||||
assert b"".join(payloads[1:]) == payload
|
||||
assert all(len(part) <= 16384 for part in payloads[1:])
|
||||
assert answer["peer_id"] in peers.items
|
||||
assert channel.readyState == "open"
|
||||
finally:
|
||||
@@ -100,3 +113,43 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
|
||||
assert not peers.items
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
|
||||
def test_camera_waits_for_post_calibration_producer_and_delivers_metadata():
|
||||
class Camera:
|
||||
calls = 0
|
||||
opened = []
|
||||
|
||||
def snapshot(self):
|
||||
self.calls += 1
|
||||
return {"generation": None} if self.calls < 2 else {
|
||||
"generation": 3, "delivery": {"media_type": "video/mp4"}}
|
||||
|
||||
def open_delivery(self, generation):
|
||||
self.opened.append(generation)
|
||||
return "lease"
|
||||
|
||||
class Channel:
|
||||
messages = []
|
||||
|
||||
def send(self, data):
|
||||
self.messages.append(data)
|
||||
|
||||
async def run():
|
||||
camera, channel = Camera(), Channel()
|
||||
peers = NodeMediaPeers(None, camera)
|
||||
peers.items["synthetic"] = {}
|
||||
assert await peers.camera_delivery("synthetic", channel) == "lease"
|
||||
assert camera.opened == [3]
|
||||
import json
|
||||
assert json.loads(channel.messages[0]) == {"type": "camera-ready", "mime": "video/mp4"}
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
|
||||
def test_installed_camera_uses_declared_os_ffmpeg():
|
||||
from pathlib import Path
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
unit = (root / "plugins/xgrids-k1/packaging/mission-core-k1.service").read_text()
|
||||
assert "Environment=MISSIONCORE_FFMPEG_BINARY=/usr/bin/ffmpeg" in unit
|
||||
assert "iproute2, ffmpeg" in (root / "plugins/xgrids-k1/packaging/build_deb.py").read_text()
|
||||
|
||||
@@ -134,8 +134,10 @@ def test_parse_wifi_status_rejects_short_frame() -> None:
|
||||
parse_wifi_status(bytes(50))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("current_handle", [True, False])
|
||||
def test_read_wifi_status_once_reads_only_and_returns_current_dhcp_address(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
current_handle: bool,
|
||||
) -> None:
|
||||
value = bytearray(54)
|
||||
value[0] = 11
|
||||
@@ -167,8 +169,11 @@ def test_read_wifi_status_once_reads_only_and_returns_current_dhcp_address(
|
||||
return status_characteristic
|
||||
return None
|
||||
|
||||
connected = []
|
||||
|
||||
class FakeClient:
|
||||
def __init__(self, _device: object, **_kwargs: object) -> None:
|
||||
connected.append(_device)
|
||||
self.services = FakeServices()
|
||||
self.name = "XGR-K1"
|
||||
self.mtu_size = 256
|
||||
@@ -197,6 +202,19 @@ def test_read_wifi_status_once_reads_only_and_returns_current_dhcp_address(
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(wifi_module, "BleakClient", FakeClient)
|
||||
fresh_handle, capture, scans = object(), object(), []
|
||||
|
||||
async def is_current(_device):
|
||||
return current_handle
|
||||
|
||||
async def refresh_exact(address, **_kwargs):
|
||||
scans.append(address)
|
||||
return capture
|
||||
|
||||
monkeypatch.setattr(wifi_module, "status_read_device_is_current", is_current)
|
||||
monkeypatch.setattr(wifi_module, "discover_known_device_capture_for_status_read", refresh_exact)
|
||||
monkeypatch.setattr(wifi_module, "captured_device_handle", lambda value: fresh_handle)
|
||||
monkeypatch.setattr(wifi_module, "mark_captured_device_gatt_validated", lambda *_a, **_k: True)
|
||||
|
||||
result = asyncio.run(read_wifi_status_once("synthetic-corebluetooth-uuid"))
|
||||
|
||||
@@ -207,6 +225,8 @@ def test_read_wifi_status_once_reads_only_and_returns_current_dhcp_address(
|
||||
assert result["max_write_without_response_size"] == 244
|
||||
assert result["mtu_size"] == 256
|
||||
assert result["status"]["ipv4"] == "10.255.254.77"
|
||||
assert connected == [retained_handle if current_handle else fresh_handle]
|
||||
assert scans == ([] if current_handle else ["synthetic-corebluetooth-uuid"])
|
||||
|
||||
|
||||
def test_read_wifi_status_recovery_keeps_fresh_retained_handle(
|
||||
|
||||
Reference in New Issue
Block a user