fix(scada): verify first sample after field completion
Generic Container CI/CD / test-build-publish (push) Failing after 47s
Server CI/CD v2 / build-test-publish-and-deploy (push) Failing after 47s

This commit is contained in:
2026-11-07 19:50:31 +08:00
parent ff8aba4964
commit dc83cf5c88
7 changed files with 131 additions and 71 deletions
+31 -6
View File
@@ -27,11 +27,11 @@ def evaluate(rows):
incident_at=INCIDENT, interval_seconds=900)
def test_recovery_uses_post_receipt_samples_and_pre_incident_same_phase_reference():
def test_recovery_uses_nearest_post_receipt_sample_and_pre_incident_reference():
result = evaluate(observations())
assert result["status"] == "passed"
assert [item["at"] for item in result["samples"]] == [
(RETURNED + timedelta(minutes=30)).isoformat(), (RETURNED + timedelta(minutes=45)).isoformat()]
assert result["required_samples"] == 1
assert [item["at"] for item in result["samples"]] == [(RETURNED + timedelta(minutes=15)).isoformat()]
assert all(check["normal_day_count"] == 15 for sample in result["samples"] for check in sample["devices"])
@@ -59,7 +59,7 @@ def test_samples_at_or_before_return_time_cannot_close_incident():
assert evaluate(rows)["status"] == "waiting"
def test_faster_sampling_counts_monitoring_periods_and_rejects_later_relapse():
def test_nearest_sample_does_not_wait_for_monitoring_interval_or_use_later_data():
rows = []
for minute in range(5, 36, 5):
at = RETURNED + timedelta(minutes=minute)
@@ -67,9 +67,34 @@ def test_faster_sampling_counts_monitoring_periods_and_rejects_later_relapse():
rows.extend({"time": at - timedelta(days=day), "device_id": device, "monitored_value": 100.}
for day in range(1, 16))
rows.append({"time": at, "device_id": device, "monitored_value": 100.})
assert evaluate(rows)["status"] == "passed"
first = evaluate(rows)
assert first["status"] == "passed"
assert first["verified_through"] == (RETURNED + timedelta(minutes=5)).isoformat()
next(row for row in rows if row["time"] == RETURNED + timedelta(minutes=25) and row["device_id"] == "P1")["monitored_value"] = 50.
assert evaluate(rows)["status"] == "waiting"
assert evaluate(rows) == first
@pytest.mark.parametrize("problem", ["abnormal", "invalid", "null", "missing_device"])
def test_nearest_bad_sample_is_not_replaced_by_later_normal_samples(problem):
rows = observations()
nearest = RETURNED + timedelta(minutes=15)
row = next(row for row in rows if row["time"] == nearest and row["device_id"] == "P1")
if problem == "missing_device":
rows.remove(row)
elif problem == "invalid":
row["quality"] = "invalid"
else:
row["monitored_value"] = 50. if problem == "abnormal" else None
result = evaluate(rows)
assert result["status"] == "waiting"
assert result["sample"]["at"] == nearest.isoformat()
def test_off_grid_feedback_uses_first_later_sample_even_without_monitoring_interval():
result = evaluate_recovery(observations(), device_ids=["P1", "F1"],
returned_at=RETURNED + timedelta(minutes=7), incident_at=INCIDENT, interval_seconds=0)
assert result["status"] == "passed"
assert result["verified_through"] == (RETURNED + timedelta(minutes=15)).isoformat()
def test_dispatch_waits_for_all_orders_and_accepts_corrected_field_completion_time():