decomposer: generate deliverable files for Define the service contract and project architecture for the FastAPI endpoint monitoring service.; Implement the typed monitor CRUD API and concurrency-safe in-memory state according to the service design.; Implement secure on-demand endpoint checks with status updates, latency measurement, robust error handling, and redacted structured logs.; Add operational API endpoints and environment-driven runtime configuration to the monitoring service.; Create automated tests for the monitoring service.; Package the service with Docker and developer documentation.; Validate the complete project.
Some checks failed
ci / validate (push) Has been cancelled

This commit is contained in:
2026-08-09 15:44:11 +00:00
parent 80ecd4bec4
commit 3500509b42

View File

@@ -1,87 +1,77 @@
from dataclasses import dataclass import asyncio
from collections.abc import Awaitable, Callable
from fastapi.testclient import TestClient import httpx
from app.checker import CheckNetworkError, CheckTimeoutError, HttpOutcome
from app.config import Settings
from app.main import create_app
@dataclass async def create(client: httpx.AsyncClient, name: str = "site") -> httpx.Response:
class FakeChecker: return await client.post(
result: object "/monitors", json={"name": name, "url": "https://example.com/path?secret=value"}
)
async def check(self, url: str) -> HttpOutcome:
if isinstance(self.result, Exception):
raise self.result
assert isinstance(self.result, HttpOutcome)
return self.result
def client_with(result: object = HttpOutcome(204, 12.5, "https://example.com/")): async def test_crud_and_error_semantics(client: httpx.AsyncClient) -> None:
app = create_app(Settings()) response = await create(client)
client = TestClient(app)
client.__enter__()
app.state.checker = FakeChecker(result)
return client
def create_monitor(client: TestClient, url: str = "https://example.com/") -> dict:
response = client.post("/monitors", json={"name": "site", "url": url})
assert response.status_code == 201 assert response.status_code == 201
return response.json() monitor = response.json()
assert monitor["current_status"]["state"] == "never_checked"
response = await client.patch(
f"/monitors/{monitor['id']}", json={"name": "renamed", "expected_status": 204}
)
assert response.status_code == 200
assert response.json()["name"] == "renamed"
assert response.json()["expected_status"] == 204
assert len((await client.get("/monitors")).json()) == 1
assert (await client.delete(f"/monitors/{monitor['id']}")).status_code == 204
response = await client.get(f"/monitors/{monitor['id']}")
assert response.status_code == 404
assert response.json() == {"error": {"code": "not_found", "message": "monitor not found"}}
def test_crud_and_operational_routes() -> None: async def test_typed_validation_is_redacted(client: httpx.AsyncClient) -> None:
with client_with() as client: response = await client.post(
assert client.get("/healthz").json() == {"status": "ok"} "/monitors", json={"name": "", "url": "not a URL", "expected_status": 99}
assert client.get("/readyz").json() == {"status": "ok"} )
item = create_monitor(client) assert response.status_code == 422
monitor_id = item["id"] assert response.json()["error"]["code"] == "invalid_request"
assert item["current_status"]["state"] == "unknown" assert "not a URL" not in response.text
assert len(client.get("/monitors").json()) == 1
updated = client.put(f"/monitors/{monitor_id}", json={
"name": "new", "url": "https://example.org/"
})
assert updated.status_code == 200
assert updated.json()["name"] == "new"
assert client.delete(f"/monitors/{monitor_id}").status_code == 204
missing = client.get(f"/monitors/{monitor_id}")
assert missing.status_code == 404
assert missing.json()["error"]["code"] == "monitor_not_found"
def test_check_updates_status() -> None: async def test_store_survives_concurrent_api_writes(client: httpx.AsyncClient) -> None:
with client_with(HttpOutcome(503, 8.0, "https://example.com/")) as client: responses = await asyncio.gather(*(create(client, f"site-{n}") for n in range(100)))
item = create_monitor(client) ids = {response.json()["id"] for response in responses}
result = client.post(f"/monitors/{item['id']}/check") assert len(ids) == 100
assert result.status_code == 200 listed = (await client.get("/monitors")).json()
assert result.json()["state"] == "down" assert {item["id"] for item in listed} == ids
status = client.get(f"/monitors/{item['id']}/status").json()
assert status["status_code"] == 503
assert status["latency_ms"] == 8.0
def test_timeout_and_network_errors_are_mapped_and_published() -> None: async def test_check_updates_current_status(client: httpx.AsyncClient) -> None:
for failure, expected_status, code in [ monitor = (await create(client)).json()
(CheckTimeoutError(50.0), 504, "check_timeout"), checked = await client.post(f"/monitors/{monitor['id']}/check")
(CheckNetworkError(20.0), 502, "network_error"), assert checked.status_code == 200
]: assert checked.json()["state"] == "up"
with client_with(failure) as client: status = await client.get(f"/monitors/{monitor['id']}/status")
item = create_monitor(client) assert status.json() == checked.json()
response = client.post(f"/monitors/{item['id']}/check")
assert response.status_code == expected_status
assert response.json()["error"]["code"] == code
current = client.get(f"/monitors/{item['id']}/status").json()
assert current["state"] == "error"
assert current["error_code"] == code
def test_validation_and_capacity() -> None: async def test_operational_routes(client: httpx.AsyncClient) -> None:
app = create_app(Settings(max_monitors=1)) assert (await client.get("/health/live")).json() == {"status": "ok"}
with TestClient(app) as client: assert (await client.get("/health/ready")).json()["storage"] == "process-local-memory"
create_monitor(client)
full = client.post("/monitors", json={"name": "other", "url": "https://example.org"})
assert full.status_code == 409 async def test_redirect_is_revalidated(
invalid = client.post("/monitors", json={"name": "", "url": "ftp://example.com"}) client_factory: Callable[[httpx.AsyncBaseTransport], Awaitable[httpx.AsyncClient]],
assert invalid.status_code == 422 ) -> None:
async def handler(request: httpx.Request) -> httpx.Response:
if request.url.host == "example.com":
return httpx.Response(302, headers={"location": "http://127.0.0.1/admin"})
raise AssertionError("blocked redirect must not reach transport")
client = await client_factory(httpx.MockTransport(handler))
async with client:
monitor = (await create(client)).json()
result = await client.post(f"/monitors/{monitor['id']}/check")
assert result.json()["state"] == "blocked"
assert result.json()["observed_status"] == 302