Skip to content

Commit 2a39d88

Browse files
author
rodrigo.nogueira
committed
Refactor get_flaky_threshold into rerun_adjusted_threshold fixture
- Converted get_flaky_threshold function to a pytest fixture using indirect parametrization - Renamed to rerun_adjusted_threshold for clarity - Updated RST docstring with usage examples and rerun count logic - Added proper type annotations (tuple[float, float]) for mypy compliance - Updated test_imports.py and test_client_middleware_digest_auth.py to use new fixture - Improved code readability by splitting long assertion lines - Restored macOS timing observation comment (40-50ms)
1 parent defe900 commit 2a39d88

3 files changed

Lines changed: 40 additions & 39 deletions

File tree

aiohttp/pytest_plugin.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,22 @@ def __call__(
6464
) -> Awaitable[RawTestServer]: ...
6565

6666

67-
def get_flaky_threshold(
68-
request: pytest.FixtureRequest,
69-
base: float,
70-
increment: float,
71-
) -> float:
72-
"""Calculate dynamic threshold for flaky tests based on rerun count.
73-
74-
When using `@pytest.mark.flaky(reruns=N)`:
75-
- execution_count is 1-based (1 for first run, 2 for first rerun, etc.)
76-
- With reruns=3, the test runs up to 4 times (1 initial + 3 reruns)
77-
- Returns base threshold on first run, incrementing by `increment` per rerun
78-
79-
Example with reruns=3, base=20ms, increment=30ms:
80-
Run 1: 20ms, Rerun 1: 50ms, Rerun 2: 80ms, Rerun 3: 110ms
67+
@pytest.fixture
68+
def rerun_adjusted_threshold(request: pytest.FixtureRequest) -> float:
69+
"""Calculate dynamic threshold based on rerun count (via indirect parametrization).
70+
71+
Returns ``base + (rerun_count * increment)``.
72+
The ``rerun_count`` is determined from ``pytest-rerunfailures`` (0 for initial run,
73+
1 for first rerun, etc.).
74+
75+
Usage::
76+
77+
@pytest.mark.flaky(reruns=3)
78+
@pytest.mark.parametrize("rerun_adjusted_threshold", [(20, 30)], indirect=True)
79+
def test_timing(rerun_adjusted_threshold: float) -> None: ...
8180
"""
81+
param: tuple[float, float] = request.param
82+
base, increment = param
8283
execution_count: int = getattr(request.node, "execution_count", 0)
8384
rerun_count = max(0, execution_count - 1)
8485
return base + (rerun_count * increment)

tests/test_client_middleware_digest_auth.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
)
2525
from aiohttp.client_reqrep import ClientResponse
2626
from aiohttp.payload import BytesIOPayload
27-
from aiohttp.pytest_plugin import AiohttpServer, get_flaky_threshold
27+
from aiohttp.pytest_plugin import AiohttpServer
2828
from aiohttp.web import Application, Request, Response
2929

3030

@@ -1331,27 +1331,28 @@ async def handler(request: Request) -> Response:
13311331
assert auth_algorithms[0] == "MD5-sess" # Not "MD5-SESS"
13321332

13331333

1334+
_REGEX_TIME_THRESHOLD = (0.02, 0.03) # (base=20ms, increment=30ms)
1335+
1336+
13341337
@pytest.mark.flaky(reruns=3)
1335-
def test_regex_performance(request: pytest.FixtureRequest) -> None:
1338+
@pytest.mark.parametrize(
1339+
"rerun_adjusted_threshold", [_REGEX_TIME_THRESHOLD], indirect=True
1340+
)
1341+
def test_regex_performance(rerun_adjusted_threshold: float) -> None:
13361342
"""Test that the regex pattern doesn't suffer from ReDoS issues.
13371343
13381344
Threshold starts at 20ms and increases on each rerun for CI variability.
13391345
"""
1340-
REGEX_TIME_THRESHOLD_DEFAULT = 0.02 # 20ms
1341-
REGEX_TIME_INCREMENT_PER_RERUN = 0.03 # 30ms
1342-
# CI/platform variability (e.g., macOS runners ~40-50ms observed)
1343-
threshold_ms = get_flaky_threshold(
1344-
request, REGEX_TIME_THRESHOLD_DEFAULT, REGEX_TIME_INCREMENT_PER_RERUN
1345-
)
1346-
13471346
value = "0" * 54773 + "\\0=a"
13481347

13491348
start = time.perf_counter()
13501349
matches = _HEADER_PAIRS_PATTERN.findall(value)
13511350
elapsed = time.perf_counter() - start
13521351

1353-
assert (
1354-
elapsed < threshold_ms
1355-
), f"Regex took {elapsed * 1000:.1f}ms, expected <{threshold_ms * 1000:.0f}ms - potential ReDoS issue"
1352+
# Relaxed for CI/platform variability (e.g., macOS runners ~40-50ms observed)
1353+
assert elapsed < rerun_adjusted_threshold, (
1354+
f"Regex took {elapsed * 1000:.1f}ms, "
1355+
f"expected <{rerun_adjusted_threshold * 1000:.0f}ms - potential ReDoS issue"
1356+
)
13561357

13571358
assert not matches

tests/test_imports.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
import pytest
77

8-
from aiohttp.pytest_plugin import get_flaky_threshold
9-
108

119
def test___all__(pytester: pytest.Pytester) -> None:
1210
"""See https://github.com/aio-libs/aiohttp/issues/6197"""
@@ -33,16 +31,26 @@ def test_web___all__(pytester: pytest.Pytester) -> None:
3331
_IMPORT_TIME_THRESHOLD_PY312 = 300
3432
_IMPORT_TIME_THRESHOLD_DEFAULT = 200
3533
_IMPORT_TIME_INCREMENT_PER_RERUN = 50
34+
_IMPORT_TIME_THRESHOLD = (
35+
(_IMPORT_TIME_THRESHOLD_PY312, _IMPORT_TIME_INCREMENT_PER_RERUN)
36+
if sys.version_info >= (3, 12)
37+
else (_IMPORT_TIME_THRESHOLD_DEFAULT, _IMPORT_TIME_INCREMENT_PER_RERUN)
38+
)
3639

