forked from b.peck/BAT
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:
94
tests/test_fmt.py
Normal file
94
tests/test_fmt.py
Normal 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"]
|
||||
Reference in New Issue
Block a user