diff --git a/tests/test_api.py b/tests/test_api.py index 7920e11..94332ff 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,32 +1,51 @@ -from uuid import uuid4 +from collections.abc import AsyncIterator -from fastapi.testclient import TestClient +import httpx +import pytest + +from app.checker import EndpointChecker, Fetcher, HopResponse +from app.config import Settings +from app.main import create_app +from app.security import ValidatedTarget -def create(client: TestClient, url: str = "https://example.com/health") -> dict[str, object]: - response = client.post("/v1/monitors", json={"name": "site", "url": url}) - assert response.status_code == 201 - return response.json() +class OkayFetcher(Fetcher): + async def fetch(self, target: ValidatedTarget, settings: Settings, remaining: float) -> HopResponse: + return HopResponse(204, None) -def test_crud_and_operational_routes(client: TestClient) -> None: - assert client.get("/healthz").json() == {"status": "ok"} - assert client.get("/readyz").json() == {"status": "ready"} - item = create(client) - monitor_id = item["id"] - assert item["current_status"]["state"] == "unknown" - assert len(client.get("/v1/monitors").json()) == 1 - updated = client.patch(f"/v1/monitors/{monitor_id}", json={"name": "new"}) - assert updated.status_code == 200 - assert updated.json()["name"] == "new" - assert client.get(f"/v1/monitors/{monitor_id}/status").json()["state"] == "unknown" - assert client.delete(f"/v1/monitors/{monitor_id}").status_code == 204 - assert client.get(f"/v1/monitors/{monitor_id}").status_code == 404 +async def public_resolver(host: str, port: int) -> list[tuple[object, ...]]: + return [(2, 1, 6, "", ("93.184.216.34", port))] -def test_validation_and_missing(client: TestClient) -> None: - assert client.post("/v1/monitors", json={"name": "", "url": "file:///tmp/x"}).status_code == 422 - missing = uuid4() - assert client.get(f"/v1/monitors/{missing}").json() == {"detail": "monitor not found"} - item = create(client) - assert client.patch(f"/v1/monitors/{item['id']}", json={}).status_code == 422 +@pytest.fixture +async def client() -> AsyncIterator[httpx.AsyncClient]: + settings = Settings(total_timeout_seconds=2, connect_timeout_seconds=1, read_timeout_seconds=1) + checker = EndpointChecker(settings, fetcher=OkayFetcher(), resolver=public_resolver) + app = create_app(settings=settings, checker=checker) + async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as value: + yield value + + +@pytest.mark.asyncio +async def test_crud_check_status_and_operations(client: httpx.AsyncClient) -> None: + assert (await client.get("/health")).json() == {"status": "ok"} + assert (await client.get("/ready")).json()["storage"] == "process-local-memory" + created = await client.post("/monitors", json={"name": "site", "url": "https://example.com/x?secret=yes"}) + assert created.status_code == 201 + monitor_id = created.json()["id"] + assert len((await client.get("/monitors")).json()) == 1 + checked = await client.post(f"/monitors/{monitor_id}/check") + assert checked.json()["status"]["state"] == "up" + assert checked.json()["applied"] is True + assert (await client.get(f"/monitors/{monitor_id}/status")).json()["http_status"] == 204 + updated = await client.put(f"/monitors/{monitor_id}", json={"name": "new", "url": "https://example.com/new"}) + assert updated.json()["current_status"] is None + assert (await client.delete(f"/monitors/{monitor_id}")).status_code == 204 + assert (await client.get(f"/monitors/{monitor_id}")).status_code == 404 + + +@pytest.mark.asyncio +async def test_validation_and_missing(client: httpx.AsyncClient) -> None: + assert (await client.post("/monitors", json={"name": "", "url": "ftp://x"})).status_code == 422 + assert (await client.get("/monitors/00000000-0000-0000-0000-000000000000")).status_code == 404