73 lines
3.3 KiB
Python
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())
|