From 24e313627986749d5a2727d01d57294567f4504d Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Wed, 21 Jan 2026 09:31:54 +0100 Subject: [PATCH] test: Add pytest-rerunfailures for integration tests Add `pytest-rerunfailures` as a dev dependency and configure all integration tests to rerun up to 3 times on failure automatically. This helps handle occasional platform-related instabilities without manual test reruns. Uses `pytest_collection_modifyitems` hook to apply the flaky marker to all integration tests, avoiding the need to decorate each test individually. Co-Authored-By: Claude Opus 4.5 --- pyproject.toml | 1 + tests/integration/conftest.py | 10 ++++++++++ uv.lock | 15 +++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 265b7e73..d6b474a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,7 @@ dev = [ "pytest-asyncio<2.0.0", "pytest-cov<8.0.0", "pytest-httpserver<2.0.0", + "pytest-rerunfailures<17.0.0", "pytest-timeout<3.0.0", "pytest-xdist<4.0.0", "pytest<9.0.0", diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 42d13367..4f016ad6 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -16,6 +16,9 @@ from collections.abc import Callable from pathlib import Path +# Rerun all integration tests up to 3 times on failure, as the platform can be unstable. +_INTEGRATION_TEST_RERUNS = 3 + _TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN' _API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL' @@ -89,3 +92,10 @@ def _isolate_test_environment(prepare_test_env: Callable[[], None]) -> None: prepare_test_env: Fixture to prepare the environment before each test. """ prepare_test_env() + + +def pytest_collection_modifyitems(items: list[pytest.Item]) -> None: + """Add flaky marker with reruns to all integration tests.""" + flaky_marker = pytest.mark.flaky(reruns=_INTEGRATION_TEST_RERUNS) + for item in items: + item.add_marker(flaky_marker) diff --git a/uv.lock b/uv.lock index 49aa39c5..ddb8aa98 100644 --- a/uv.lock +++ b/uv.lock @@ -60,6 +60,7 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-httpserver" }, + { name = "pytest-rerunfailures" }, { name = "pytest-timeout" }, { name = "pytest-xdist" }, { name = "ruff" }, @@ -99,6 +100,7 @@ dev = [ { name = "pytest-asyncio", specifier = "<2.0.0" }, { name = "pytest-cov", specifier = "<8.0.0" }, { name = "pytest-httpserver", specifier = "<2.0.0" }, + { name = "pytest-rerunfailures", specifier = "<17.0.0" }, { name = "pytest-timeout", specifier = "<3.0.0" }, { name = "pytest-xdist", specifier = "<4.0.0" }, { name = "ruff", specifier = "~=0.14.0" }, @@ -2010,6 +2012,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0d/d2/dfc2f25f3905921c2743c300a48d9494d29032f1389fc142e718d6978fb2/pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9", size = 21000, upload-time = "2025-04-10T08:17:13.906Z" }, ] +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, +] + [[package]] name = "pytest-timeout" version = "2.4.0"