#!/usr/bin/env python3 """ check_schedkit.py -- one command, one verdict for the schedkit artifact. Exit 0 == the committed schedkit.py is the fixed build, the spec that grades it is green, and that spec bites. Exit 1 == otherwise (the failing leg is printed). Legs 1 spec on the committed module must exit 0 2 spec on four sampled mutants each must exit non-zero 3 cost differential, one 2,000-node chain, both builds, same machine: the fixed build must be fast and the pre-fix build slow -- the perf claim graded by measurement, not by assertion Usage: python3 check_schedkit.py [--mutant-budget SECONDS] """ import os import shutil import subprocess import sys import tempfile HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) import mutate_teeth as teeth # noqa: E402 # Four single-substitution bugs the spec must kill. Indices into teeth.MUTANTS; # all four are pure-behaviour mutants, so each run costs one full spec pass. SAMPLE = [0, 1, 7, 9] TIMING_PROBE = ''' import importlib.util, sys, time path, n = sys.argv[1], int(sys.argv[2]) spec = importlib.util.spec_from_file_location("probe_mod", path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) g = mod.Graph() for i in range(n - 1): g.add_edge("d%06d" % i, "d%06d" % (i + 1)) t0 = time.monotonic() cyc = mod.find_cycles(g) print("%.4f %d" % (time.monotonic() - t0, len(cyc))) ''' def main() -> int: budget = 300.0 if "--mutant-budget" in sys.argv: budget = float(sys.argv[sys.argv.index("--mutant-budget") + 1]) fails = [] print("check_schedkit -- %s" % HERE) # -------------------------------------------------- leg 1: the spec is green tmp = tempfile.mkdtemp(prefix="check-control-") try: shutil.copy(teeth.MODULE, os.path.join(tmp, "schedkit.py")) shutil.copy(teeth.SPEC, os.path.join(tmp, "spec_schedkit.py")) rc, out, dt = teeth.run_spec(tmp, budget) print("1 spec on committed module rc=%s %.1fs %s" % (rc, dt, teeth.summary(out))) if rc != 0: fails.append("leg 1: the spec did not pass on the committed module") finally: shutil.rmtree(tmp, ignore_errors=True) # ------------------------------------------------- leg 2: the spec has teeth src = open(teeth.MODULE).read() for idx in SAMPLE: label, old, new = teeth.MUTANTS[idx] if src.count(old) != 1: fails.append("leg 2: mutant %d anchor is not unique" % idx) print("2 mutant %-2d ANCHOR MISSING %s" % (idx, label)) continue tmp = tempfile.mkdtemp(prefix="check-m%02d-" % idx) try: with open(os.path.join(tmp, "schedkit.py"), "w") as fh: fh.write(src.replace(old, new)) shutil.copy(teeth.SPEC, os.path.join(tmp, "spec_schedkit.py")) rc, out, dt = teeth.run_spec(tmp, budget) ok = rc is None or rc != 0 print( "2 mutant %-2d %-8s %.1fs %s" % (idx, "CAUGHT" if ok else "SURVIVED", dt, label) ) if not ok: fails.append("leg 2: mutant %d survived: %s" % (idx, label)) finally: shutil.rmtree(tmp, ignore_errors=True) # ------------------------------------- leg 3: measured cost of both builds tmp = tempfile.mkdtemp(prefix="check-timing-") try: probe = os.path.join(tmp, "probe.py") with open(probe, "w") as fh: fh.write(TIMING_PROBE) n = 2000 times = {} for name, mod in (("fixed", teeth.MODULE), ("pre-fix", teeth.BASELINE)): if not os.path.exists(mod): fails.append("leg 3: missing module %s" % mod) continue p = subprocess.run( [sys.executable, probe, mod, str(n)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=300, text=True, ) if p.returncode != 0: fails.append("leg 3: probe on %s failed: %s" % (name, p.stdout.strip())) continue secs, cycles = p.stdout.split() times[name] = float(secs) print("3 %-7s chain n=%d find_cycles %.4fs, %s cycles" % (name, n, float(secs), cycles)) if cycles != "0": fails.append("leg 3: %s reported %s cycles on an acyclic chain" % (name, cycles)) if "fixed" in times and times["fixed"] >= 0.5: fails.append("leg 3: fixed build took %.3fs on a 2,000-node chain" % times["fixed"]) if "pre-fix" in times and times["pre-fix"] <= 1.0: fails.append( "leg 3: pre-fix build was fast (%.3fs) -- the quadratic claim is not reproducible" % times["pre-fix"] ) if len(times) == 2: print(" ratio: %.0fx slower before the fix" % (times["pre-fix"] / times["fixed"])) finally: shutil.rmtree(tmp, ignore_errors=True) if fails: print("\nCHECK FAILED (%d):" % len(fails)) for f in fails: print(" - %s" % f) return 1 print("\nCHECK OK: spec green on the committed module, 4/4 sampled mutants killed, cost differential reproduced") return 0 if __name__ == "__main__": sys.exit(main())