81 lines
3.2 KiB
Python
81 lines
3.2 KiB
Python
"""Smoke test — PERT chart endpoint and data quality."""
|
|
import sys, requests, urllib.parse
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
|
|
BASE = "http://localhost:8000/api/tna"
|
|
checks = []
|
|
|
|
def check(label, ok, detail=""):
|
|
checks.append((label, ok, detail))
|
|
print(f" [{'PASS' if ok else 'FAIL'}] {label}" + (f" — {detail}" if detail else ""))
|
|
|
|
# Get orders first
|
|
r = requests.get(f"{BASE}/orders")
|
|
orders = r.json().get("orders", [])
|
|
check("Orders available", len(orders) > 0, f"{len(orders)} orders")
|
|
|
|
for order in orders:
|
|
style = order["style_number"]
|
|
encoded = urllib.parse.quote(style, safe='')
|
|
|
|
r = requests.get(f"{BASE}/orders/{encoded}/pert")
|
|
check(f"PERT endpoint 200 for {style[:20]}", r.status_code == 200, str(r.status_code))
|
|
|
|
if r.status_code != 200:
|
|
continue
|
|
|
|
data = r.json()
|
|
|
|
# Structure checks
|
|
check("PERT has nodes array", isinstance(data.get("nodes"), list), f"{len(data.get('nodes',[]))} nodes")
|
|
check("PERT has edges array", isinstance(data.get("edges"), list), f"{len(data.get('edges',[]))} edges")
|
|
check("PERT has critical_path_ids", isinstance(data.get("critical_path_ids"), list))
|
|
check("PERT has days_to_pcd", "days_to_pcd" in data, str(data.get("days_to_pcd")))
|
|
check("PERT has track_y_positions", isinstance(data.get("track_y_positions"), dict))
|
|
|
|
nodes = data.get("nodes", [])
|
|
check("At least 5 nodes", len(nodes) >= 5, f"{len(nodes)}")
|
|
|
|
if nodes:
|
|
n = nodes[0]
|
|
required_fields = ["id", "task_name", "sop_code", "track", "status",
|
|
"end_date", "delay_days", "float_days", "is_critical", "x", "y"]
|
|
check("Node has all required fields", all(f in n for f in required_fields),
|
|
str([f for f in required_fields if f not in n]))
|
|
check("Node x > 0", n["x"] > 0, f"x={n['x']}")
|
|
check("Node y > 0", n["y"] > 0, f"y={n['y']}")
|
|
check("Node status is valid", n["status"] in ("RED","AMBER","GREEN","DONE","PENDING"),
|
|
n["status"])
|
|
|
|
edges = data.get("edges", [])
|
|
if edges:
|
|
e = edges[0]
|
|
check("Edge has id, source, target", all(f in e for f in ["id","source","target"]))
|
|
node_ids = {n["id"] for n in nodes}
|
|
orphan = [e for e in edges if e["source"] not in node_ids or e["target"] not in node_ids]
|
|
check("No orphan edges (source/target in nodes)", len(orphan) == 0,
|
|
f"{len(orphan)} orphans: {orphan[:2]}")
|
|
|
|
cp = data.get("critical_path_ids", [])
|
|
check("Critical path has nodes", len(cp) > 0, f"path={cp}")
|
|
check("Critical path nodes are in node list", all(n in {n['id'] for n in nodes} for n in cp),
|
|
f"path={cp}")
|
|
|
|
# Check critical nodes are marked
|
|
crit_nodes = [n for n in nodes if n["is_critical"]]
|
|
check("At least 1 critical node", len(crit_nodes) > 0, f"{len(crit_nodes)} critical")
|
|
|
|
# Frontend
|
|
r = requests.get("http://localhost:5173/tna")
|
|
check("Frontend /tna still loads", r.status_code == 200)
|
|
|
|
passed = sum(1 for _, ok, _ in checks if ok)
|
|
failed = sum(1 for _, ok, _ in checks if not ok)
|
|
print(f"\n{passed} PASS / {failed} FAIL")
|
|
if failed == 0:
|
|
print("\nPERT Chart: PASS")
|
|
sys.exit(0)
|
|
else:
|
|
print("\nPERT Chart: FAIL")
|
|
sys.exit(1)
|