#!/usr/bin/env python3 """HTTP smoke test for the v2 demo stack. Run while uvicorn is on :8000.""" from __future__ import annotations import json import sys import urllib.error import urllib.request BASE = "http://127.0.0.1:8000" TENANT = "demo-smoke" PASSWORD = "demo-smoke-pass" def req( method: str, path: str, *, body: dict | None = None, token: str | None = None ) -> tuple[int, bytes]: headers = {"Content-Type": "application/json"} if token: headers["Authorization"] = f"Bearer {token}" data = json.dumps(body).encode() if body is not None else None request = urllib.request.Request( f"{BASE}{path}", data=data, headers=headers, method=method ) try: with urllib.request.urlopen(request, timeout=120) as resp: return resp.status, resp.read() except urllib.error.HTTPError as exc: return exc.code, exc.read() def main() -> int: print("1. Health") code, raw = req("GET", "/health") if code != 200: print(f" FAIL health {code}: {raw[:200]}") return 1 health = json.loads(raw) print( f" OK status={health.get('status')} reference={health.get('reference_faiss_count')}" ) print("2. UI") code, _ = req("GET", "/v2.html") if code != 200: print(f" FAIL v2.html {code}") return 1 print(" OK /v2.html served") print("3. Register / login") code, raw = req( "POST", "/auth/register", body={"tenant_id": TENANT, "password": PASSWORD} ) if code not in (201, 409): print(f" FAIL register {code}: {raw[:200]}") return 1 code, raw = req( "POST", "/auth/login", body={"tenant_id": TENANT, "password": PASSWORD} ) if code != 200: print(f" FAIL login {code}: {raw[:200]}") return 1 token = json.loads(raw)["access_token"] print(" OK JWT received") print("4. Auth me") code, raw = req("GET", "/auth/me", token=token) if code != 200 or json.loads(raw).get("tenant_id") != TENANT: print(f" FAIL /auth/me {code}") return 1 print(" OK") print("5. Schema") code, raw = req("GET", "/api/schema", token=token) if code != 200: print(f" FAIL schema {code}: {raw[:200]}") return 1 sections = json.loads(raw).get("sections") or [] print(f" OK {len(sections)} sections") print("6. Reference status") code, raw = req("GET", "/api/upload/reference/status", token=token) ref = json.loads(raw) if code != 200: print(f" FAIL reference status {code}") return 1 print( f" OK chunks={ref.get('reference_chunk_count')} ready={ref.get('ready_for_generation')}" ) if not ref.get("ready_for_generation"): print(" SKIP preview — no reference docs (upload past reports for full test)") return 0 print("7. Preview") payload = { "raw_notes": "E2: roof tile slipped on south slope", "property_type": "semi-detached house", "tenure": "freehold", "interference_level": "minimum", } code, raw = req("POST", "/api/report/preview", body=payload, token=token) if code != 200: print(f" FAIL preview {code}: {raw[:300]}") return 1 preview = json.loads(raw) print( f" OK mapped={preview.get('sections_mapped')} review={preview.get('sections_needing_review')}" ) print("All smoke checks passed.") return 0 if __name__ == "__main__": sys.exit(main())