feat(scada): add calibrated monitoring and incident recovery

This commit is contained in:
2026-11-07 19:44:58 +08:00
parent 26fa5d1909
commit ff8aba4964
109 changed files with 9165 additions and 629 deletions
+19 -3
View File
@@ -55,6 +55,11 @@ def test_capabilities_reports_ready_only_with_five_pressures_and_outlet_flow(rep
assert response.status_code == 200
assert response.json()["burst_monitoring_ready"] is True
assert response.json()["burst_monitoring_reason"] is None
rules = response.json()["monitoring_config"]
assert rules["decision_policy"] == "weighted"
assert rules["weights"] == {"burst_detection": 0.5, "pressure": 0.4, "outlet_flow": 0.1}
assert rules["alert_threshold"] == 0.8
assert rules["pressure_device_ids"] == ["P1", "P2", "P3", "P4", "P5"]
def test_capabilities_reports_only_missing_storage_not_worker():
@@ -71,7 +76,17 @@ def test_capabilities_reports_only_missing_storage_not_worker():
assert result.reason == "需先部署 SCADA 回放存储结构"
def test_step_command_processes_pending_period_in_same_request(monkeypatch):
def test_weighted_capabilities_allow_flow_as_optional_support(replay_api):
client, project, *_ = replay_api
monitoring = {"pressure_device_ids": ["P1", "P2", "P3", "P4", "P5"]}
project.settings = {"scada_monitoring": monitoring}
assert client.get("/scada-replays/capabilities").json()["burst_monitoring_ready"] is True
monitoring["decision_policy"] = "all_signals"
assert client.get("/scada-replays/capabilities").json()["burst_monitoring_ready"] is False
@pytest.mark.parametrize("action", ["step", "monitor"])
def test_monitoring_command_processes_pending_period_in_same_request(monkeypatch, action):
calls = []
class Service:
@@ -90,7 +105,8 @@ def test_step_command_processes_pending_period_in_same_request(monkeypatch):
replay_id = uuid4()
context = ProjectContext(uuid4(), "demo", uuid4(), "member")
command = scada_replay.ScadaReplayCommand(
request_id=uuid4(), expected_revision=1, action="step"
request_id=uuid4(), expected_revision=1, action=action,
**({"at_time": "2026-07-16T00:00:00Z"} if action == "monitor" else {}),
)
result = asyncio.run(scada_replay.replay_command(
@@ -98,7 +114,7 @@ def test_step_command_processes_pending_period_in_same_request(monkeypatch):
))
assert result == "completed-period"
assert calls[-2:] == [(replay_id, "step"), (replay_id, "processed")]
assert calls[-2:] == [(replay_id, action), (replay_id, "processed")]
def test_client_cannot_override_project_frequency_on_creation(replay_api):