Files
NODEDC_MISSION_CORE/tests/test_node_rerun.py
T

81 lines
3.1 KiB
Python

"""Native RRD empty reads are pauses, not peer EOF. No device/network involved."""
import time
from k1link.data_plane import ConsumerFrameContext, DecodedPointCloudView
from k1link.viewer.node_rerun import NodeRerunBridge, RrdSubscriber
from k1link.viewer.rerun_bridge import RerunSceneSettings
def points(sequence=1, age=0):
now = time.monotonic_ns()
return DecodedPointCloudView(
context=ConsumerFrameContext(sequence, time.time_ns(), now - int(age * 1e9), now, 1, True),
frame_id="world", positions_xyz=((1.0, 2.0, 3.0),), intensities=b"\x01",
)
def drain_until(subscriber, predicate, seconds=3):
deadline = time.monotonic() + seconds
payloads = []
while time.monotonic() < deadline:
payload = subscriber.read()
assert payload is not None, "idle native binary read retired the live subscriber"
if payload:
assert payload.startswith(b"RRF2")
payloads.append(payload)
if predicate():
return payloads
raise AssertionError("native subscriber did not make progress")
def test_native_idle_read_keeps_subscriber_alive_and_resumes():
subscriber = RrdSubscriber(RerunSceneSettings)
try:
assert drain_until(subscriber, lambda: subscriber.output.empty())
# This forces several SDK reads with no data; the previous len(None)
# retired both RRD and camera before a first point could arrive.
assert subscriber.read() == b""
assert not subscriber.closed.is_set()
subscriber.offer(points())
assert drain_until(subscriber, lambda: subscriber.snapshot()["sequence"] == 1)
assert subscriber.read() == b""
subscriber.offer(points(2))
assert drain_until(subscriber, lambda: subscriber.snapshot()["sequence"] == 2)
assert subscriber.snapshot()["points"] == 1
assert not subscriber.closed.is_set()
finally:
subscriber.close()
subscriber.thread.join(timeout=3)
assert not subscriber.thread.is_alive()
def test_subscriber_does_not_publish_queued_stale_points():
subscriber = RrdSubscriber(RerunSceneSettings)
try:
drain_until(subscriber, lambda: subscriber.output.empty())
subscriber.offer(points(age=5))
assert subscriber.read() == b""
assert subscriber.snapshot()["sequence"] == 0
subscriber.offer(points(2))
drain_until(subscriber, lambda: subscriber.snapshot()["sequence"] == 2)
finally:
subscriber.close()
subscriber.thread.join(timeout=3)
def test_reopened_viewer_does_not_replay_cached_points_after_source_pause(monkeypatch):
bridge = NodeRerunBridge()
try:
bridge.process(points())
cached_at, frame = next(iter(bridge.latest.values()))
bridge.latest[type(frame)] = (cached_at - 5, frame)
sub = bridge.subscribe()
drain_until(sub, lambda: sub.output.empty())
assert sub.read() == b""
assert sub.snapshot()["sequence"] == 0
bridge.process(points(2))
drain_until(sub, lambda: sub.snapshot()["sequence"] == 2)
finally:
bridge.close()
sub.thread.join(timeout=3)