Spaces:
Paused
Paused
Download tests/test_platform/test_foundation.py from whassan/SensorflowStudio: direct link, hf CLI and curl.
- Browser
- Download file 9.32 kB
-
https://huggingface.co/spaces/whassan/SensorflowStudio/resolve/main/tests/test_platform/test_foundation.py
- Command line
-
hf download hf://spaces/whassan/SensorflowStudio/tests/test_platform/test_foundation.py
-
curl -L -o test_foundation.py https://huggingface.co/spaces/whassan/SensorflowStudio/resolve/main/tests/test_platform/test_foundation.py
9.32 kB
| """Phase 1 platform foundation tests — metrics, container quality, compare, gates, evidence.""" | |
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| import pytest | |
| from sensorflow.platform.metrics_engine import ( | |
| aggregate_container_rows, | |
| container_quality_metrics, | |
| delta_metrics, | |
| precision_recall_f1, | |
| verification_rates, | |
| ) | |
| from sensorflow.platform.container_quality import profile_from_counts | |
| from sensorflow.platform.levels import AggregateLevel, EvaluationScope, summarize_scope | |
| from sensorflow.platform.gates import ( | |
| DEFAULT_GATE_CONFIG, | |
| evaluate_multi_gates, | |
| list_gate_defs, | |
| load_gate_config, | |
| ) | |
| from sensorflow.platform.evidence import build_evidence_package, export_evidence_package | |
| from sensorflow.platform.compare import compare_models | |
| from sensorflow.platform.entities import EvidencePackage, Provenance | |
| # ------------------------------------------------------------------ metrics | |
| def test_precision_recall_f1_basic(): | |
| out = precision_recall_f1(tp=8, fp=2, fn=2) | |
| assert out["precision"] == 0.8 | |
| assert out["recall"] == 0.8 | |
| assert out["f1"] == 0.8 | |
| def test_precision_recall_empty(): | |
| out = precision_recall_f1(0, 0, 0) | |
| assert out["precision"] is None | |
| assert out["recall"] is None | |
| assert out["f1"] is None | |
| def test_verification_rates(): | |
| v = verification_rates( | |
| n_objects=100, | |
| verified=40, | |
| reviewed=55, | |
| disputed=5, | |
| auto_accepted=30, | |
| hitl=15, | |
| ) | |
| assert v["verified_rate"] == 0.4 | |
| assert v["hitl_rate"] == 0.15 | |
| assert v["disputed_rate"] == 0.05 | |
| assert v["auto_accept_rate"] == 0.3 | |
| assert v["unverified"] == 60 | |
| def test_container_quality_metrics_bundle(): | |
| m = container_quality_metrics( | |
| tp=10, fp=5, fn=5, sum_iou=7.0, n_objects=20, | |
| verified=8, reviewed=12, hitl=4, anomalies=2, | |
| ) | |
| assert m["precision"] == pytest.approx(10 / 15, rel=1e-3) | |
| assert m["mean_iou"] == 0.7 | |
| assert m["verification"]["verified_rate"] == 0.4 | |
| assert m["anomaly_rate"] == 0.1 | |
| def test_aggregate_container_rows(): | |
| rows = [ | |
| {"tp": 5, "fp": 1, "fn": 1, "sum_iou": 4.0, "n_objects": 10, "verified": 3, "reviewed": 4}, | |
| {"tp": 5, "fp": 1, "fn": 1, "sum_iou": 3.5, "n_objects": 10, "verified": 5, "reviewed": 6}, | |
| ] | |
| agg = aggregate_container_rows(rows) | |
| assert agg["tp"] == 10 | |
| assert agg["verification"]["verified"] == 8 | |
| def test_delta_metrics(): | |
| deltas = delta_metrics( | |
| {"precision": 0.9, "recall": 0.8}, | |
| {"precision": 0.88, "recall": 0.85}, | |
| keys=["precision", "recall"], | |
| ) | |
| assert deltas[0]["delta"] == pytest.approx(-0.02) | |
| assert deltas[1]["delta"] == pytest.approx(0.05) | |
| def test_profile_from_counts(): | |
| p = profile_from_counts( | |
| container_id="c-1", tp=4, fp=1, fn=1, sum_iou=3.2, | |
| n_objects=10, verified=2, reviewed=5, hitl=3, | |
| ) | |
| assert p["container_id"] == "c-1" | |
| assert p["f1"] is not None | |
| assert p["verification"]["hitl"] == 3 | |
| # ------------------------------------------------------------------ levels | |
| def test_aggregate_ladder(): | |
| ladder = AggregateLevel.ladder() | |
| assert ladder[0] == AggregateLevel.FRAME | |
| assert ladder[-1] == AggregateLevel.POPULATION | |
| assert AggregateLevel.CONTAINER.parent() == AggregateLevel.DATASET | |
| assert AggregateLevel.FRAME.child() is None | |
| def test_evaluation_scope_summary(): | |
| scope = EvaluationScope( | |
| level=AggregateLevel.CONTAINER, | |
| run_id="run-1", | |
| mega_container_id=42, | |
| model_version="model-v1", | |
| ) | |
| s = summarize_scope(scope) | |
| assert s["backend"] == "megaeval" | |
| assert s["refs"]["mega_container_id"] == 42 | |
| # ------------------------------------------------------------------ gates | |
| def test_gate_defs_include_multi_gate_skeleton(tmp_path: Path): | |
| cfg_path = tmp_path / "gates.json" | |
| cfg = load_gate_config(cfg_path) | |
| assert cfg_path.exists() | |
| defs = list_gate_defs(cfg) | |
| types = {d.gate_type for d in defs} | |
| for required in ("scenario", "coverage", "regression", "safety", "release", "quality", "launch"): | |
| assert required in types | |
| def test_evaluate_multi_gates_skeleton(tmp_path: Path, monkeypatch): | |
| cfg_path = tmp_path / "gates.json" | |
| monkeypatch.setattr( | |
| "sensorflow.platform.gates.DEFAULT_GATE_CONFIG_PATH", cfg_path | |
| ) | |
| # rewrite load to use tmp | |
| from sensorflow.platform import gates as gates_mod | |
| monkeypatch.setattr(gates_mod, "DEFAULT_GATE_CONFIG_PATH", cfg_path) | |
| out = gates_mod.evaluate_multi_gates() | |
| assert out["summary"]["unwired_count"] >= 3 | |
| assert out["summary"]["release_ready"] is False | |
| types = [g["gate_type"] for g in out["gates"]] | |
| assert "scenario" in types and "safety" in types | |
| skeleton = [g for g in out["gates"] if g["gate_type"] == "safety"][0] | |
| assert skeleton["ready"] is False | |
| assert skeleton["passed"] is None | |
| def test_gate_config_thresholds_are_config_driven(): | |
| assert "map_3d" in DEFAULT_GATE_CONFIG["gates"]["quality"]["thresholds"] | |
| assert DEFAULT_GATE_CONFIG["gates"]["safety"]["ready"] is False | |
| # ------------------------------------------------------------------ evidence | |
| def test_evidence_package_stub(tmp_path: Path, monkeypatch): | |
| monkeypatch.setattr( | |
| "sensorflow.platform.evidence.EVIDENCE_DIR", tmp_path | |
| ) | |
| pkg = build_evidence_package(evaluation_id="eval-test") | |
| assert isinstance(pkg, EvidencePackage) | |
| assert pkg.evaluation_id == "eval-test" | |
| assert "model_versions" in pkg.placeholders or pkg.model_versions | |
| path = export_evidence_package(pkg, tmp_path / f"{pkg.package_id}.json") | |
| assert path.exists() | |
| raw = json.loads(path.read_text()) | |
| assert raw["evaluation_id"] == "eval-test" | |
| assert "gate_results" in raw | |
| assert "compute_usage" in raw | |
| assert "provenance" in raw | |
| # append-only: second export with same path gets a revision file | |
| path2 = export_evidence_package(pkg, path) | |
| assert path2 != path | |
| assert path2.exists() | |
| # ------------------------------------------------------------------ compare (unit, no mega store) | |
| def test_compare_models_requires_two_runs(): | |
| with pytest.raises(ValueError): | |
| compare_models(["only-one"]) | |
| class _FakeRun: | |
| def __init__(self, run_id, model_version, headline, status="published"): | |
| self.run_id = run_id | |
| self.model_version = model_version | |
| self.headline = headline | |
| self.status = status | |
| self.population_id = "pop-1" | |
| self.label_version = "labels-v1" | |
| class _FakeStore: | |
| def __init__(self, runs): | |
| self.runs = {r.run_id: r for r in runs} | |
| def artifacts(self, run_id): | |
| raise NotImplementedError | |
| def test_compare_models_matrix(monkeypatch): | |
| a = _FakeRun("run-a", "model-A", { | |
| "precision": 0.9, "recall": 0.8, "f1": 0.85, | |
| "mean_iou": 0.7, "safety_recall": 0.75, "anomaly_rate": 0.1, | |
| }) | |
| b = _FakeRun("run-b", "model-B", { | |
| "precision": 0.88, "recall": 0.82, "f1": 0.85, | |
| "mean_iou": 0.71, "safety_recall": 0.74, "anomaly_rate": 0.09, | |
| }) | |
| c = _FakeRun("run-c", "model-C", { | |
| "precision": 0.91, "recall": 0.79, "f1": 0.845, | |
| "mean_iou": 0.69, "safety_recall": 0.78, "anomaly_rate": 0.11, | |
| }) | |
| store = _FakeStore([a, b, c]) | |
| def fake_compare(store, cand, base, policy=None): | |
| return { | |
| "recommendation": "PROMOTE", | |
| "blockers": [], | |
| "headline_deltas": [], | |
| "per_class": [], | |
| "regressions": [], | |
| } | |
| monkeypatch.setattr("sensorflow.megaeval.analysis.compare_runs", fake_compare) | |
| out = compare_models( | |
| ["run-a", "run-b", "run-c"], | |
| baseline_run_id="run-a", | |
| store=store, | |
| ) | |
| assert len(out["models"]) == 3 | |
| assert len(out["pairwise"]) == 2 | |
| assert len(out["metric_matrix"]) >= 3 | |
| recall_row = next(r for r in out["metric_matrix"] if r["metric"] == "recall") | |
| assert recall_row["model-B"] == 0.82 | |
| assert recall_row["deltas_vs_baseline"]["model-B"] == pytest.approx(0.02) | |
| # ------------------------------------------------------------------ API smoke (optional FastAPI) | |
| def test_platform_router_mounts(): | |
| from fastapi.testclient import TestClient | |
| from sensorflow.platform.api import router | |
| from fastapi import FastAPI | |
| app = FastAPI() | |
| app.include_router(router) | |
| client = TestClient(app) | |
| levels = client.get("/api/evaluations/levels") | |
| assert levels.status_code == 200 | |
| body = levels.json() | |
| assert "population" in body["levels"] | |
| assert body["backends"]["container"] == "megaeval" | |
| gates = client.get("/api/gates") | |
| assert gates.status_code == 200 | |
| assert any(g["gate_type"] == "scenario" for g in gates.json()["gates"]) | |
| status = client.get("/api/gates/status") | |
| assert status.status_code == 200 | |
| assert status.json()["summary"]["release_ready"] is False | |
| evidence = client.post("/api/evaluations/evidence", json={ | |
| "evaluation_id": "api-eval-1", | |
| "persist": False, | |
| }) | |
| assert evidence.status_code == 200 | |
| assert evidence.json()["package"]["evaluation_id"] == "api-eval-1" | |
| bad = client.post("/api/models/compare", json={"run_ids": ["x"]}) | |
| assert bad.status_code == 422 or bad.status_code == 400 | |