Skip to content

Commit b74bc52

Browse files
authored
Fixing flaky tests - part 2 (#3838)
1 parent 92ea9e2 commit b74bc52

File tree

10 files changed

+804
-496
lines changed

10 files changed

+804
-496
lines changed

dev_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pytest==8.3.4 ; platform_python_implementation == "PyPy"
1212
pytest-asyncio>=0.23.0
1313
pytest-asyncio==1.1.0 ; platform_python_implementation == "PyPy"
1414
pytest-cov
15+
coverage<7.11.1
1516
pytest-cov==6.0.0 ; platform_python_implementation == "PyPy"
1617
coverage==7.6.12 ; platform_python_implementation == "PyPy"
1718
pytest-profiling==1.8.1

redis/multidb/client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,13 @@ def _on_circuit_state_change_callback(
301301
)
302302

303303
def close(self):
304-
self.command_executor.active_database.client.close()
304+
"""
305+
Closes the client and all its resources.
306+
"""
307+
if self._bg_scheduler:
308+
self._bg_scheduler.stop()
309+
if self.command_executor.active_database:
310+
self.command_executor.active_database.client.close()
305311

306312

307313
def _half_open_circuit(circuit: CircuitBreaker):

tests/helpers.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import logging
2+
from time import sleep
3+
from typing import Callable
4+
5+
6+
def wait_for_condition(
7+
predicate: Callable[[], bool],
8+
timeout: float = 0.2,
9+
check_interval: float = 0.01,
10+
error_message: str = "Timeout waiting for condition",
11+
) -> None:
12+
"""
13+
Poll a condition until it becomes True or timeout is reached.
14+
15+
Args:
16+
predicate: A callable that returns True when the condition is met
17+
timeout: Maximum time to wait in seconds (default: 0.2s = 20 * 0.01s)
18+
check_interval: Time to sleep between checks in seconds (default: 0.01s)
19+
error_message: Error message to raise if timeout occurs
20+
21+
Raises:
22+
AssertionError: If the condition is not met within the timeout period
23+
24+
Example:
25+
# Wait for circuit breaker to open
26+
wait_for_condition(
27+
lambda: cb2.state == CBState.OPEN,
28+
timeout=0.2,
29+
error_message="Timeout waiting for cb2 to open"
30+
)
31+
32+
# Wait for failover strategy to select a specific database
33+
wait_for_condition(
34+
lambda: client.command_executor.active_database is mock_db,
35+
timeout=0.2,
36+
error_message="Timeout waiting for active database to change"
37+
)
38+
"""
39+
max_retries = int(timeout / check_interval)
40+
41+
for attempt in range(max_retries):
42+
if predicate():
43+
logging.debug(f"Condition met after {attempt} attempts")
44+
return
45+
sleep(check_interval)
46+
47+
raise AssertionError(error_message)

tests/test_asyncio/helpers.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import asyncio
2+
import logging
3+
from typing import Callable
4+
5+
6+
async def wait_for_condition(
7+
predicate: Callable[[], bool],
8+
timeout: float = 0.2,
9+
check_interval: float = 0.01,
10+
error_message: str = "Timeout waiting for condition",
11+
) -> None:
12+
"""
13+
Poll a condition until it becomes True or timeout is reached.
14+
15+
Args:
16+
predicate: A callable that returns True when the condition is met
17+
timeout: Maximum time to wait in seconds (default: 0.2s = 20 * 0.01s)
18+
check_interval: Time to sleep between checks in seconds (default: 0.01s)
19+
error_message: Error message to raise if timeout occurs
20+
21+
Raises:
22+
AssertionError: If the condition is not met within the timeout period
23+
24+
Example:
25+
# Wait for circuit breaker to open
26+
await wait_for_condition(
27+
lambda: cb2.state == CBState.OPEN,
28+
timeout=0.2,
29+
error_message="Timeout waiting for cb2 to open"
30+
)
31+
32+
# Wait for failover strategy to select a specific database
33+
await wait_for_condition(
34+
lambda: client.command_executor.active_database is mock_db,
35+
timeout=0.2,
36+
error_message="Timeout waiting for active database to change"
37+
)
38+
"""
39+
max_retries = int(timeout / check_interval)
40+
41+
for attempt in range(max_retries):
42+
if predicate():
43+
logging.debug(f"Condition met after {attempt} attempts")
44+
return
45+
await asyncio.sleep(check_interval)
46+
47+
raise AssertionError(error_message)

0 commit comments

Comments
 (0)