Co-Study4Grid / expert_backend /tests /test_models_api.py
github-actions[bot]
Deploy 7688ef1
13d4e44
Raw
History Blame Contribute Delete
4.15 kB
# 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"}