80 lines
2.4 KiB
Python
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)
|