ModPilot / api /test_main.py
ThejasRao's picture
Deploy ModPilot Investigation Engine
7302343
Raw
History Blame Contribute Delete
4.37 kB
"""Tests for the engine FastAPI skeleton (F-0.5).
Covers: /health envelope, error handlers, HMAC permissive/strict modes,
correlation-id roundtrip.
"""
import hmac
import time
from collections.abc import Iterator
from hashlib import sha256
import pytest
from fastapi.testclient import TestClient
from api.config import Settings, get_settings
from api.errors import EngineError
from api.main import app
from api.middleware import HEADER_CORRELATION, HEADER_SIGNATURE, HEADER_TIMESTAMP
@pytest.fixture
def client() -> TestClient:
return TestClient(app)
@pytest.fixture
def prod_client(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestClient]:
"""Client with HMAC strictly enforced — production-like config."""
get_settings.cache_clear()
monkeypatch.setenv("ENV", "production")
monkeypatch.setenv("ENGINE_SHARED_SECRET", "test-secret")
try:
yield TestClient(app)
finally:
get_settings.cache_clear()
def test_health_returns_ok_envelope(client: TestClient) -> None:
r = client.get("/health")
assert r.status_code == 200
body = r.json()
assert body["ok"] is True
assert body["data"]["engine"] == "0.0.1"
assert body["data"]["model_reasoner"] == "gemini-2.5-pro"
assert body["data"]["model_summarizer"] == "gemini-2.5-flash"
def test_correlation_id_roundtrip_when_provided(client: TestClient) -> None:
cid = "test-correlation-12345"
r = client.get("/health", headers={HEADER_CORRELATION: cid})
assert r.headers[HEADER_CORRELATION] == cid
def test_correlation_id_generated_when_absent(client: TestClient) -> None:
r = client.get("/health")
assert HEADER_CORRELATION in r.headers
assert len(r.headers[HEADER_CORRELATION]) > 0
def test_hmac_permissive_in_dev(client: TestClient) -> None:
# Dev mode: no signature header required; request passes.
# /health is in the public path set anyway, but proves the middleware doesn't crash.
assert client.get("/health").status_code == 200
def test_hmac_strict_rejects_missing_signature(prod_client: TestClient) -> None:
# /health is still public — use a non-existent path to exercise middleware.
r = prod_client.post("/feedback", json={"foo": "bar"})
# 401 from HMAC middleware (UNAUTHORIZED envelope) takes precedence over 404.
assert r.status_code == 401
body = r.json()
assert body["ok"] is False
assert body["error"]["code"] == "UNAUTHORIZED"
assert body["error"]["retryable"] is False
def test_hmac_strict_accepts_valid_signature(prod_client: TestClient) -> None:
secret = "test-secret"
body = b'{"hello":"world"}'
timestamp = str(int(time.time()))
signature = hmac.new(
secret.encode("utf-8"),
f"{timestamp}.".encode() + body,
sha256,
).hexdigest()
r = prod_client.post(
"/feedback",
content=body,
headers={
HEADER_SIGNATURE: signature,
HEADER_TIMESTAMP: timestamp,
"content-type": "application/json",
},
)
# Signature passes; downstream 404 because the route doesn't exist yet.
assert r.status_code == 404
def test_hmac_strict_rejects_skewed_timestamp(prod_client: TestClient) -> None:
secret = "test-secret"
body = b"{}"
# 10 minutes in the future — past the 5-minute skew window.
timestamp = str(int(time.time()) + 600)
signature = hmac.new(
secret.encode("utf-8"),
f"{timestamp}.".encode() + body,
sha256,
).hexdigest()
r = prod_client.post(
"/feedback",
content=body,
headers={HEADER_SIGNATURE: signature, HEADER_TIMESTAMP: timestamp},
)
assert r.status_code == 401
assert "skew" in r.json()["error"]["message"]
def test_engine_error_renders_envelope(client: TestClient) -> None:
@app.get("/_test_rate_limited")
async def _boom() -> None:
raise EngineError("RATE_LIMITED", "test-only")
r = client.get("/_test_rate_limited")
assert r.status_code == 429
body = r.json()
assert body == {
"ok": False,
"error": {"code": "RATE_LIMITED", "message": "test-only", "retryable": True},
}
def test_settings_dev_mode_default() -> None:
get_settings.cache_clear()
s = Settings(_env_file=None)
assert s.is_dev is True
assert s.hmac_enforced is False
get_settings.cache_clear()