тесты и фкисы клиента
Some checks failed
CI / Lint (ruff + mypy) (push) Failing after 36s
CI / Run tests (push) Has been skipped
CI / Docker build test (push) Successful in 21s

This commit is contained in:
2026-03-30 17:02:03 +07:00
parent 8c25c17382
commit 03aa7805d1
2 changed files with 104 additions and 3 deletions

View File

@@ -52,6 +52,36 @@ class GlitchTipClient:
return results return results
async def _get_paginated_with_fallbacks(
self,
path: str,
param_candidates: list[dict],
*,
fallback_filter=None,
) -> list:
last_error: Exception | None = None
for index, candidate in enumerate(param_candidates):
try:
results = await self._get_paginated(path, params=candidate)
if fallback_filter is not None:
results = [item for item in results if fallback_filter(item)]
return results
except httpx.HTTPStatusError as exc:
last_error = exc
if exc.response.status_code != 422 or index == len(param_candidates) - 1:
raise
logger.warning(
"GlitchTip rejected issue query params for %s with 422; "
"retrying with a simpler request",
path,
)
if last_error is not None:
raise last_error
return []
@staticmethod @staticmethod
def _parse_next_cursor(link_header: str) -> str | None: def _parse_next_cursor(link_header: str) -> str | None:
for part in link_header.split(","): for part in link_header.split(","):
@@ -72,9 +102,17 @@ class GlitchTipClient:
async def list_issues( async def list_issues(
self, project_slug: str, query: str = "is:unresolved", sort: str = "date" self, project_slug: str, query: str = "is:unresolved", sort: str = "date"
) -> list[dict]: ) -> list[dict]:
return await self._get_paginated( path = f"/api/0/projects/{settings.glitchtip_org_slug}/{project_slug}/issues/"
f"/api/0/projects/{settings.glitchtip_org_slug}/{project_slug}/issues/", return await self._get_paginated_with_fallbacks(
params={"query": query, "sort": sort}, path,
[
{"query": query, "sort": sort},
{"query": query},
{},
],
fallback_filter=(
lambda issue: (issue.get("status") or "unresolved").lower() == "unresolved"
),
) )
async def get_issue(self, issue_id: int) -> dict: async def get_issue(self, issue_id: int) -> dict:

View File

@@ -0,0 +1,63 @@
import httpx
import pytest
from glitchup_bot.glitchtip_client.client import GlitchTipClient
@pytest.mark.asyncio
async def test_list_issues_retries_without_query_params_on_422() -> None:
attempts: list[dict[str, str | int]] = []
def handler(request: httpx.Request) -> httpx.Response:
attempts.append(dict(request.url.params))
if len(attempts) < 3:
return httpx.Response(422, request=request, json={"detail": "bad query"})
return httpx.Response(
200,
request=request,
json=[
{"id": "1", "status": "unresolved", "title": "keep"},
{"id": "2", "status": "resolved", "title": "drop"},
],
headers={"link": ""},
)
client = GlitchTipClient()
client._client = httpx.AsyncClient(
base_url=client.base_url,
headers=client.headers,
transport=httpx.MockTransport(handler),
)
try:
issues = await client.list_issues("backend-production")
finally:
await client.close()
assert [issue["id"] for issue in issues] == ["1"]
assert attempts == [
{"query": "is:unresolved", "sort": "date", "limit": "100"},
{"query": "is:unresolved", "limit": "100"},
{"limit": "100"},
]
@pytest.mark.asyncio
async def test_list_issues_preserves_non_422_errors() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(500, request=request, json={"detail": "server error"})
client = GlitchTipClient()
client._client = httpx.AsyncClient(
base_url=client.base_url,
headers=client.headers,
transport=httpx.MockTransport(handler),
)
try:
with pytest.raises(httpx.HTTPStatusError):
await client.list_issues("backend-production")
finally:
await client.close()