Files
felhom-controller/controller/internal/backup/r1181_app_legs_kept_test.go
T

62 lines
2.3 KiB
Go

package backup
import (
"os"
"os/exec"
"path/filepath"
"testing"
)
// R-1181 + D25 for app folders — the data-loss hunt's C3 case (felhom.eu audits/dataloss-hunt-2026-10-20/
// C3-D2-missing-leg/), asserting: a MISSING declared folder keeps its second-drive copy and is listed as kept; an
// EMPTIED folder is not mirrored over its full copy (the production `rsync -a --delete` mirror is used when present).
func TestR1181_MissingAndEmptiedAppFoldersKeepTheirCopies(t *testing.T) {
m, src, target, prov := newTier2V2(t, "app")
if _, err := exec.LookPath("rsync"); err == nil {
m.tier2Mirror = rsyncMirror
}
prov.has["app"] = true
prov.binds["app"] = []ClassifiedBind{mHDD("appdata/app/photos"), mHDD("appdata/app/docs")}
mustWrite(t, filepath.Join(src, "appdata", "app", "photos", "family.jpg"), "PHOTO")
mustWrite(t, filepath.Join(src, "appdata", "app", "docs", "contract.pdf"), "PDF")
if err := m.RunTier2("app"); err != nil {
t.Fatal(err)
}
destBase := filepath.Join(target, "backups", "secondary", "app")
photo := filepath.Join(destBase, "hdd", "appdata", "app", "photos", "family.jpg")
doc := filepath.Join(destBase, "hdd", "appdata", "app", "docs", "contract.pdf")
if !exists(photo) || !exists(doc) {
t.Fatal("precondition: run 1 did not copy both folders")
}
if err := os.RemoveAll(filepath.Join(src, "appdata", "app", "photos")); err != nil {
t.Fatal(err)
}
if err := os.Remove(filepath.Join(src, "appdata", "app", "docs", "contract.pdf")); err != nil {
t.Fatal(err)
}
if err := m.RunTier2("app"); err != nil {
t.Fatal(err)
}
if !exists(photo) {
t.Fatal("the MISSING folder's second-drive copy was deleted (R-1181)")
}
if !exists(doc) {
t.Fatal("the EMPTIED folder was mirrored over its full copy (R-1181)")
}
kept := m.KeptCopies()
if len(kept) != 1 || kept[0].Kind != "app" || kept[0].Reason != "folder_missing" {
t.Fatalf("kept copies = %+v, want the photos folder", kept)
}
if cd := m.settings.GetCrossDriveConfig("app"); cd == nil || cd.LastWarning == "" {
t.Fatalf("the run did not warn: %+v", cd)
}
// The folder comes back: mirrored again, the record goes.
mustWrite(t, filepath.Join(src, "appdata", "app", "photos", "family.jpg"), "PHOTO")
if err := m.RunTier2("app"); err != nil {
t.Fatal(err)
}
if len(m.KeptCopies()) != 0 {
t.Fatalf("the record outlived the folder's return: %+v", m.KeptCopies())
}
}