Co-Study4Grid / expert_backend /tests /test_diff_switches.py
github-actions[bot]
Deploy 7688ef1
13d4e44
Raw
History Blame Contribute Delete
2.64 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.
# If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
# you can obtain one at http://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
"""Unit tests for the vectorised DiagramMixin._diff_switches (QW11).
The old implementation looped over ~85 k switches doing two `.loc` lookups
each; the vectorised version aligns the two `open` columns on the shared index
and compares in NumPy. These tests lock the semantics the old loop had:
only switches present in BOTH grids are considered, a change is reported as
`from_open` (contingency) → `to_open` (action), and unchanged / absent
switches are omitted.
"""
import pandas as pd
from expert_backend.services.recommender_service import RecommenderService
class _FakeNetwork:
def __init__(self, switches_df):
self._df = switches_df
def get_switches(self):
return self._df
def _switches(open_by_id):
return pd.DataFrame({"open": list(open_by_id.values())}, index=list(open_by_id))
def test_none_action_snapshot_returns_empty():
assert RecommenderService._diff_switches(None, _FakeNetwork(_switches({}))) == {}
def test_detects_open_and_close_transitions():
action = _switches({"SW_A": True, "SW_B": False, "SW_C": True})
cont = _FakeNetwork(_switches({"SW_A": False, "SW_B": True, "SW_C": True}))
result = RecommenderService._diff_switches(action, cont)
# SW_A: closed→open, SW_B: open→closed, SW_C: unchanged (omitted).
assert result == {
"SW_A": {"from_open": False, "to_open": True},
"SW_B": {"from_open": True, "to_open": False},
}
def test_switches_absent_from_contingency_are_skipped():
action = _switches({"SW_A": True, "SW_ONLY_IN_ACTION": True})
cont = _FakeNetwork(_switches({"SW_A": False}))
result = RecommenderService._diff_switches(action, cont)
assert result == {"SW_A": {"from_open": False, "to_open": True}}
assert "SW_ONLY_IN_ACTION" not in result
def test_no_changes_returns_empty():
action = _switches({"SW_A": True, "SW_B": False})
cont = _FakeNetwork(_switches({"SW_A": True, "SW_B": False}))
assert RecommenderService._diff_switches(action, cont) == {}
def test_failure_is_swallowed_to_empty():
class _Boom:
def get_switches(self):
raise RuntimeError("boom")
# Switches are informational — a failure must not break the SLD response.
assert RecommenderService._diff_switches(_switches({"SW_A": True}), _Boom()) == {}