88b0a2e761
gates / gates (push) Successful in 30s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
45 lines
3.1 KiB
Python
45 lines
3.1 KiB
Python
import subprocess, sys, shutil
|
|
M = [
|
|
("host candidate leaves out kernel/boot/firmware", "internal/osupdates/service.go",
|
|
"if layer == LayerHost && hostSlowRE.MatchString(p.Name) {\n\t\t\t\tcontinue", "if false && hostSlowRE.MatchString(p.Name) {\n\t\t\t\tcontinue",
|
|
"./internal/osupdates/", "TestCandidate_HostLeavesOutKernelBootFirmware"),
|
|
("host nights counted per layer", "internal/osupdates/service.go",
|
|
"reps, err := s.Store.OSReportsSince(h, layer, first)", "reps, err := s.Store.OSReportsSince(h, LayerGuest, first)",
|
|
"./internal/osupdates/", "TestLayers_SeparateSets"),
|
|
("alarm 1 stale threshold", "internal/osupdates/service.go",
|
|
"now.Sub(ref) >= stale", "now.Sub(ref) >= 10*stale", "./internal/osupdates/", "TestAlarm_StaleLeg"),
|
|
("alarm 1 switch OFF not watched", "internal/osupdates/service.go",
|
|
"holds := st.Enabled && canRun", "holds := canRun", "./internal/osupdates/", "TestAlarm_StaleLeg"),
|
|
("alarm 2 reboot-needed counts from the FIRST report", "internal/osupdates/service.go",
|
|
"\t\tsince = rep.ReceivedAt\n", "\t\tif since.IsZero() {\n\t\t\tsince = rep.ReceivedAt\n\t\t}\n", "./internal/osupdates/", "TestAlarm_RebootNeeded"),
|
|
("alarm 3 counts only fast-lane pending", "internal/osupdates/service.go",
|
|
"pendingAny += len(fastPending(layer, r.Pending))", "pendingAny += len(r.Pending)", "./internal/osupdates/", "TestAlarm_Ring0Stalled"),
|
|
("alarm 4 ring 0 never alarms", "internal/osupdates/service.go",
|
|
"\tif ring == 0 {\n\t\treturn nil\n\t}\n", "", "./internal/osupdates/", "TestAlarm_NotCovered"),
|
|
("alarm events are operator-only", "internal/notify/dispatcher.go",
|
|
'\t"os_ring0_stalled": true,\n', "", "./internal/notify/", "TestOSUpdateEvents_OperatorOnlyExceptApplied"),
|
|
("host_release served to ring 1", "internal/osupdates/service.go",
|
|
"b.Release, b.HostRelease = s.releaseBlock(LayerGuest), s.releaseBlock(LayerHost)", "b.Release = s.releaseBlock(LayerGuest)",
|
|
"./internal/api/", "TestOSUpdate_DesiredBlockMatchesTheGolden"),
|
|
]
|
|
ok = True
|
|
for name, f, old, new, pkg, test in M:
|
|
src = open(f).read()
|
|
assert src.count(old) == 1, (name, src.count(old))
|
|
shutil.copy(f, f + ".bak")
|
|
open(f, "w").write(src.replace(old, new))
|
|
r = subprocess.run(["go", "test", pkg, "-run", "^" + test + "$", "-v", "-count=1"], capture_output=True, text=True)
|
|
shutil.move(f + ".bak", f)
|
|
out = r.stdout + r.stderr
|
|
ran = ("=== RUN " + test) in out
|
|
failed = ("--- FAIL: " + test) in out
|
|
verdict = "CAUGHT" if (ran and failed and r.returncode != 0) else "NOT CAUGHT"
|
|
if verdict != "CAUGHT": ok = False
|
|
print(f"[{verdict}] {name}: mutated {f}; {test} ran={ran} failed={failed} rc={r.returncode}")
|
|
for l in out.splitlines():
|
|
if "_test.go:" in l or l.startswith("FAIL\t") or "build failed" in l or l.startswith("#"):
|
|
print(" " + l.strip()[:220])
|
|
r = subprocess.run(["go", "test", "./internal/osupdates/", "./internal/notify/", "./internal/api/", "-count=1"], capture_output=True, text=True)
|
|
print("after restore:", r.stdout.strip().replace("\n", " | "), "rc=", r.returncode)
|
|
sys.exit(0 if ok and r.returncode == 0 else 1)
|