# -*- coding: utf-8 -*- """Seam test for scripts/catalog_gates.py --fast. Run: python3 scripts/test_catalog_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. So the assertion is on the member gate's OWN distinctive stdout — never on the runner's summary line — plus the exit code. The second and third tests pin --fast's CONTENT, not just its exit code: the two runtime gates must NOT run (a push that pulls images and starts containers gets bypassed within a week, and the bypass becomes the habit), and the skip must be ANNOUNCED — a silently narrowed run reads as "covered everything" when it did not. """ import os import subprocess import sys import unittest ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ENTRY = os.path.join(ROOT, "scripts", "catalog_gates.py") class CatalogGatesFastTest(unittest.TestCase): @classmethod def setUpClass(cls): p = subprocess.run([sys.executable, ENTRY, "--fast"], cwd=ROOT, 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_static_gate_actually_ran(self): self.assertIn("image-pin gate", self.out, "check-image-pins is listed but its own output never appeared — an inert " "runner prints the summary without calling anything:\n%s" % self.out) def test_runtime_gates_did_not_run(self): for fingerprint in ("resolvability gate", "volume-persistence gate", "canary"): self.assertNotIn(fingerprint, self.out, "a runtime gate ran under --fast (%r) — --fast must touch no network " "and no container runtime:\n%s" % (fingerprint, self.out)) self.assertNotIn("image-resolvable OK", self.out) self.assertNotIn("volume-persistence OK", self.out) def test_skip_is_announced(self): self.assertIn("--fast SKIPPED", self.out) self.assertIn("image-resolvable", self.out) self.assertIn("volume-persistence", self.out) def test_default_run_still_selects_all_three(self): """--fast must not change the no-flag behaviour. Asserted on the GATES table rather than by running it — the default run deploys every template and takes minutes per app.""" import importlib.util spec = importlib.util.spec_from_file_location("catalog_gates_under_test", ENTRY) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) self.assertEqual(len(mod.GATES), 3) self.assertEqual([g[0] for g in mod.GATES if g[3]], ["image-pins"]) if __name__ == "__main__": unittest.main(verbosity=2)