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"}, ] def test_parse_next_cursor_extracts_only_cursor_value() -> None: link_header = ( '; rel="next"; results="true"; cursor="..."' ) cursor = GlitchTipClient._parse_next_cursor(link_header) assert cursor == "cD0yMDI2LTAzLTI2KzIxJTNBNTklM0EyMS4xNjkxNDklMkIwMCUzQTAw&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()