Phase 1 data layer: calc/fmt/alarms + 31 CPython tests + live gateway P1 smoke

pytest 31/31. In-gateway end-to-end: 559 activations correlated (uuid mode), 3 chatterers,
34 fleeting, 1 flood, health F(22) on the deliberately-bad sim plant. Gate G1 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 13:08:02 -05:00
parent c82a2fa6df
commit ecb10b9b7b
12 changed files with 1971 additions and 3 deletions

94
tests/test_fmt.py Normal file
View File

@@ -0,0 +1,94 @@
import os
import time
from PrimeControls import calc, fmt
H = 3600000
M = 60000
T0 = 1784200000000
def test_dur_num_pct():
assert fmt.dur(None) == "--"
assert fmt.dur(42000) == "42s"
assert fmt.dur(90 * M) == "1h 30m"
assert fmt.dur(26 * H) == "1d 2h"
assert fmt.num(None) == "--"
assert fmt.num(1234567) == "1,234,567"
assert fmt.num(12.345, 1) == "12.3"
assert fmt.pct(34.2) == "34%"
assert fmt.pct(34.2, 0, True) == "+34%"
def test_delta_chip():
assert fmt.delta_chip(calc.delta(200, 100))["arrow"] == fmt.ARROW_UP
assert fmt.delta_chip(calc.delta(50, 100))["arrow"] == fmt.ARROW_DOWN
assert fmt.delta_chip(calc.delta(10, 0))["text"] == "new"
assert fmt.delta_chip(None)["text"] == "--"
def bundle_with(rows=None, status=None):
return calc.build_bundle(rows or [], status or [], 0, T0, T0 + 4 * H, T0 + 4 * H)
def lifecycle(eid, src, t, dur_ms=None, ack_ms=None, prio=3):
lvl, name = calc.normalize_priority(prio)
rows = [{"event_id": eid, "source": src, "display_path": "", "priority": lvl,
"priority_name": name, "state": "active", "ts": t, "is_system": False,
"ack_user": None}]
if dur_ms:
rows.append(dict(rows[0], state="clear", ts=t + dur_ms))
return rows
def test_insights_fallback_and_cap():
b = bundle_with()
ins = fmt.insights(b)
assert len(ins) == 1 and ins[0]["severity"] == 3
assert "No alarm events" in ins[0]["text"]
def test_insights_chatter_and_flood_fire():
rows = []
for i in range(100): # ~25/hr over the 4h window, median gap 50s
rows += lifecycle("c%d" % i, "prov:default:/tag:P/A/Chat:/alm:Chat",
T0 + i * 50000, dur_ms=8000)
for i in range(15):
rows += lifecycle("f%d" % i, "prov:default:/tag:P/B/F%d:/alm:F%d" % (i, i),
T0 + 2 * H + i * 30000, dur_ms=M)
b = bundle_with(rows)
b["insights"] = fmt.insights(b)
texts = " | ".join(i["text"] for i in b["insights"])
assert "chatter" in texts.lower()
assert "flood" in texts.lower()
assert len(b["insights"]) <= 5
def test_shift_bounds_grid():
os.environ["TZ"] = "UTC"
time.tzset()
# Thu Jul 16 2026 14:20 UTC
now = 1784211600000 + 20 * M
sb = fmt.shift_bounds(now, 8, 0)
cs, ce = sb["current"]
ps, pe = sb["previous"]
assert ce - cs == 8 * H and pe == cs
lt = time.localtime(cs / 1000.0)
assert lt.tm_hour in (0, 8, 16)
sb2 = fmt.shift_bounds(now, 12, 6)
lt2 = time.localtime(sb2["current"][0] / 1000.0)
assert lt2.tm_hour in (6, 18)
def test_shift_report_sections():
rows = []
for i in range(10):
rows += lifecycle("b%d" % i, "prov:default:/tag:P/A/T%d:/alm:T%d" % (i, i),
T0 + i * 10 * M, dur_ms=M)
b = bundle_with(rows)
b["insights"] = fmt.insights(b)
rep = fmt.shift_report(b, "Thu 6:00 AM - Thu 2:00 PM")
heads = [s["heading"] for s in rep["sections"]]
assert any("SHIFT REPORT" in h for h in heads)
assert any("KPIs" in h for h in heads)
assert "Activations" in rep["text"]