R-1288: a restore of a set-aside unit sets the replaced install's unit aside at once, with no alarm. R-1282: the later media restart time is stored and resumed at start, once. Red-proved. Commit only.
gates / gates (push) Successful in 1m26s
gates / gates (push) Successful in 1m26s
This commit is contained in:
@@ -320,3 +320,56 @@ func TestD47_ASetAsideTellsTheOperatorOnce(t *testing.T) {
|
||||
t.Fatalf("the operator hears once, with both identities: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// R-1288, the Tester 1 order measured 2026-10-25 on 0.343.0: install A backed up → reinstall B → B's first backup sets
|
||||
// A's unit aside (one alarm) and writes B's own unit → the household restores A's set-aside copy. Before: the next
|
||||
// backup found B's unit and set it aside with a SECOND alarm. Now B's unit is set aside AT the restore, quietly, and
|
||||
// the next backup writes A's unit with nothing more set aside.
|
||||
// RED-PROOF: drop the retireReplacedUnit call → after the restore the primary place still holds B's unit, and the
|
||||
// next capture alarms a second time.
|
||||
func TestR1288_ARestoreOfASetAsideUnitRetiresTheReplacedUnitQuietly(t *testing.T) {
|
||||
r := d47Setup(t, "aaaa000000000001")
|
||||
var alarms []string
|
||||
r.m.SetUnitSetAsideNotify(func(stack, unitID, liveID, dest string) { alarms = append(alarms, unitID) })
|
||||
r.reinstall("bbbb000000000002")
|
||||
if err := r.m.captureRecoveryUnit("tandoor", false); err != nil { // B's first backup: A set aside, B's unit written
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(alarms) != 1 || len(r.setAside(t)) != 1 {
|
||||
t.Fatalf("precondition: one set-aside, one alarm; got alarms %v, set-aside %v", alarms, r.setAside(t))
|
||||
}
|
||||
r.m.discoverDBs = func(context.Context) ([]DiscoveredDB, error) {
|
||||
return []DiscoveredDB{{StackName: "tandoor", ContainerName: "tandoor-postgres", DBType: DBTypePostgres}}, nil
|
||||
}
|
||||
r.m.importDBDump = func(context.Context, DiscoveredDB, string) error { return nil }
|
||||
r.m.volumeReplayFrom = func(string, string) (int, error) { return 1, nil }
|
||||
r.m.undoVolumeProbeFn = func(string) (int64, bool, error) { return 10, true, nil }
|
||||
r.m.undoVolumeTarFn = func(vol, dir string) error {
|
||||
return os.WriteFile(filepath.Join(dir, vol+".tar"), []byte("live"), 0o600)
|
||||
}
|
||||
ks := r.sett.GetKeptCopies()
|
||||
if _, _, err := r.m.RestoreSetAsideUnit(ks[0].ID); err != nil {
|
||||
t.Fatalf("restore of A's set-aside unit: %v", err)
|
||||
}
|
||||
if r.prov.info.InstallID != "aaaa000000000001" {
|
||||
t.Fatalf("precondition: the restored app is install A, got %q", r.prov.info.InstallID)
|
||||
}
|
||||
if exists, id, _ := unitOwnerOf(r.unitDir()); exists {
|
||||
t.Fatalf("after the restore the primary place still holds install %q's unit — it must be set aside at the restore", id)
|
||||
}
|
||||
if got := len(r.setAside(t)); got != 2 {
|
||||
t.Fatalf("set-aside units after the restore: %d, want 2 (A's, kept as the household's copy, and B's)", got)
|
||||
}
|
||||
if len(alarms) != 1 {
|
||||
t.Fatalf("the restore the household chose must not alarm: alarms %v", alarms)
|
||||
}
|
||||
if !strings.Contains(r.logs.String(), "replaced by the restored install") {
|
||||
t.Fatal("the restore's set-aside must say why in one line")
|
||||
}
|
||||
if err := r.m.captureRecoveryUnit("tandoor", false); err != nil { // the next backup: A's own unit, nothing set aside
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(alarms) != 1 || len(r.setAside(t)) != 2 {
|
||||
t.Fatalf("the next backup set something aside again: alarms %v, set-aside %v", alarms, r.setAside(t))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user