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:41:17 +00:00
parent adfa4602d5
commit e56b15b112

View File

@@ -1,35 +1,87 @@
import httpx from dataclasses import dataclass
import pytest
from fastapi.testclient import TestClient
from app.checker import CheckNetworkError, CheckTimeoutError, HttpOutcome
from app.config import Settings
from app.main import create_app
@pytest.mark.anyio @dataclass
async def test_crud_check_status_and_operations(client: httpx.AsyncClient) -> None: class FakeChecker:
created = await client.post("/monitors", json={"name": "Example", "url": "https://example.com/a?token=secret"}) result: object
assert created.status_code == 201
monitor_id = created.json()["id"]
assert created.json()["status"]["state"] == "unknown"
assert (await client.get("/monitors")).json()[0]["name"] == "Example"
changed = await client.patch(f"/monitors/{monitor_id}", json={"name": "Changed"}) async def check(self, url: str) -> HttpOutcome:
assert changed.status_code == 200 if isinstance(self.result, Exception):
assert changed.json()["name"] == "Changed" raise self.result
assert isinstance(self.result, HttpOutcome)
checked = await client.post(f"/monitors/{monitor_id}/check") return self.result
assert checked.status_code == 200
assert checked.json()["status"]["state"] == "up"
assert "token" not in checked.json()["url"]
assert (await client.get(f"/monitors/{monitor_id}/status")).json()["http_status"] == 204
assert (await client.get("/healthz")).json() == {"status": "ok"}
assert (await client.get("/readyz")).status_code == 200
assert (await client.delete(f"/monitors/{monitor_id}")).status_code == 204
missing = await client.get(f"/monitors/{monitor_id}")
assert missing.status_code == 404
assert missing.json()["error"]["code"] == "http_404"
@pytest.mark.anyio def client_with(result: object = HttpOutcome(204, 12.5, "https://example.com/")):
async def test_validation_error_has_contract_shape(client: httpx.AsyncClient) -> None: app = create_app(Settings())
response = await client.post("/monitors", json={"name": "", "url": "file:///etc/passwd"}) client = TestClient(app)
assert response.status_code == 422 client.__enter__()
assert response.json()["error"]["code"] == "validation_error" 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
return response.json()
def test_crud_and_operational_routes() -> None:
with client_with() as client:
assert client.get("/healthz").json() == {"status": "ok"}
assert client.get("/readyz").json() == {"status": "ok"}
item = create_monitor(client)
monitor_id = item["id"]
assert item["current_status"]["state"] == "unknown"
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:
with client_with(HttpOutcome(503, 8.0, "https://example.com/")) as client:
item = create_monitor(client)
result = client.post(f"/monitors/{item['id']}/check")
assert result.status_code == 200
assert result.json()["state"] == "down"
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:
for failure, expected_status, code in [
(CheckTimeoutError(50.0), 504, "check_timeout"),
(CheckNetworkError(20.0), 502, "network_error"),
]:
with client_with(failure) as client:
item = create_monitor(client)
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:
app = create_app(Settings(max_monitors=1))
with TestClient(app) as client:
create_monitor(client)
full = client.post("/monitors", json={"name": "other", "url": "https://example.org"})
assert full.status_code == 409
invalid = client.post("/monitors", json={"name": "", "url": "ftp://example.com"})
assert invalid.status_code == 422