Skip to content

Fix flaky FileTrigger/FileDeleteTrigger tests by awaiting the task#66825

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/file-trigger-test-race
May 17, 2026
Merged

Fix flaky FileTrigger/FileDeleteTrigger tests by awaiting the task#66825
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/file-trigger-test-race

Conversation

@potiuk
Copy link
Copy Markdown
Member

@potiuk potiuk commented May 12, 2026

Summary

test_task_file_trigger and test_file_delete_trigger in providers/standard/tests/unit/standard/triggers/test_file.py waited a fixed asyncio.sleep(0.5) after p.touch() and then asserted on the trigger's effect. On the Pendulum2 ARM scheduled job (failing run) the test_file_delete_trigger race fires: captured stdout shows Found file … but the unlink hasn't returned by the time the assertion runs, so await anyio.Path(p).exists() is False fails with assert True is False.

The trigger has to wake from its poke_interval=0.2 sleep, run is_file(), stat(), unlink(), log, and yield — all anyio thread-pool-backed file ops. 0.5s isn't always enough on slow runners.

Fix

Switch to await asyncio.wait_for(task, timeout=5.0) so the assertion can't race the trigger's detect → (unlink) → yield cycle. Once the task is done, the trigger has completed all its work, so the file-existence assertion (for the delete variant) and task.done() is True (for the wait variant) are deterministic.

Also drop the trailing asyncio.get_event_loop().stop() cleanup line. It was a workaround for 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.

Test plan

  • Local: uv run --project providers/standard pytest providers/standard/tests/unit/standard/triggers/test_file.py -xvs (both tests pass)
  • CI: Pendulum2 ARM scheduled job becomes deterministic

related: #61616 (the anyio conversion that made the unlink path async)


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 4.7)

Generated-by: Claude Code (Opus 4.7) following the guidelines

`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.
@potiuk potiuk force-pushed the fix/file-trigger-test-race branch from e509262 to 6b3a5c5 Compare May 16, 2026 10:55
@potiuk potiuk marked this pull request as draft May 17, 2026 12:57
@potiuk potiuk marked this pull request as ready for review May 17, 2026 12:59
@potiuk potiuk merged commit d4e2215 into apache:main May 17, 2026
174 of 176 checks passed
@potiuk potiuk deleted the fix/file-trigger-test-race branch May 17, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants