D47 / R-1269 (P2): a new install never writes into an earlier install's backup — every install has an identity (install_id), the unit records it, every unit writer asks first; another install's unit is set aside whole (backups/set-aside/<app>/<stamp>, a D25 kept copy, „Visszaállítás” + „Eltávolítás” on the restore page); a move that fails refuses the write. Red-proved. Commit only.
gates / gates (push) Successful in 1m33s
gates / gates (push) Successful in 1m33s
This commit is contained in:
@@ -95,3 +95,71 @@ func TestD25_RemoveHandlerRemovesOnlyTheRecordedCopy(t *testing.T) {
|
||||
t.Fatalf("another copy was touched: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// D47 (2026-10-25): a set-aside unit of an earlier install is a kept copy with „Visszaállítás" beside „Eltávolítás";
|
||||
// a second-drive copy is not restorable from this list (render test per branch of {{if .Restorable}}).
|
||||
func TestD47_RestorePageOffersRestoreOnlyForASetAsideUnit(t *testing.T) {
|
||||
d := i18nLayoutData("backups-restore", "Visszaállítás a mentésből")
|
||||
d["Backup"] = i18nBackupStatus(false, false)
|
||||
d["OffboxConfigured"] = true
|
||||
d["OffsiteStoreState"] = "known"
|
||||
d["KeptCopies"] = []keptCopyRow{
|
||||
{ID: "aaaaaaaaaaaaaaaa", Source: "tandoor", Line: "a(z) belso meghajtóról megőrzött másolat · egy korábbi telepítés mentése (újratelepítés előtt készült)", SizeHuman: "150 MB", Since: "2026-10-25T08:00:00Z", Restorable: true},
|
||||
{ID: "bbbbbbbbbbbbbbbb", Source: "csaladi_fotok", Line: "a(z) hdd_3 meghajtóról megőrzött másolat · a meghajtó nincs csatlakoztatva", SizeHuman: "1.2 GB", Since: "2026-10-21T12:00:00Z"},
|
||||
}
|
||||
d["KeptUnitRestorable"] = true
|
||||
html := renderBackupPage(t, "backups_restore", d)
|
||||
if n := strings.Count(html, `action="/backup/kept/restore"`); n != 1 {
|
||||
t.Fatalf("exactly the set-aside unit's row offers the restore, found %d", n)
|
||||
}
|
||||
i := strings.Index(html, `action="/backup/kept/restore"`)
|
||||
if !strings.Contains(html[i:i+300], `value="aaaaaaaaaaaaaaaa"`) || !strings.Contains(html, "confirmRestoreKeptUnit(this)") {
|
||||
t.Fatal("the restore form must name the set-aside unit's record and ask first")
|
||||
}
|
||||
if strings.Count(html, `action="/backup/kept/remove"`) != 2 {
|
||||
t.Fatal("both rows keep the remove button")
|
||||
}
|
||||
}
|
||||
|
||||
// The restore handler names a set-aside unit ONLY by its record: no confirm → refused; an unknown id → not found; a
|
||||
// second-drive copy's id is not a unit → not found (nothing starts).
|
||||
func TestD47_KeptUnitRestoreHandlerRefusals(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
lg := log.New(io.Discard, "", 0)
|
||||
sett, err := settings.Load(filepath.Join(tmp, "settings.json"), lg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
share := filepath.Join(tmp, "hdd_1", "backups", "secondary", "_shares", "hdd_3", "csaladi_fotok")
|
||||
if err := os.MkdirAll(share, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := os.Stat(share)
|
||||
sys := st.Sys().(*syscall.Stat_t)
|
||||
if err := sett.UpsertKeptCopy(settings.KeptCopy{Kind: "share", Source: "csaladi_fotok", Drive: "hdd_3", Reason: "drive_away",
|
||||
DestBase: filepath.Dir(filepath.Dir(share)), Path: share, Dev: uint64(sys.Dev), Ino: sys.Ino}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg := &config.Config{}
|
||||
cfg.Paths.DataDir = tmp
|
||||
s := &Server{cfg: cfg, backupMgr: backup.NewManager(cfg, sett, lg), logger: lg}
|
||||
post := func(form string) string {
|
||||
rr := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("POST", "/backup/kept/restore", strings.NewReader(form))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
s.keptUnitRestoreHandler(rr, req)
|
||||
return rr.Header().Get("Location")
|
||||
}
|
||||
if loc := post("id=x"); !strings.Contains(loc, "flash.kept.restore_needs_confirmation") {
|
||||
t.Fatalf("no confirm → %q", loc)
|
||||
}
|
||||
if loc := post("id=ffffffffffffffff&confirm=1"); !strings.Contains(loc, "flash.kept.not_found") {
|
||||
t.Fatalf("unknown id → %q", loc)
|
||||
}
|
||||
if loc := post("id=" + settings.KeptCopyID(share) + "&confirm=1"); !strings.Contains(loc, "flash.kept.not_found") {
|
||||
t.Fatalf("a second-drive copy is not a restorable unit → %q", loc)
|
||||
}
|
||||
if s.backupMgr.RestoreStatus().Running {
|
||||
t.Fatal("a refusal must start nothing")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user