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

56 lines
2.2 KiB
Go

package backup
import (
"path/filepath"
"strings"
"testing"
"time"
)
// R-1178 (data-loss hunt 2026-10-20, R5): the second drive's „Teljes visszaállítás" merged files, THEN the unit half
// refused (a cut-off database copy), left the app STOPPED, and said „az alkalmazás és az adatai érintetlenek". Now the
// unit's refusals are asked before the file half: nothing moves, the app is never stopped, and the sentence is true.
// RED-PROOF: without the CheckOnly pre-check in RestoreTier2Whole this fails on „files changed before the refusal"
// (1 restored + 1 replaced, the measured R5 outcome — audits/dataloss-hunt-2026-10-20/C3-R5-whole-restore/).
func TestR1178_AUnitRefusalComesBeforeAnyFileMoves(t *testing.T) {
cut := strings.Replace(pgDump(1), "PostgreSQL database dump complete", "", 1) // a cut-off copy (R-640)
f := r102Tier2Fixture(t, []string{"app_data.tar"}, cut)
f.m.stackProvider = fileAppProvider{f.fake}
mid := time.Date(2026, 9, 22, 10, 0, 0, 0, time.UTC)
mirrorLeg := filepath.Join(f.destBase, "hdd", "appdata", "app")
liveLeg := filepath.Join(f.liveDrive, "appdata", "app")
writeAt(t, filepath.Join(mirrorLeg, "p1.jpg"), "P1", mid)
writeAt(t, filepath.Join(mirrorLeg, "p2.jpg"), "P2 mirror NEWER", mid.Add(72*time.Hour))
writeAt(t, filepath.Join(liveLeg, "p2.jpg"), "P2 live older", mid.Add(48*time.Hour))
before := fingerprint(t, liveLeg)
res, err := f.m.RestoreTier2Whole("app")
if err == nil {
t.Fatal("a cut-off database copy must refuse the whole restore")
}
if res.Files.Restored+res.Files.Replaced != 0 {
t.Fatalf("files changed before the refusal: %+v", res.Files)
}
if after := fingerprint(t, liveLeg); !sameFingerprint(before, after) {
t.Fatalf("the live files changed: before %v after %v", before, after)
}
if f.fake.stopped {
t.Fatalf("the app was stopped by a restore that refused — calls %v", f.fake.calls)
}
if !strings.Contains(err.Error(), "rintetlenek") { // „érintetlenek" — now true
t.Fatalf("the refusal must keep its „untouched\" sentence (true now), got %v", err)
}
}
func sameFingerprint(a, b map[string]string) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if b[k] != v {
return false
}
}
return true
}