|
11 | 11 |
|
12 | 12 |
|
13 | 13 | def test_retry_three_times() -> None: |
14 | | - """Test retry_until().""" |
15 | | - ini = time() |
| 14 | + """retry_until retries until the callable succeeds.""" |
| 15 | + calls = 0 |
16 | 16 | value = 0 |
17 | 17 |
|
18 | 18 | def call_me_three_times() -> bool: |
19 | | - nonlocal value |
20 | | - sleep(0.3) # Sleep for 0.3 seconds to simulate work |
| 19 | + nonlocal value, calls |
| 20 | + calls += 1 |
| 21 | + sleep(0.3) # simulate work |
21 | 22 |
|
22 | 23 | if value == 2: |
23 | 24 | return True |
24 | 25 |
|
25 | 26 | value += 1 |
26 | 27 | return False |
27 | 28 |
|
28 | | - retry_until(call_me_three_times, 1) |
29 | | - |
30 | | - end = time() |
31 | | - |
32 | | - assert 0.9 <= (end - ini) <= 1.1 # Allow for small timing variations |
| 29 | + # Generous budget so all three calls fit even under load; assert on behavior |
| 30 | + # (call count + success), not wall-clock, to stay deterministic. |
| 31 | + assert retry_until(call_me_three_times, 5) is True |
| 32 | + assert calls == 3 |
33 | 33 |
|
34 | 34 |
|
35 | 35 | def test_function_times_out() -> None: |
36 | | - """Test time outs with retry_until().""" |
| 36 | + """retry_until raises WaitTimeout after exhausting its budget.""" |
37 | 37 | ini = time() |
| 38 | + calls = 0 |
38 | 39 |
|
39 | 40 | def never_true() -> bool: |
40 | | - sleep( |
41 | | - 0.1, |
42 | | - ) # Sleep for 0.1 seconds to simulate work (called ~10 times in 1 second) |
| 41 | + nonlocal calls |
| 42 | + calls += 1 |
| 43 | + sleep(0.1) # simulate work |
43 | 44 | return False |
44 | 45 |
|
45 | 46 | with pytest.raises(exc.WaitTimeout): |
46 | 47 | retry_until(never_true, 1) |
47 | 48 |
|
48 | | - end = time() |
49 | | - |
50 | | - assert 0.9 <= (end - ini) <= 1.1 # Allow for small timing variations |
| 49 | + # It retried for the full budget before timing out. The lower bound is |
| 50 | + # deterministic (retry_until only times out once elapsed >= the budget); |
| 51 | + # no fragile upper bound that load can blow past. |
| 52 | + assert (time() - ini) >= 0.9 |
| 53 | + assert calls > 1 |
51 | 54 |
|
52 | 55 |
|
53 | 56 | def test_function_times_out_no_raise() -> None: |
54 | | - """Tests retry_until() with exception raising disabled.""" |
| 57 | + """retry_until returns instead of raising when raises=False.""" |
55 | 58 | ini = time() |
| 59 | + calls = 0 |
56 | 60 |
|
57 | 61 | def never_true() -> bool: |
58 | | - sleep( |
59 | | - 0.1, |
60 | | - ) # Sleep for 0.1 seconds to simulate work (called ~10 times in 1 second) |
| 62 | + nonlocal calls |
| 63 | + calls += 1 |
| 64 | + sleep(0.1) # simulate work |
61 | 65 | return False |
62 | 66 |
|
63 | 67 | retry_until(never_true, 1, raises=False) |
64 | 68 |
|
65 | | - end = time() |
66 | | - assert 0.9 <= (end - ini) <= 1.1 # Allow for small timing variations |
| 69 | + assert (time() - ini) >= 0.9 |
| 70 | + assert calls > 1 |
67 | 71 |
|
68 | 72 |
|
69 | 73 | def test_function_times_out_no_raise_assert() -> None: |
70 | | - """Tests retry_until() with exception raising disabled, returning False.""" |
| 74 | + """retry_until returns False on timeout when raises=False.""" |
71 | 75 | ini = time() |
| 76 | + calls = 0 |
72 | 77 |
|
73 | 78 | def never_true() -> bool: |
74 | | - sleep( |
75 | | - 0.1, |
76 | | - ) # Sleep for 0.1 seconds to simulate work (called ~10 times in 1 second) |
| 79 | + nonlocal calls |
| 80 | + calls += 1 |
| 81 | + sleep(0.1) # simulate work |
77 | 82 | return False |
78 | 83 |
|
79 | 84 | assert not retry_until(never_true, 1, raises=False) |
80 | 85 |
|
81 | | - end = time() |
82 | | - assert 0.9 <= (end - ini) <= 1.1 # Allow for small timing variations |
| 86 | + assert (time() - ini) >= 0.9 |
| 87 | + assert calls > 1 |
83 | 88 |
|
84 | 89 |
|
85 | 90 | def test_retry_three_times_no_raise_assert() -> None: |
86 | | - """Tests retry_until() with exception raising disabled, with closure variable.""" |
87 | | - ini = time() |
| 91 | + """retry_until returns True on success even with raises=False.""" |
| 92 | + calls = 0 |
88 | 93 | value = 0 |
89 | 94 |
|
90 | 95 | def call_me_three_times() -> bool: |
91 | | - nonlocal value |
92 | | - sleep( |
93 | | - 0.3, |
94 | | - ) # Sleep for 0.3 seconds to simulate work (called 3 times in ~0.9 seconds) |
| 96 | + nonlocal value, calls |
| 97 | + calls += 1 |
| 98 | + sleep(0.3) # simulate work |
95 | 99 |
|
96 | 100 | if value == 2: |
97 | 101 | return True |
98 | 102 |
|
99 | 103 | value += 1 |
100 | 104 | return False |
101 | 105 |
|
102 | | - assert retry_until(call_me_three_times, 1, raises=False) |
103 | | - |
104 | | - end = time() |
105 | | - assert 0.9 <= (end - ini) <= 1.1 # Allow for small timing variations |
| 106 | + # Behavior-based, generous budget: deterministic even under load. |
| 107 | + assert retry_until(call_me_three_times, 5, raises=False) is True |
| 108 | + assert calls == 3 |
0 commit comments