Files
2026-07-27 15:16:01 +02:00

80 lines
2.4 KiB
Python

"""Exercises AiohttpFetcher against a real local HTTP server."""
from __future__ import annotations
from collections.abc import AsyncIterator
import aiohttp
import pytest
import pytest_asyncio
from aiohttp import web
from sticker_downloader.errors import FetchError
from sticker_downloader.fetcher import AiohttpFetcher, Fetcher
async def _handle(request: web.Request) -> web.Response:
status = int(request.match_info["status"])
if status == 200:
return web.Response(body=b"file-bytes", content_type="image/webp")
return web.Response(status=status, text="nope")
@pytest_asyncio.fixture
async def server() -> AsyncIterator[str]:
app = web.Application()
app.router.add_get("/{status}", _handle)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "127.0.0.1", 0)
await site.start()
port = runner.addresses[0][1]
try:
yield f"http://127.0.0.1:{port}"
finally:
await runner.cleanup()
@pytest_asyncio.fixture
async def session() -> AsyncIterator[aiohttp.ClientSession]:
async with aiohttp.ClientSession() as client:
yield client
async def test_returns_the_body_on_success(server: str, session) -> None:
fetcher = AiohttpFetcher(session)
assert await fetcher.fetch(f"{server}/200") == b"file-bytes"
@pytest.mark.parametrize("status", [404, 429, 500, 503])
async def test_raises_fetch_error_with_the_status(
server: str, session, status: int
) -> None:
fetcher = AiohttpFetcher(session)
with pytest.raises(FetchError) as excinfo:
await fetcher.fetch(f"{server}/{status}")
assert excinfo.value.status == status
assert str(status) in str(excinfo.value)
async def test_only_server_side_statuses_are_retriable(server: str, session) -> None:
fetcher = AiohttpFetcher(session)
with pytest.raises(FetchError) as not_found:
await fetcher.fetch(f"{server}/404")
with pytest.raises(FetchError) as rate_limited:
await fetcher.fetch(f"{server}/429")
assert not_found.value.retriable is False
assert rate_limited.value.retriable is True
async def test_connection_failures_surface_as_client_errors(session) -> None:
fetcher = AiohttpFetcher(session)
# Port 1 is reserved and refuses connections.
with pytest.raises(aiohttp.ClientError):
await fetcher.fetch("http://127.0.0.1:1/200")
def test_aiohttp_fetcher_satisfies_the_protocol(session) -> None:
assert isinstance(AiohttpFetcher(session), Fetcher)