feat: add webhook case management

This commit is contained in:
2026-06-09 11:13:56 +08:00
parent 490b3089d2
commit 9d791be174
17 changed files with 1982 additions and 12 deletions

View File

@@ -3,12 +3,102 @@ from __future__ import annotations
import json
import tempfile
import unittest
from datetime import datetime, timezone
from pathlib import Path
from cold_display_guard.main import restore_runtime_state
from cold_display_guard.cases import CaseStore
from cold_display_guard.main import case_sink_path, deliver_runtime_webhooks, persist_case_updates, restore_runtime_state
UTC = timezone.utc
class RuntimeRestoreTests(unittest.TestCase):
def test_case_sink_path_uses_default_logs_location(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
root = Path(tmpdir)
path = case_sink_path(root, {})
self.assertEqual(path, (root / "logs" / "cases.jsonl").resolve())
def test_persist_case_updates_writes_case_snapshots(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
path = Path(tmpdir) / "cases.jsonl"
store = CaseStore()
snapshots = persist_case_updates(
store,
path,
[
{
"event": "time_alarm",
"ts": datetime(2026, 6, 9, 9, 0, tzinfo=UTC).isoformat(),
"batch_id": "batch_000001",
"camera_id": "cam_01",
"zone_id": "1",
"zone_label": "区域 1",
"severity": "alarm",
"state": "alerted",
}
],
)
written = [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()]
self.assertEqual(len(snapshots), 1)
self.assertEqual(written[0]["case_type"], "time_alarm")
self.assertEqual(written[0]["case_status"], "open")
def test_deliver_runtime_webhooks_sends_event_and_case_payloads(self) -> None:
deliveries: list[tuple[str, dict[str, object]]] = []
def fake_post(url: str, payload: dict[str, object], timeout: tuple[float, float]) -> tuple[int, str]:
deliveries.append((url, payload))
return 200, "ok"
with tempfile.TemporaryDirectory() as tmpdir:
audit_path = Path(tmpdir) / "webhook_delivery.jsonl"
deliver_runtime_webhooks(
[
{
"event": "time_alarm",
"ts": datetime(2026, 6, 9, 9, 0, tzinfo=UTC).isoformat(),
"batch_id": "batch_000001",
"camera_id": "cam_01",
"zone_id": "1",
"zone_label": "区域 1",
"severity": "alarm",
"state": "alerted",
}
],
[
{
"case_id": "case_batch_000001",
"batch_id": "batch_000001",
"case_type": "time_alarm",
"case_status": "open",
"source_event": "time_alarm",
"handled_source": "",
"created_at": datetime(2026, 6, 9, 9, 0, tzinfo=UTC).isoformat(),
"updated_at": datetime(2026, 6, 9, 9, 0, tzinfo=UTC).isoformat(),
}
],
{
"webhooks": {
"enabled": True,
"event_url": "https://example.com/events",
"case_url": "https://example.com/cases",
}
},
audit_path,
http_post=fake_post,
)
self.assertEqual(len(deliveries), 2)
self.assertEqual(deliveries[0][1]["kind"], "batch_event")
self.assertEqual(deliveries[1][1]["kind"], "case_event")
def test_restore_runtime_state_uses_stable_occupancy_when_raw_metrics_flicker(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
diagnostics_path = Path(tmpdir) / "runtime_diagnostics.jsonl"