fix(k1): restore low-latency live recovery path
This commit is contained in:
@@ -6,6 +6,7 @@ import json
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1416,16 +1417,60 @@ def test_source_end_none_epoch_cas_waits_for_canonical_archive_seal(
|
||||
gateway.close()
|
||||
|
||||
|
||||
def test_acquisition_candidate_never_spawns_before_authority_reservation(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("MISSIONCORE_FFMPEG_BINARY", str(_silent_ffmpeg(tmp_path)))
|
||||
session = tmp_path / "sessions" / "camera-pre-popen-denied"
|
||||
session.mkdir(parents=True)
|
||||
gateway = XgridsK1CameraGateway(tmp_path, XGRIDS_K1_PLUGIN_ID)
|
||||
popen_called = False
|
||||
|
||||
def forbidden_popen(*_: object, **__: object) -> object:
|
||||
nonlocal popen_called
|
||||
popen_called = True
|
||||
raise AssertionError("FFmpeg must not start before authority reservation")
|
||||
|
||||
monkeypatch.setattr(camera_module.subprocess, "Popen", forbidden_popen)
|
||||
try:
|
||||
with pytest.raises(ValueError, match="authority"):
|
||||
gateway.activate_recording_producer(
|
||||
"sensor.camera.right",
|
||||
"192.168.1.20",
|
||||
session,
|
||||
pre_prepare_fence=lambda _reserve: False,
|
||||
commit_fence=lambda commit: commit(),
|
||||
)
|
||||
|
||||
snapshot = gateway.snapshot()
|
||||
assert popen_called is False
|
||||
assert snapshot["active_source_id"] is None
|
||||
assert snapshot["recording"]["active"] is False
|
||||
finally:
|
||||
gateway.close()
|
||||
|
||||
|
||||
def test_acquisition_candidate_binds_epoch_before_any_reader_thread_starts(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
monkeypatch.setenv("MISSIONCORE_FFMPEG_BINARY", str(_silent_ffmpeg(tmp_path)))
|
||||
session = tmp_path / "sessions" / "camera-bind-before-reader"
|
||||
session.mkdir(parents=True)
|
||||
gateway = XgridsK1CameraGateway(tmp_path, XGRIDS_K1_PLUGIN_ID)
|
||||
caplog.set_level("INFO", logger="k1link.device_plugins.xgrids_k1.camera")
|
||||
bound_generation: list[int] = []
|
||||
reader_start_generation: list[int] = []
|
||||
authority_reserved = False
|
||||
|
||||
def reserve_authority(reserve: Callable[[], bool]) -> bool:
|
||||
nonlocal authority_reserved
|
||||
assert authority_reserved is False
|
||||
assert reserve() is True
|
||||
authority_reserved = True
|
||||
return True
|
||||
|
||||
def bind(committed: dict[str, object]) -> None:
|
||||
recording = committed["recording"]
|
||||
@@ -1436,6 +1481,7 @@ def test_acquisition_candidate_binds_epoch_before_any_reader_thread_starts(
|
||||
|
||||
def start_threads(producer: object) -> None:
|
||||
generation = producer.generation # type: ignore[attr-defined]
|
||||
assert authority_reserved is True
|
||||
assert bound_generation == [generation]
|
||||
reader_start_generation.append(generation)
|
||||
|
||||
@@ -1445,6 +1491,7 @@ def test_acquisition_candidate_binds_epoch_before_any_reader_thread_starts(
|
||||
"sensor.camera.right",
|
||||
"192.168.1.20",
|
||||
session,
|
||||
pre_prepare_fence=reserve_authority,
|
||||
commit_fence=lambda commit: commit(),
|
||||
committed_before_start=bind,
|
||||
)
|
||||
@@ -1452,6 +1499,16 @@ def test_acquisition_candidate_binds_epoch_before_any_reader_thread_starts(
|
||||
assert bound_generation == [activated["recording"]["active_epoch"]]
|
||||
assert reader_start_generation == bound_generation
|
||||
assert activated["recording"]["media_ready"] is False
|
||||
timing = [
|
||||
record
|
||||
for record in caplog.records
|
||||
if getattr(record, "event_code", None) == "k1_camera_activation_timing"
|
||||
]
|
||||
assert len(timing) == 1
|
||||
assert timing[0].camera_generation == bound_generation[0]
|
||||
assert timing[0].camera_authority_wait_ms >= 0
|
||||
assert timing[0].camera_ffmpeg_prepare_ms >= 0
|
||||
assert timing[0].camera_post_spawn_commit_ms >= 0
|
||||
finally:
|
||||
gateway.close()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user