package backup import ( "testing" "time" ) // After a controller restart the Backup → Apps „Databases" table is SYNTHESISED from the dump files on disk (the last // run's result is not in memory). Seen 2026-10-10 on demo-hp after the 0.305.0 delivery: every `pre-restore-` undo copy // (R-379) was listed as one more row of the night's run — adventurelog four times, bookstack four times, each stamped // with the run's time. An undo copy is not part of any run: it stays in the file list (its visibility is a recorded // decision), but the run table shows one row per database, the newest real dump. func TestSynthesisedRunListsNoUndoCopy(t *testing.T) { m, _ := newTestManager(t, "/srv/sys") night := time.Date(2026, 10, 10, 2, 15, 0, 0, time.UTC) m.cachedStatus = &FullBackupStatus{DumpFiles: []DumpFileInfo{ {StackName: "adventurelog", DBType: DBTypePostgres, FileName: "adventurelog-postgres.sql", ModTime: night}, {StackName: "adventurelog", DBType: DBTypePostgres, FileName: "pre-restore-20260913T193505Z-adventurelog-postgres.sql", ModTime: night.AddDate(0, 0, -27), IsUndo: true}, {StackName: "adventurelog", DBType: DBTypePostgres, FileName: "pre-restore-20260928T021839Z-adventurelog-postgres.sql", ModTime: night.AddDate(0, 0, -12), IsUndo: true}, {StackName: "bookstack", DBType: DBTypeMariaDB, FileName: "bookstack-mariadb.sql", ModTime: night}, {StackName: "bookstack", DBType: DBTypeMariaDB, FileName: "pre-restore-20260930T113419Z-bookstack-mariadb.sql", ModTime: night.AddDate(0, 0, -10), IsUndo: true}, }} st := m.GetFullStatus(time.Time{}) if st.LastDBDump == nil { t.Fatal("no synthesised run") } per := map[string]int{} for _, r := range st.LastDBDump.Results { per[r.DB.StackName]++ if r.FilePath != "adventurelog-postgres.sql" && r.FilePath != "bookstack-mariadb.sql" { t.Errorf("an undo copy is listed as a row of the run: %s", r.FilePath) } } if per["adventurelog"] != 1 || per["bookstack"] != 1 || len(st.LastDBDump.Results) != 2 { t.Errorf("want one row per database (2), got %d: %v", len(st.LastDBDump.Results), per) } if !st.LastDBDump.LastRun.Equal(night) { t.Errorf("the run time must come from the real dumps: %v", st.LastDBDump.LastRun) } if len(st.DumpFiles) != 5 { t.Errorf("the file list must keep every file, undo copies included (R-379): %d", len(st.DumpFiles)) } } // Only undo copies on disk: there is no run to show, so no synthesised run (a zero-time „last backup" would be a lie). func TestSynthesisedRunAbsentWhenOnlyUndoCopies(t *testing.T) { m, _ := newTestManager(t, "/srv/sys") m.cachedStatus = &FullBackupStatus{DumpFiles: []DumpFileInfo{ {StackName: "bookstack", DBType: DBTypeMariaDB, FileName: "pre-restore-20260930T113419Z-bookstack-mariadb.sql", ModTime: time.Now(), IsUndo: true}, }} if st := m.GetFullStatus(time.Time{}); st.LastDBDump != nil { t.Errorf("a run was synthesised from undo copies alone: %+v", st.LastDBDump) } }