fix(k1): stabilize live recovery and media admission
This commit is contained in:
@@ -37,6 +37,7 @@ from k1link.device_plugins.xgrids_k1.facade import (
|
||||
ACTION_PHYSICAL_COMMAND_RECONCILE,
|
||||
ACTION_PHYSICAL_COMMAND_REOPEN_RETIRED_RECONCILIATION,
|
||||
ACTION_PHYSICAL_COMMAND_RETIRE_UNAVAILABLE,
|
||||
ACTION_STATE_READ,
|
||||
ACTION_STREAM_START_LIVE,
|
||||
ACTION_STREAM_START_REPLAY,
|
||||
ACTION_STREAM_STOP,
|
||||
@@ -1285,6 +1286,57 @@ def test_sync_runtime_actions_run_outside_the_api_event_loop() -> None:
|
||||
assert service.thread_id != event_loop_thread
|
||||
|
||||
|
||||
def test_state_reads_are_single_flight_and_survive_one_cancelled_waiter() -> None:
|
||||
class BlockingStateService(FakeXgridsService):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.state_calls = 0
|
||||
self.started = threading.Event()
|
||||
self.release = threading.Event()
|
||||
|
||||
def state(self) -> dict[str, Any]:
|
||||
self.state_calls += 1
|
||||
self.started.set()
|
||||
if not self.release.wait(timeout=2):
|
||||
raise AssertionError("state read was not released by the test")
|
||||
return {"phase": "idle", "revision": self.state_calls}
|
||||
|
||||
service = BlockingStateService()
|
||||
adapter = XgridsK1PluginFacade(service)
|
||||
|
||||
def invocation(invocation_id: str) -> RuntimeActionInvocation:
|
||||
return RuntimeActionInvocation(
|
||||
invocation_id=invocation_id,
|
||||
plugin_id=adapter.plugin_id,
|
||||
action_id=ACTION_STATE_READ,
|
||||
requested_at=datetime.now(UTC),
|
||||
parameters={},
|
||||
)
|
||||
|
||||
async def exercise() -> None:
|
||||
first = asyncio.create_task(adapter.invoke(invocation("state-read-first")))
|
||||
while not service.started.is_set():
|
||||
await asyncio.sleep(0)
|
||||
second = asyncio.create_task(adapter.invoke(invocation("state-read-second")))
|
||||
await asyncio.sleep(0.02)
|
||||
assert service.state_calls == 1
|
||||
|
||||
first.cancel()
|
||||
with pytest.raises(asyncio.CancelledError):
|
||||
await first
|
||||
assert service.state_calls == 1
|
||||
|
||||
service.release.set()
|
||||
assert await second == {"phase": "idle", "revision": 1}
|
||||
assert await adapter.invoke(invocation("state-read-fresh")) == {
|
||||
"phase": "idle",
|
||||
"revision": 2,
|
||||
}
|
||||
|
||||
asyncio.run(exercise())
|
||||
assert service.state_calls == 2
|
||||
|
||||
|
||||
def test_runtime_requires_successful_handshake_before_dispatch() -> None:
|
||||
adapter = XgridsK1PluginFacade(FakeXgridsService())
|
||||
runtime = _in_process_runtime(adapter, activate=False)
|
||||
|
||||
Reference in New Issue
Block a user