File size: 3,804 Bytes
a115eaf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
Smoke coverage for the read-only /v1/analysis/* endpoints (analysis_api.py).

These need at least one aggregatable sweep under SPOOKY_BENCHMARKS_DIR
(default <repo>/results/sweeps). That tree isn't committed, so every test
skips cleanly when it's absent rather than failing on a fresh checkout / CI.
"""

import pytest
from fastapi.testclient import TestClient

from api import app
from analysis_api import _sweep_dir_map


def _first_sweep_id():
    ids = list(_sweep_dir_map().keys())
    if not ids:
        pytest.skip("no sweeps under SPOOKY_BENCHMARKS_DIR")
    # newest-first, matching the /sweeps ordering
    with TestClient(app) as client:
        return client.get("/v1/analysis/sweeps").json()["sweeps"][0]["sweep_id"]


def test_list_sweeps_shape():
    with TestClient(app) as client:
        body = client.get("/v1/analysis/sweeps").json()
    assert "sweeps" in body and body["sweep_count"] == len(body["sweeps"])
    for entry in body["sweeps"]:
        assert entry["sweep_id"]
        assert set(entry) >= {"solvers", "grid_sizes", "n_completed", "git_commit"}


def test_summary_and_recommend_agree_on_solvers():
    sweep_id = _first_sweep_id()
    with TestClient(app) as client:
        summary = client.get(f"/v1/analysis/sweeps/{sweep_id}/summary")
        assert summary.status_code == 200, summary.text
        assert isinstance(summary.json()["statistical_tests"], list)

        rec = client.get(f"/v1/analysis/sweeps/{sweep_id}/recommend")
        assert rec.status_code == 200, rec.text
        body = rec.json()
        assert body["solvers"], "recommend returned no solvers for the whole sweep"
        # sorted best-first: success rate descending
        rates = [s["success_rate"] for s in body["solvers"]]
        assert rates == sorted(rates, reverse=True)
        assert body["verdict"]


def test_plots_return_plotly_json():
    sweep_id = _first_sweep_id()
    with TestClient(app) as client:
        for name in ("scaling", "success_rate", "variable_reduction"):
            res = client.get(f"/v1/analysis/sweeps/{sweep_id}/plots/{name}")
            assert res.status_code == 200, (name, res.text)
            assert "data" in res.json()
        assert (
            client.get(f"/v1/analysis/sweeps/{sweep_id}/plots/bogus").status_code == 404
        )


def test_by_instance_and_filtered_plot():
    sweep_id = _first_sweep_id()
    with TestClient(app) as client:
        grids = client.get("/v1/analysis/sweeps").json()["sweeps"][0]["grid_sizes"]
        assert grids, "sweep has no grid sizes"
        grid = grids[0]

        rows = client.get(
            f"/v1/analysis/sweeps/{sweep_id}/by-instance?grid_size={grid}"
        )
        assert rows.status_code == 200, rows.text
        body = rows.json()
        assert body["row_count"] == len(body["rows"]) > 0
        for row in body["rows"]:
            assert row["grid_size"] == grid
            assert 0.0 <= row["success_rate"] <= 1.0
            assert isinstance(row["failure_causes"], dict)

        # a filterable plot honours grid_size; scaling ignores it (still 200)
        assert (
            client.get(
                f"/v1/analysis/sweeps/{sweep_id}/plots/success_rate?grid_size={grid}"
            ).status_code
            == 200
        )
        assert (
            client.get(
                f"/v1/analysis/sweeps/{sweep_id}/plots/scaling?grid_size={grid}"
            ).status_code
            == 200
        )
        assert (
            client.get(
                f"/v1/analysis/sweeps/{sweep_id}/by-instance?grid_size=999x999"
            ).status_code
            == 404
        )


def test_unknown_sweep_404():
    with TestClient(app) as client:
        assert (
            client.get("/v1/analysis/sweeps/does_not_exist/summary").status_code == 404
        )