Files
felhom.eu/scripts/host_swap_rule_gate.py
T

73 lines
3.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""host_swap_rule_gate.py — the hub and the box judge „too little host swap" by ONE rule (R-1216, D28 = A).
Run from the repo root: python3 scripts/host_swap_rule_gate.py
Exit 0 clean · 1 convicted · 2 inconclusive (the felhom-controller clone is not beside this one — never a silent pass).
WHY. The rule lives twice: the hub raises `host_swap_short` for the operator (hub/internal/api/host_swap.go), and the
controller's install page tells the household „A gépen nincs elég cserehely (swap)…" (internal/web/
system_memory_handlers.go). Two Go modules cannot share a function, so they share a CASE TABLE: each repo carries
`testdata/host_swap_rule_cases.json` and a Go test that runs its own implementation over every row. This gate is the
contract between them:
1. the two tables are BYTE-IDENTICAL (a row changed on one side only is drift);
2. each table is READ by a Go test in its own package (a table no test opens proves nothing — the label without the
fact: the file name present, the run absent).
The decoys are in scripts/test_host_swap_rule_gate.py, run from scripts/test_gate_decoys.py.
"""
from __future__ import annotations
import glob
import io
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
REPO = os.environ.get("HOST_SWAP_RULE_REPO") or os.path.dirname(HERE)
WORKSPACE = os.path.dirname(REPO)
NAME = "host_swap_rule_cases.json"
HUB_DIR = os.path.join(REPO, "hub", "internal", "api")
CTRL_DIR = os.path.join(WORKSPACE, "felhom-controller", "controller", "internal", "web")
def read_by_a_test(pkg_dir: str) -> bool:
for f in glob.glob(os.path.join(pkg_dir, "*_test.go")):
if NAME in io.open(f, encoding="utf-8").read():
return True
return False
def main() -> int:
hub = os.path.join(HUB_DIR, "testdata", NAME)
ctrl = os.path.join(CTRL_DIR, "testdata", NAME)
if not os.path.exists(hub):
print("host-swap-rule: CONVICTS — the hub's case table is gone (%s)" % os.path.relpath(hub, REPO))
return 1
if not os.path.isdir(os.path.join(WORKSPACE, "felhom-controller")):
print("host-swap-rule: INCONCLUSIVE — no felhom-controller clone beside this one; the contract cannot be read",
file=sys.stderr)
return 2
problems = []
if not os.path.exists(ctrl):
problems.append("the controller's case table is gone (felhom-controller/controller/internal/web/testdata/%s)" % NAME)
else:
a, b = open(hub, "rb").read(), open(ctrl, "rb").read()
if a != b:
problems.append("the two case tables differ (%d vs %d bytes) — the hub and the box no longer judge host "
"swap by the same rule" % (len(a), len(b)))
for label, d in (("hub", HUB_DIR), ("controller", CTRL_DIR)):
if not read_by_a_test(d):
problems.append("no Go test in the %s package reads %s — a table nothing runs proves nothing" % (label, NAME))
print("host-swap-rule: compared the hub's and the controller's %s, and looked for the test that runs each" % NAME)
if problems:
print("host-swap-rule gate CONVICTS (%d):" % len(problems))
for p in problems:
print(" " + p)
return 1
print("host-swap-rule gate OK: one rule, byte-identical tables, both run by a test.")
return 0
if __name__ == "__main__":
sys.exit(main())