From 6b3a5c5be78ed7f0d88300f74a089285cdd429b8 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 12 May 2026 21:09:29 +0200 Subject: [PATCH] Fix flaky FileTrigger/FileDeleteTrigger tests by awaiting the task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `test_task_file_trigger` and `test_file_delete_trigger` waited `asyncio.sleep(0.5)` after `p.touch()` and then asserted on the trigger's effect (task.done() / file gone). The trigger has to wake from its poll-interval sleep, run `is_file()`, run `stat()`, (for the delete variant) run `unlink()`, log, and yield. With anyio's thread- pool-backed file ops, 0.5s isn't always enough on slow runners — the Pendulum2 ARM job repeatedly hits the race in `test_file_delete_trigger` ("Found file" is logged but unlink hasn't returned by the time the assertion runs). Switch to `await asyncio.wait_for(task, timeout=5.0)` so the assertion can't race the trigger's detect → yield cycle. Once the task is done, the trigger has completed all its work (including unlink for the delete trigger), so the file-existence assertion is deterministic. Also drop the `asyncio.get_event_loop().stop()` cleanup line. It was protecting against the pending task left behind by the fixed-sleep pattern; with `wait_for`, there's no pending task and pytest-asyncio's own teardown handles loop lifecycle. --- .../tests/unit/standard/triggers/test_file.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/providers/standard/tests/unit/standard/triggers/test_file.py b/providers/standard/tests/unit/standard/triggers/test_file.py index 2d5a52eaf151f..793f0aeb62861 100644 --- a/providers/standard/tests/unit/standard/triggers/test_file.py +++ b/providers/standard/tests/unit/standard/triggers/test_file.py @@ -60,12 +60,11 @@ async def test_task_file_trigger(self, tmp_path): p.touch() - await asyncio.sleep(0.5) + # Await the task directly so the assertion can't race the trigger's + # detect → yield cycle on slow runners (ARM, Pendulum2 special job). + await asyncio.wait_for(task, timeout=5.0) assert task.done() is True - # Prevents error when task is destroyed while in "pending" state - asyncio.get_event_loop().stop() - @pytest.mark.skipif(not AIRFLOW_V_3_0_PLUS, reason="Skip on Airflow < 3.0") class TestFileDeleteTrigger: @@ -101,8 +100,9 @@ async def test_file_delete_trigger(self, tmp_path): p.touch() - await asyncio.sleep(0.5) + # Await the task directly so the assertion can't race the trigger's + # detect → unlink → yield cycle on slow runners (ARM, Pendulum2 + # special job). The trigger only yields after `await filepath.unlink()` + # returns, so once the task is done, the file is guaranteed gone. + await asyncio.wait_for(task, timeout=5.0) assert await anyio.Path(p).exists() is False - - # Prevents error when task is destroyed while in "pending" state - asyncio.get_event_loop().stop()