3c49dc8ea4
gates / gates (push) Successful in 12s
R-399: monitoring.integrity.read_data_subset defaults to 100%. A pack damaged without changing its size made plain `restic check` report "no errors were found" on demo-hp 2026-08-30; every read-data form caught it. Cost on that 134 MB store: 35.0s structure vs 39.2s at 100%. "off" (any case) is the off token; empty means not-configured, therefore the default; a malformed value falls back to the DEFAULT, never to structure. A completed check over 5 minutes logs a WARN naming the duration, the depth and R-401 — operator log only, no hub event, no depth change. The depth is now recorded with the verdict (LastIntegrityDepth; empty = NOT RECORDED, never "structure"). R-400: 24 debug-page references, 17 dispatched, 7 dead — three of which fetched on page LOAD, so those panels were permanently blank. backup/crossdrive implemented; backup/infra, hub/infra-push, dr/infra-status, storage/watchdog-status and both storage/simulate-* deleted with their panels and JavaScript. scripts/debug_route_gate.py fails in both directions and is registered after the seven were resolved. 18 referenced, 18 dispatched, none orphaned. Corrections: the dead-field warning in report/types.go said the controller runs no integrity check and the notifiers are called from nowhere — both false since v0.227.0. controller.yaml.example gains its missing integrity: block. integrityCheckTimeout's "ships OFF" comment rewritten.
70 lines
2.9 KiB
Python
70 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Seam test for scripts/controller_gates.py.
|
|
|
|
Run from controller/: python3 scripts/test_controller_gates.py
|
|
|
|
WHY THIS EXISTS. An entry point is a seam by definition: a runner that LISTS a gate but never
|
|
executes it is inert and fully green, and this project has shipped an inert seam four times. So
|
|
the assertion is on each member gate's OWN distinctive stdout — never on the runner's summary
|
|
line, which the runner can print without ever calling anything — plus the exit code, which is a
|
|
runner's actual effect.
|
|
|
|
Red-proofed 2026-08-02: replacing run_gate's body with `return 0` (the inert runner) turns
|
|
test_every_member_gate_actually_ran red while the summary still prints "all controller gates OK".
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
|
|
SCRIPTS = os.path.dirname(os.path.abspath(__file__))
|
|
CTRL = os.path.dirname(SCRIPTS)
|
|
ENTRY = os.path.join(SCRIPTS, "controller_gates.py")
|
|
|
|
# (label, a substring only THAT gate can print)
|
|
FINGERPRINTS = [
|
|
("template-id", "integrity gate OK — every JS element-ID reference"),
|
|
("emoji", "emoji gate OK"),
|
|
("native-confirm", "native-confirm gate OK"),
|
|
("offbox-rename", "offbox rename gate OK"),
|
|
("app-row-dedup", "app_row_dedup_gate: OK"),
|
|
("mojibake", "mojibake_gate: OK"),
|
|
("docker-v", "docker -v gate OK"),
|
|
("debug-routes", "debug route gate OK"),
|
|
("reuse-refs", "cited paths — exact"),
|
|
]
|
|
|
|
|
|
class ControllerGatesTest(unittest.TestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
p = subprocess.run([sys.executable, ENTRY, "--fast"], cwd=CTRL,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
cls.rc = p.returncode
|
|
cls.out = p.stdout.decode("utf-8", "replace")
|
|
|
|
def test_exit_code_is_zero(self):
|
|
self.assertEqual(self.rc, 0, self.out)
|
|
|
|
def test_every_member_gate_actually_ran(self):
|
|
for label, fingerprint in FINGERPRINTS:
|
|
self.assertIn(fingerprint, self.out,
|
|
"gate %r is listed but its own output never appeared — an inert runner "
|
|
"prints the summary without calling anything:\n%s" % (label, self.out))
|
|
|
|
def test_shared_reuse_checker_is_not_copied_into_this_repo(self):
|
|
"""It lives in felhom.eu/scripts/ and is invoked across the workspace. A copy here would
|
|
recreate exactly the drift it exists to detect."""
|
|
self.assertFalse(os.path.exists(os.path.join(SCRIPTS, "reuse_refs_check.py")),
|
|
"reuse_refs_check.py must NOT be copied into this repo")
|
|
|
|
def test_unknown_argument_is_rejected(self):
|
|
p = subprocess.run([sys.executable, ENTRY, "--nope"], cwd=CTRL,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
self.assertEqual(p.returncode, 2, p.stdout.decode("utf-8", "replace"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|