From bf162b3654c0d858725aee7363a43aea07a62ea7 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Mon, 2 Nov 2026 12:25:24 +0800 Subject: [PATCH 1/3] Allow a second status read before a 10 ms DAG wait budget runs out With a 10 ms budget, the poll's wait can wake just before the deadline on Windows' coarse timer and read the task status once more before the timeout fires; the test required exactly one read and failed on the release PR's Windows 3.13 runner. For the timeout case it now checks what the waiter promises: submit first, one or more status reads, a pause last. --- test/unit_test/headless/test_dag_managed_tasks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unit_test/headless/test_dag_managed_tasks.py b/test/unit_test/headless/test_dag_managed_tasks.py index baef2cf9e..ac56eaf47 100644 --- a/test/unit_test/headless/test_dag_managed_tasks.py +++ b/test/unit_test/headless/test_dag_managed_tasks.py @@ -170,7 +170,13 @@ def endpoint(operation, _body, _timeout): result = run_dag(definition(payload), stop_event=stop) assert not result.succeeded assert result.nodes["one"].result["input_released"] is None - assert calls == ["submit", "get", "pause"] + if reason == "timeout": + # A 10 ms budget: the poll's wait can wake just before the deadline on a coarse + # (Windows) timer and read the status once more before the budget runs out. + assert calls[0] == "submit" and calls[-1] == "pause", calls + assert calls[1:-1] and set(calls[1:-1]) == {"get"}, calls + else: + assert calls == ["submit", "get", "pause"] def test_owner_revocation_during_poll_stops_dispatch_and_preserves_review(tmp_path, monkeypatch): From da4f6491819e393483282586d9fe95c9e1e6be22 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Mon, 2 Nov 2026 12:34:13 +0800 Subject: [PATCH 2/3] Wait for the panel's reconnect before checking its clipboard The viewer panel connects off the GUI thread, and its clipboard authority is adopted when the connect answers. The reconnect case enqueued the new viewer's clipboard after a single processEvents(), so on a slow runner (the release PR's Windows 3.10) the connect had not answered yet and the authorised clipboard was dropped. It now settles the connect first, as the test's own _tab() helper does. --- test/unit_test/headless/test_remote_clipboard_delivery_gui.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit_test/headless/test_remote_clipboard_delivery_gui.py b/test/unit_test/headless/test_remote_clipboard_delivery_gui.py index 65c4c8291..61c336832 100644 --- a/test/unit_test/headless/test_remote_clipboard_delivery_gui.py +++ b/test/unit_test/headless/test_remote_clipboard_delivery_gui.py @@ -7,6 +7,7 @@ import pytest pytest.importorskip('PySide6.QtWidgets', exc_type=ImportError) +from headless._qt_settle import settle from headless.test_remote_registry_owners_gui import qapp as qapp, _tab from je_auto_control.utils.clipboard import clipboard from je_auto_control.utils.rbac import AuthorizationContext, Role, UserStore, authorization_scope, current_authorization @@ -42,6 +43,7 @@ def test_queued_clipboard_from_a_disconnected_gui_viewer_cannot_apply_to_a_repla panel._disconnect() if reconnect: panel._connect() + settle(panel) # the connect runs off the GUI thread; its viewer is adopted when it answers qapp.processEvents() assert applied == [], 'the queued clipboard from the old connection changed local state' if reconnect: From 36880c436fd912f6ff7277cd7915594fc2336a5e Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Mon, 2 Nov 2026 12:39:25 +0800 Subject: [PATCH 3/3] Split the DAG wait test's composite assertions --- test/unit_test/headless/test_dag_managed_tasks.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit_test/headless/test_dag_managed_tasks.py b/test/unit_test/headless/test_dag_managed_tasks.py index ac56eaf47..ba258d970 100644 --- a/test/unit_test/headless/test_dag_managed_tasks.py +++ b/test/unit_test/headless/test_dag_managed_tasks.py @@ -173,8 +173,10 @@ def endpoint(operation, _body, _timeout): if reason == "timeout": # A 10 ms budget: the poll's wait can wake just before the deadline on a coarse # (Windows) timer and read the status once more before the budget runs out. - assert calls[0] == "submit" and calls[-1] == "pause", calls - assert calls[1:-1] and set(calls[1:-1]) == {"get"}, calls + assert calls[0] == "submit", calls + assert calls[-1] == "pause", calls + assert calls[1:-1], calls + assert set(calls[1:-1]) == {"get"}, calls else: assert calls == ["submit", "get", "pause"]