Spaces:
Sleeping
Sleeping
| # Copyright (c) 2025-2026, RTE (https://www.rte-france.com) | |
| # This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. | |
| # SPDX-License-Identifier: MPL-2.0 | |
| """Tests for the new ConfigRequest fields + ``/api/models`` endpoint.""" | |
| from __future__ import annotations | |
| import pytest | |
| # expert_backend.main imports the recommenders package, whose __init__ | |
| # registers the concrete upstream model classes — skip in mock-only | |
| # environments (same convention as test_recommenders_registry.py). | |
| pytest.importorskip("expert_op4grid_recommender.models.base") | |
| fastapi_testclient = pytest.importorskip("fastapi.testclient") | |
| TestClient = fastapi_testclient.TestClient | |
| from expert_backend.main import ConfigRequest, app | |
| client = TestClient(app) | |
| # --------------------------------------------------------------------- | |
| # ConfigRequest schema | |
| # --------------------------------------------------------------------- | |
| def test_config_request_default_model_is_expert(): | |
| cr = ConfigRequest(network_path="/n", action_file_path="/a") | |
| assert cr.model == "expert" | |
| assert cr.compute_overflow_graph is True | |
| def test_config_request_accepts_custom_model(): | |
| cr = ConfigRequest( | |
| network_path="/n", action_file_path="/a", | |
| model="random", compute_overflow_graph=False, | |
| ) | |
| assert cr.model == "random" | |
| assert cr.compute_overflow_graph is False | |
| def test_config_request_roundtrips_through_json(): | |
| payload = { | |
| "network_path": "/n", "action_file_path": "/a", | |
| "model": "random_overflow", "compute_overflow_graph": True, | |
| } | |
| cr = ConfigRequest(**payload) | |
| dumped = cr.model_dump() | |
| assert dumped["model"] == "random_overflow" | |
| assert dumped["compute_overflow_graph"] is True | |
| # --------------------------------------------------------------------- | |
| # GET /api/models endpoint | |
| # --------------------------------------------------------------------- | |
| def test_models_endpoint_returns_200(): | |
| resp = client.get("/api/models") | |
| assert resp.status_code == 200 | |
| def test_models_endpoint_lists_canonical_three(): | |
| payload = client.get("/api/models").json() | |
| names = {m["name"] for m in payload["models"]} | |
| assert {"expert", "random", "random_overflow"}.issubset(names) | |
| def test_models_endpoint_marks_expert_default(): | |
| payload = client.get("/api/models").json() | |
| expert = next(m for m in payload["models"] if m["name"] == "expert") | |
| assert expert["is_default"] is True | |
| assert expert["requires_overflow_graph"] is True | |
| def test_models_endpoint_random_does_not_require_graph(): | |
| payload = client.get("/api/models").json() | |
| rnd = next(m for m in payload["models"] if m["name"] == "random") | |
| assert rnd["requires_overflow_graph"] is False | |
| def test_models_endpoint_random_overflow_requires_graph(): | |
| payload = client.get("/api/models").json() | |
| ro = next(m for m in payload["models"] if m["name"] == "random_overflow") | |
| assert ro["requires_overflow_graph"] is True | |
| def test_models_endpoint_random_has_minimal_params(): | |
| payload = client.get("/api/models").json() | |
| rnd = next(m for m in payload["models"] if m["name"] == "random") | |
| names = {p["name"] for p in rnd["params"]} | |
| assert names == {"n_prioritized_actions"} | |
| def test_models_endpoint_expert_has_legacy_knobs(): | |
| payload = client.get("/api/models").json() | |
| expert = next(m for m in payload["models"] if m["name"] == "expert") | |
| names = {p["name"] for p in expert["params"]} | |
| for required in ( | |
| "n_prioritized_actions", | |
| "min_line_reconnections", | |
| "min_close_coupling", | |
| "min_open_coupling", | |
| "min_line_disconnections", | |
| "min_pst", | |
| "min_load_shedding", | |
| "min_renewable_curtailment_actions", | |
| "ignore_reconnections", | |
| ): | |
| assert required in names, f"missing param {required!r}" | |
| def test_models_endpoint_param_shape(): | |
| payload = client.get("/api/models").json() | |
| for model in payload["models"]: | |
| for param in model["params"]: | |
| assert {"name", "label", "kind", "default"}.issubset(param) | |
| assert param["kind"] in {"int", "float", "bool"} | |