3740

3841
@pytest.mark.internal
3942
@pytest.mark.dev_mode
4043
@pytest.mark.flaky(reruns=3)
44+
@pytest.mark.parametrize(
45+
"rerun_adjusted_threshold", [_IMPORT_TIME_THRESHOLD], indirect=True
46+
)
4147
@pytest.mark.skipif(
4248
not sys.platform.startswith("linux") or platform.python_implementation() == "PyPy",
4349
reason="Timing is more reliable on Linux",
4450
)
45-
def test_import_time(request: pytest.FixtureRequest, pytester: pytest.Pytester) -> None:
51+
def test_import_time(
52+
rerun_adjusted_threshold: float, pytester: pytest.Pytester
53+
) -> None:
4654
"""Check that importing aiohttp doesn't take too long.
4755
4856
Obviously, the time may vary on different machines and may need to be adjusted
@@ -52,15 +60,6 @@ def test_import_time(request: pytest.FixtureRequest, pytester: pytest.Pytester)
5260
Threshold increases by _IMPORT_TIME_INCREMENT_PER_RERUN ms on each rerun
5361
to account for CI variability.
5462
"""
55-
base_threshold = (
56-
_IMPORT_TIME_THRESHOLD_PY312
57-
if sys.version_info >= (3, 12)
58-
else _IMPORT_TIME_THRESHOLD_DEFAULT
59-
)
60-
expected_time = get_flaky_threshold(
61-
request, base_threshold, _IMPORT_TIME_INCREMENT_PER_RERUN
62-
)
63-
6463
root = Path(__file__).parent.parent
6564
old_path = os.environ.get("PYTHONPATH")
6665
os.environ["PYTHONPATH"] = os.pathsep.join([str(root)] + sys.path)
@@ -76,4 +75,4 @@ def test_import_time(request: pytest.FixtureRequest, pytester: pytest.Pytester)
7675
else:
7776
os.environ["PYTHONPATH"] = old_path
7877

79-
assert runtime_ms < expected_time
78+
assert runtime_ms < rerun_adjusted_threshold

0 commit comments

Comments
 (0)