# tests/test_operator_machine_endpoints.py from tests.conftest import wire_operator_auth def test_machine_endpoints_not_blocked_by_gate(client, db_session, monkeypatch): """With the gate ON and no cookie, the LAN-only watcher endpoints must reach their handlers (the gate must never silently break heartbeats). A handler may return 422 for an empty body — that still proves the gate let it through. Note: /emitters/report uses a minimal valid body to avoid triggering the app's validation_exception_handler (which calls await request.body() — a known deadlock in Starlette 0.27 TestClient when the body is already consumed). The gate behaviour is identical regardless of body validity. """ wire_operator_auth(monkeypatch, db_session, enabled=True) r = client.post("/api/series3/heartbeat", json={}, follow_redirects=False) assert r.status_code != 401 # gate would 401 an unauth /api/* route assert r.status_code != 303 r = client.post("/api/series4/heartbeat", json={}, follow_redirects=False) assert r.status_code not in (401, 303) # /emitters/report is a sync endpoint with required Pydantic fields; supply a # valid body so the validation_exception_handler (which awaits request.body()) # is never triggered — that handler deadlocks the Starlette 0.27 TestClient. valid_report = { "unit": "TEST001", "unit_type": "series3", "timestamp": "2024-01-01T00:00:00Z", "file": "test.evt", "status": "OK", } r = client.post("/emitters/report", json=valid_report, follow_redirects=False) assert r.status_code != 303 # gate would 303 an unauth HTML route def test_static_assets_exempt(client, db_session, monkeypatch): wire_operator_auth(monkeypatch, db_session, enabled=True) # /sw.js and /manifest.json are PWA assets clients fetch pre-login. assert client.get("/sw.js", follow_redirects=False).status_code in (200, 404) assert client.get("/sw.js", follow_redirects=False).status_code != 303