Files
app/backend/tests/flow/test_watchdog.py
T
stroblmeandClaude Opus 5 640654bd66 Rename the import package app to fluksio
A wheel whose top-level module is `app` collides with anything else in a
user's venv, so the package that is about to be published takes the name
it is published under. Only the Python package moves; the repo, the
Docker WORKDIR and the compose project keep theirs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 21:48:05 +02:00

69 lines
2.0 KiB
Python

"""Loop-lag watchdog: what the deep health check reads."""
from fastapi.testclient import TestClient
from fluksio.flow.events import EventBus
from fluksio.flow.watchdog import DEGRADED_STRIKES, LoopWatchdog
from fluksio.main import app
def test_a_responsive_loop_stays_healthy():
watchdog = LoopWatchdog()
for _ in range(10):
watchdog._record(0.002)
assert not watchdog.degraded
assert watchdog.snapshot()["max_60s"] == 2.0
def test_sustained_lag_marks_the_engine_degraded():
watchdog = LoopWatchdog()
for _ in range(20):
watchdog._record(1.0)
assert watchdog.degraded
def test_a_blocked_loop_is_announced_once_it_keeps_happening():
events = []
bus = EventBus()
bus.publish = events.append # type: ignore[method-assign]
watchdog = LoopWatchdog(bus)
for _ in range(DEGRADED_STRIKES - 1):
watchdog._record(6.0)
assert events == []
watchdog._record(6.0)
assert [e["type"] for e in events] == ["engine_degraded"]
# A recovered loop resets the count, so the next stall is announced again.
watchdog._record(0.001)
for _ in range(DEGRADED_STRIKES):
watchdog._record(6.0)
assert len(events) == 2
def test_health_reports_503_once_the_loop_is_wedged():
"""The point of the deep check: unhealthy without the process being dead."""
watchdog = LoopWatchdog()
app.state.watchdog = watchdog
# No lifespan here, so there is no controller either — the endpoint has to
# cope with a half-built app rather than assume the engine is up.
client = TestClient(app)
try:
assert client.get("/api/v1/utils/health/").status_code == 200
for _ in range(20):
watchdog._record(1.0)
response = client.get("/api/v1/utils/health/")
assert response.status_code == 503
body = response.json()
assert body["status"] == "degraded"
assert body["problems"] == ["event loop lagging"]
finally:
del app.state.watchdog