From 6a6e00bf39527dca693fd9ba798384c10220263a Mon Sep 17 00:00:00 2001 From: mnajafian-nv Date: Tue, 20 Oct 2026 02:59:41 -0700 Subject: [PATCH] test: count event-loop turns in the OpenClaw stop test The test gave stop() 0.2 s of wall-clock time to propagate its cancellation. After the cancellation, stop() awaits only mocks and in-process tasks and finishes in 1 to 7 event-loop turns, so only a process pause could fail it: a pause of more than 0.2 s while the test waited could raise TimeoutError. A full garbage collection at this test takes 161 to 219 ms on an M-series Mac with Python 3.14 when tests/adapters/ runs, and the Python 3.14 jobs on Windows and linux-arm64 have been failing this test on pull requests that do not change stop() or this test. Wait for each step by counting event-loop turns (at most 100) instead of seconds. The test still fails when stop() keeps waiting on the blocked cleanup step after the cancellation, never reaches it, or returns without re-raising the cancellation. Signed-off-by: mnajafian-nv --- tests/adapters/test_openclaw.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/adapters/test_openclaw.py b/tests/adapters/test_openclaw.py index 031624bf2..5f0a37604 100644 --- a/tests/adapters/test_openclaw.py +++ b/tests/adapters/test_openclaw.py @@ -1142,14 +1142,26 @@ async def wait_for_process(): runtime._log_tasks = [log_task] runtime._temp_dir = mock_temp_dir + # stop() awaits only mocks and in-process tasks here, and no timer has to + # fire, so each step finishes within a few event-loop turns. Counting turns + # instead of seconds keeps a garbage-collector pause on a slow runner from + # failing the test. + async def run_event_loop_until(condition): + for _ in range(100): + if condition(): + return True + await asyncio.sleep(0) + return condition() + stop_task = asyncio.create_task(runtime.stop()) - await asyncio.wait_for(entered.wait(), timeout=1) - stop_task.cancel() try: - with pytest.raises(asyncio.CancelledError): - await asyncio.wait_for(asyncio.shield(stop_task), timeout=0.2) + assert await run_event_loop_until(entered.is_set) + stop_task.cancel() + assert await run_event_loop_until(stop_task.done) + assert stop_task.cancelled() finally: release.set() + stop_task.cancel() with suppress(asyncio.CancelledError): await stop_task