тесты и фкисы клиента
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
63
tests/test_glitchtip_client.py
Normal file
63
tests/test_glitchtip_client.py
Normal 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()
|
||||||
Reference in New Issue
Block a user