#!/usr/bin/env python3 """Local-only smoke test for the dry-run OpenVINO router classifier. This script uses only synthetic fixture messages. It assumes router_classifier.py is already running on localhost and never installs/enables a persistent service. """ from __future__ import annotations import argparse import json import sys import time import urllib.error import urllib.request from pathlib import Path from typing import Any DEFAULT_BASE_URL = "http://127.0.0.1:18819" BUSY_FILE = Path("/sys/class/accel/accel0/device/npu_busy_time_us") FIXTURE = Path(__file__).resolve().parent / "fixtures" / "atlas_hermes_messages.jsonl" def npu_busy_time_us() -> int | None: try: return int(BUSY_FILE.read_text().strip()) except Exception: return None def get_json(url: str, timeout_s: float) -> dict[str, Any]: with urllib.request.urlopen(url, timeout=timeout_s) as response: # noqa: S310 - localhost smoke URL return json.loads(response.read().decode("utf-8")) def post_json(url: str, payload: dict[str, Any], timeout_s: float) -> dict[str, Any]: request = urllib.request.Request( url, data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST", ) with urllib.request.urlopen(request, timeout=timeout_s) as response: # noqa: S310 - localhost smoke URL return json.loads(response.read().decode("utf-8")) def load_fixture(limit: int) -> list[dict[str, Any]]: rows = [json.loads(line) for line in FIXTURE.read_text().splitlines() if line.strip()] return rows[:limit] def assert_expected(result: dict[str, Any], expected: dict[str, Any]) -> list[str]: failures: list[str] = [] labels = result.get("labels", {}) for key, value in expected.items(): actual_label = labels.get(key, {}) actual_value = actual_label.get("value") if actual_value != value: failures.append(f"{result.get('id')}: {key} expected {value!r}, got {actual_value!r}") return failures def main() -> int: parser = argparse.ArgumentParser(description="Smoke-test a running localhost router classifier") parser.add_argument("--base-url", default=DEFAULT_BASE_URL) parser.add_argument("--timeout-s", type=float, default=30.0) parser.add_argument("--limit", type=int, default=10) args = parser.parse_args() if not args.base_url.startswith("http://127.0.0.1:") and not args.base_url.startswith("http://localhost:"): raise SystemExit("refusing non-local base URL; this smoke is localhost-only") before = npu_busy_time_us() started = time.perf_counter() try: health = get_json(f"{args.base_url.rstrip('/')}/healthz", args.timeout_s) labels = get_json(f"{args.base_url.rstrip('/')}/v1/labels", args.timeout_s) rows = load_fixture(args.limit) results = [] failures: list[str] = [] for row in rows: result = post_json( f"{args.base_url.rstrip('/')}/v1/classify", {"id": row["id"], "text": row["text"], "options": {"include_evidence": False, "dry_run": True}}, args.timeout_s, ) results.append(result) failures.extend(assert_expected(result, row.get("expected", {}))) after = npu_busy_time_us() except urllib.error.URLError as exc: raise SystemExit(f"smoke failed: {exc}") from exc response_npu_delta = sum((r.get("npu_busy_delta_us") or 0) for r in results) outer_sysfs_delta = None if before is None or after is None else after - before npu_proven = response_npu_delta > 0 and (outer_sysfs_delta is None or outer_sysfs_delta > 0) summary = { "ok": not failures, "service": health.get("service"), "mode": health.get("mode"), "model": health.get("model"), "label_count": len(labels.get("prototype_ids", [])), "fixture_count": len(results), "duration_ms": round((time.perf_counter() - started) * 1000, 3), "response_npu_busy_delta_us": response_npu_delta, "outer_sysfs_npu_busy_delta_us": outer_sysfs_delta, "npu_proven": npu_proven, "failures": failures, } print(json.dumps(summary, indent=2, sort_keys=True)) return 0 if not failures and npu_proven else 1 if __name__ == "__main__": raise SystemExit(main())