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 }