#!/usr/bin/env python3 """Red-proof the R-893 option A tests: apply one mutation, run its test, expect FAIL, restore the file.""" import subprocess, sys ROOT = "/mnt/5_hdd/felhom.eu/git/felhom-controller/controller" U = ROOT + "/internal/backup/offbox_restore_undo.go" R = ROOT + "/internal/backup/offbox_reconstitute.go" CASES = [ ("put-back skipped", U, " if volumesMoved {\n if err := m.putBack(stack, c); err != nil {", " if false {\n if err := m.putBack(stack, c); err != nil {", "TestR893A_AFailedReplayPutsTheLiveVolumesBackExactly"), ("volume-replay branch without undo", R, "if definitionMoved || nVols > 0 || undo != nil {", "if definitionMoved || nVols > 0 {", "TestR893A_AFailedVolumeReplayStillPutsBackWhenItCountedNothing"), ("fit check without the copy", R, "if free < need+volNeed {", "if free < need {", "TestR893A_TheCopyMustFitBeforeAnythingStops"), ("probe error ignored", U, " if pErr != nil {\n return 0, nil, pErr\n }", " if pErr != nil {\n continue\n }", "TestR893A_AnUnmeasurableVolumeRefusesBeforeAnythingStops"), ("no drop on exit", R, " defer undo.drop(m, stack)\n", "", "TestR893A_ASuccessfulRestoreRemovesTheCopy"), ("copy not kept on a failed put-back", U, " c.keep = true\n", "", "TestR893A_AFailedPutBackHoldsTheAppAndKeepsTheCopy"), ("copy error ignored", R, " if cErr != nil {\n m.logger.Printf(\"[ERROR] [offbox] %s: the copy of the live volumes failed", " if cErr != nil && false {\n m.logger.Printf(\"[ERROR] [offbox] %s: the copy of the live volumes failed", "TestR893A_AFailedCopyRestoresNothingAndStartsTheApp"), ("slice-1 hold after the rollback", R, " return res, m.putBackAfterFailedRestore(stack, iErr, liveDef, undo, res.VolumesReplayed > 0, res.FilesPlaced, restartStack, \"err.backup.db_restore_failed_held_mixed\")", " m.holdAppAfterMixedRestore(stack, iErr, liveDef)\n return res, util.MsgError(\"err.backup.db_restore_failed_held_mixed\", stack)", "TestR893_AVersionChangeThenAFailedReplayStartsTheAppAtItsLiveDefinition"), ("DB-start branch only restarts", R, " return res, m.putBackAfterFailedRestore(stack, err, liveDef, undo, res.VolumesReplayed > 0, res.FilesPlaced, restartStack, \"err.backup.restore_failed_held_mixed\")", " _ = restartStack()\n return res, err", "TestR893_AVersionChangeThenAFailedDBStartStartsTheAppAtItsLiveDefinition"), ] bad = 0 for name, path, old, new, test in CASES: src = open(path).read() if src.count(old) != 1: print("SETUP-ERROR", name, "match count", src.count(old)); bad += 1; continue open(path, "w").write(src.replace(old, new)) try: p = subprocess.run(["go", "test", "./internal/backup/", "-run", "^" + test + "$", "-count=1"], cwd=ROOT, capture_output=True, text=True) out = p.stdout + p.stderr line = next((l.strip() for l in out.splitlines() if "_test.go:" in l), out.strip().splitlines()[-1] if out.strip() else "") verdict = "RED (good)" if p.returncode != 0 else "STILL GREEN (BAD)" if p.returncode == 0: bad += 1 print("%-38s %-18s %s" % (name, verdict, line[:220])) finally: open(path, "w").write(src) print("restored; failures-to-go-red:", bad) sys.exit(1 if bad else 0)