Skip to content

Commit 979fe6a

Browse files
authored
deflake: add flaky marker and tweak timeouts to address flaky poll (#9373)
## 📝 Summary Addresses the flaky test seen in commit 76cc73b. The test is prone to race conditions, and a bit of local tweaking seems to indicate the following timeouts are stable
1 parent c68d8df commit 979fe6a

1 file changed

Lines changed: 40 additions & 5 deletions

File tree

tests/_utils/test_file_watcher.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,44 @@
44
import asyncio
55
import os
66
import shutil
7+
import warnings
78
from pathlib import Path
89
from tempfile import NamedTemporaryFile
10+
from typing import TYPE_CHECKING
911
from unittest.mock import patch
1012

1113
import pytest
1214

15+
if TYPE_CHECKING:
16+
from collections.abc import Callable
17+
1318
from marimo._dependencies.dependencies import DependencyManager
1419
from marimo._utils import async_path
1520
from marimo._utils.file_watcher import FileWatcherManager, PollingFileWatcher
1621

1722

23+
async def _wait_for(
24+
predicate: Callable[[], bool],
25+
*,
26+
timeout: float = 0.5,
27+
interval: float = 0.05,
28+
) -> None:
29+
loop = asyncio.get_event_loop()
30+
deadline = loop.time() + timeout
31+
while loop.time() < deadline:
32+
if predicate():
33+
return
34+
await asyncio.sleep(interval)
35+
# Surface a timeout so reruns/flakes leave a breadcrumb instead of
36+
# failing silently at the next assert with a misleading count.
37+
warnings.warn(
38+
f"_wait_for timed out after {timeout}s waiting on "
39+
f"{getattr(predicate, '__name__', repr(predicate))}",
40+
stacklevel=2,
41+
)
42+
43+
44+
@pytest.mark.flaky(reruns=3)
1845
async def test_polling_file_watcher() -> None:
1946
with NamedTemporaryFile(delete=False) as tmp_file:
2047
tmp_path = Path(tmp_file.name)
@@ -37,7 +64,7 @@ async def test_callback(path: Path):
3764
f.write("modification")
3865

3966
# Wait for the watcher to detect the change
40-
await asyncio.sleep(0.2)
67+
await _wait_for(lambda: len(callback_calls) == 1)
4168

4269
# Stop / cleanup
4370
watcher.stop()
@@ -48,6 +75,7 @@ async def test_callback(path: Path):
4875
assert callback_calls[0] == tmp_path
4976

5077

78+
@pytest.mark.flaky(reruns=3)
5179
async def test_file_watcher_manager() -> None:
5280
# Create two temporary files
5381
with (
@@ -90,7 +118,9 @@ async def callback3(path: Path) -> None:
90118
f.write("modification1")
91119

92120
# Wait for callbacks
93-
await asyncio.sleep(0.2)
121+
await _wait_for(
122+
lambda: len(callback1_calls) == 1 and len(callback2_calls) == 1
123+
)
94124

95125
# Both callbacks should be called for file1
96126
assert len(callback1_calls) == 1
@@ -102,12 +132,16 @@ async def callback3(path: Path) -> None:
102132
# Remove one callback from file1
103133
manager.remove_callback(tmp_path1, callback1)
104134

135+
# Space writes so the second mtime is distinguishable from the first
136+
# on filesystems with coarse mtime granularity (e.g. HFS+).
137+
await asyncio.sleep(0.05)
138+
105139
# Modify file1 again
106140
with open(tmp_path1, "w") as f: # noqa: ASYNC230
107141
f.write("modification2")
108142

109143
# Wait for callbacks
110-
await asyncio.sleep(0.2)
144+
await _wait_for(lambda: len(callback2_calls) == 2)
111145

112146
# Only callback2 should be called again
113147
assert len(callback1_calls) == 1 # unchanged
@@ -119,7 +153,7 @@ async def callback3(path: Path) -> None:
119153
f.write("modification3")
120154

121155
# Wait for callbacks
122-
await asyncio.sleep(0.2)
156+
await _wait_for(lambda: len(callback3_calls) == 1)
123157

124158
# callback3 should be called for file2
125159
assert len(callback1_calls) == 1
@@ -137,7 +171,8 @@ async def callback3(path: Path) -> None:
137171
with open(tmp_path2, "w") as f: # noqa: ASYNC230
138172
f.write("modification4")
139173

140-
# Wait for potential callbacks
174+
# Wait for potential callbacks (negative assertion — keep a fixed
175+
# budget since there's nothing to poll on).
141176
await asyncio.sleep(0.2)
142177

143178
# No new calls should happen

0 commit comments

Comments
 (0)