#!/usr/bin/env python3 """Run one conditional pytest gate and reject empty or silently skipped evidence.""" from __future__ import annotations import argparse import importlib.util import json import os import platform import subprocess import sys from datetime import datetime, timezone from pathlib import Path from xml.etree import ElementTree GATES = { "model-download-runtime": "tests/conditional/test_model_download_runtime.py", "external-evaluation": "tests/conditional/test_external_evaluation_runtime.py", "network-services": "tests/conditional/test_network_services.py", "operator-ui": "tests/conditional/test_operator_ui.py", "cuda-runtime": "tests/conditional/test_cuda_runtime.py", "bitsandbytes-runtime": "tests/conditional/test_cuda_runtime.py", "jetson-runtime": "tests/conditional/test_jetson_runtime.py", "mps-runtime": "tests/conditional/test_mps_runtime.py", "mlx-runtime": "tests/conditional/test_mlx_runtime.py", "remote-execution": "tests/conditional/test_remote_runtime.py", } JETSON_RELEASE = Path("/etc/nv_tegra_release") def missing_prerequisites(gate: str) -> list[str]: missing: list[str] = [] if gate in {"cuda-runtime", "bitsandbytes-runtime", "jetson-runtime", "mps-runtime"}: import torch if gate.startswith(("cuda", "bitsandbytes", "jetson")): if not torch.cuda.is_available(): missing.append("a CUDA-capable PyTorch runtime") elif not (hasattr(torch.backends, "mps") and torch.backends.mps.is_available()): missing.append("an available Apple MPS backend") if gate == "bitsandbytes-runtime" and importlib.util.find_spec("bitsandbytes") is None: missing.append("bitsandbytes") if gate == "jetson-runtime": if platform.machine().lower() not in {"aarch64", "arm64"}: missing.append("an ARM64 host") if not JETSON_RELEASE.is_file(): missing.append("a Jetson L4T runtime") if gate == "mlx-runtime": for module in ("mlx", "mlx_lm"): if importlib.util.find_spec(module) is None: missing.append(module) if gate == "remote-execution": for variable in ( "OBLITERATUS_REMOTE_HOST", "OBLITERATUS_REMOTE_USER", "OBLITERATUS_REMOTE_KEY", "OBLITERATUS_REMOTE_KNOWN_HOSTS", ): if not os.environ.get(variable): missing.append(variable) return missing def counts(junit_path: Path) -> dict[str, int]: root = ElementTree.parse(junit_path).getroot() suites = [root] if root.tag == "testsuite" else list(root.findall("testsuite")) return { key: sum(int(suite.attrib.get(key, "0")) for suite in suites) for key in ("tests", "failures", "errors", "skipped") } def write_report(path: Path, gate: str, status: str, **extra: object) -> None: path.parent.mkdir(parents=True, exist_ok=True) payload = { "schema_version": 1, "gate": gate, "status": status, "generated_at": datetime.now(timezone.utc).isoformat(), "git_sha": os.environ.get("GITHUB_SHA", "local"), **extra, } path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n") def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("gate", choices=sorted(GATES)) parser.add_argument("--evidence-dir", type=Path, default=Path("conditional-evidence")) parser.add_argument("--allow-missing", action="store_true") args = parser.parse_args() report = args.evidence_dir / f"{args.gate}.json" junit = args.evidence_dir / f"{args.gate}.xml" missing = missing_prerequisites(args.gate) if missing: message = "Missing prerequisites: " + ", ".join(missing) write_report(report, args.gate, "not_run", reason=message) print(message, file=sys.stderr) return 0 if args.allow_missing else 2 command = [ sys.executable, "-m", "pytest", GATES[args.gate], "--no-cov", "-q", f"--junitxml={junit}", ] result = subprocess.run(command, check=False) if not junit.is_file(): write_report(report, args.gate, "failed", exit_code=result.returncode, reason="no JUnit") return result.returncode or 1 result_counts = counts(junit) passed = ( result.returncode == 0 and result_counts["tests"] > 0 and result_counts["failures"] == 0 and result_counts["errors"] == 0 and result_counts["skipped"] == 0 ) write_report( report, args.gate, "passed" if passed else "failed", exit_code=result.returncode, counts=result_counts, ) if not passed: print(f"conditional gate did not produce unskipped green evidence: {result_counts}") return 0 if passed else 1 if __name__ == "__main__": raise SystemExit(main())