refactor tests
Publish container image / Build and push (push) Successful in 32s

This commit is contained in:
2026-07-26 23:49:40 +02:00
parent 5ef10d28fe
commit ce9f1e3d20
32 changed files with 1546 additions and 1923 deletions
+76 -82
View File
@@ -25,6 +25,17 @@ async def gitea_client(handler: Handler, *, retries: int = 3) -> AsyncGenerator[
await client.close()
@pytest.fixture
def recorded_backoffs(monkeypatch: pytest.MonkeyPatch) -> list[int]:
backoffs: list[int] = []
async def record_backoff(delay: int) -> None:
backoffs.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", record_backoff)
return backoffs
async def test_sends_authenticated_json_request_contract() -> None:
requests: list[httpx.Request] = []
@@ -221,19 +232,17 @@ async def test_pagination_stops_only_after_a_short_page(
@pytest.mark.parametrize("status", [400, 401, 403, 404, 422])
async def test_nonretryable_status_fails_once(status: int, monkeypatch: pytest.MonkeyPatch) -> None:
async def test_nonretryable_status_fails_once(
status: int,
recorded_backoffs: list[int],
) -> None:
attempts = 0
sleeps: list[int] = []
async def handler(_request: httpx.Request) -> httpx.Response:
nonlocal attempts
attempts += 1
return httpx.Response(status)
async def sleep(delay: int) -> None:
sleeps.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
async with gitea_client(handler) as client:
with pytest.raises(
GiteaError,
@@ -242,104 +251,89 @@ async def test_nonretryable_status_fails_once(status: int, monkeypatch: pytest.M
await client.default_branch("org", "repo")
assert attempts == 1
assert sleeps == []
assert recorded_backoffs == []
@pytest.mark.parametrize("status", [429, 500, 502, 503, 504])
async def test_retryable_status_recovers_after_backoff(
status: int, monkeypatch: pytest.MonkeyPatch
@pytest.mark.parametrize(
("status", "failures", "expected_backoffs"),
[
(429, 1, [1]),
(500, 1, [1]),
(502, 1, [1]),
(503, 1, [1]),
(504, 1, [1]),
pytest.param(None, 2, [1, 2], id="transport"),
],
)
async def test_retryable_failure_recovers_after_exponential_backoff(
status: int | None,
failures: int,
expected_backoffs: list[int],
recorded_backoffs: list[int],
) -> None:
attempts = 0
sleeps: list[int] = []
async def handler(_request: httpx.Request) -> httpx.Response:
async def handler(request: httpx.Request) -> httpx.Response:
nonlocal attempts
attempts += 1
if attempts == 1:
if attempts <= failures:
if status is None:
raise httpx.ConnectError("connection refused", request=request)
return httpx.Response(status)
return httpx.Response(200, json={"default_branch": "main"})
async def sleep(delay: int) -> None:
sleeps.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
async with gitea_client(handler) as client:
assert await client.default_branch("org", "repo") == "main"
assert attempts == 2
assert sleeps == [1]
assert attempts == failures + 1
assert recorded_backoffs == expected_backoffs
async def test_retryable_status_exhaustion_uses_exponential_backoff(
monkeypatch: pytest.MonkeyPatch,
@pytest.mark.parametrize(
("status", "retries", "expected_message", "expected_cause", "expected_backoffs"),
[
pytest.param(
503,
3,
"Gitea remained unavailable for GET /repos/org/repo",
None,
[1, 2],
id="status",
),
pytest.param(
None,
2,
"Gitea request failed: GET /repos/org/repo",
httpx.ConnectError,
[1],
id="transport",
),
],
)
async def test_retry_exhaustion_reports_failure(
status: int | None,
retries: int,
expected_message: str,
expected_cause: type[BaseException] | None,
expected_backoffs: list[int],
recorded_backoffs: list[int],
) -> None:
attempts = 0
sleeps: list[int] = []
async def handler(_request: httpx.Request) -> httpx.Response:
nonlocal attempts
attempts += 1
return httpx.Response(503)
async def sleep(delay: int) -> None:
sleeps.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
async with gitea_client(handler) as client:
with pytest.raises(
GiteaError,
match="Gitea remained unavailable for GET /repos/org/repo",
):
await client.default_branch("org", "repo")
assert attempts == 3
assert sleeps == [1, 2]
async def test_transport_failure_retries_and_recovers(monkeypatch: pytest.MonkeyPatch) -> None:
attempts = 0
sleeps: list[int] = []
async def handler(request: httpx.Request) -> httpx.Response:
nonlocal attempts
attempts += 1
if attempts < 3:
if status is None:
raise httpx.ConnectError("connection refused", request=request)
return httpx.Response(200, json={"default_branch": "main"})
return httpx.Response(status)
async def sleep(delay: int) -> None:
sleeps.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
async with gitea_client(handler) as client:
assert await client.default_branch("org", "repo") == "main"
assert attempts == 3
assert sleeps == [1, 2]
async def test_transport_failure_exhaustion_preserves_cause(
monkeypatch: pytest.MonkeyPatch,
) -> None:
attempts = 0
sleeps: list[int] = []
async def handler(request: httpx.Request) -> httpx.Response:
nonlocal attempts
attempts += 1
raise httpx.ConnectError("connection refused", request=request)
async def sleep(delay: int) -> None:
sleeps.append(delay)
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
async with gitea_client(handler, retries=2) as client:
with pytest.raises(
GiteaError,
match="Gitea request failed: GET /repos/org/repo",
) as raised:
async with gitea_client(handler, retries=retries) as client:
with pytest.raises(GiteaError, match=expected_message) as raised:
await client.default_branch("org", "repo")
assert isinstance(raised.value.__cause__, httpx.ConnectError)
assert attempts == 2
assert sleeps == [1]
if expected_cause is None:
assert raised.value.__cause__ is None
else:
assert isinstance(raised.value.__cause__, expected_cause)
assert attempts == retries
assert recorded_backoffs == expected_backoffs