package backup import ( "testing" "time" ) // drivePathProvider puts every app on /mnt/felhom-drives/hdd_1 (the measured R-897 case). type drivePathProvider struct{ unitFailProvider } func (p *drivePathProvider) GetStackHDDPath(string) string { return "/mnt/felhom-drives/hdd_1" } // R-897: right after a boot, a capture for an app on a drive waits until the drive's bind is LIVE. The drive reads // not-bound, then bound → the capture (here a capture that fails, so it is visible as a unit event) starts only after. // COMPANION RED-PROOF (observed): remove the driveReady call in captureAllRecoveryUnits → "captured while the drive // was not bound". func TestDriveReady_RefreshWaitsForTheBindThenCaptures(t *testing.T) { m, got := newUnitNotifyManager(t, []string{"calibre-web"}, map[string]bool{"calibre-web": true}) base := m.stackProvider.(*unitFailProvider) m.stackProvider = &drivePathProvider{*base} now := time.Date(2026, 10, 7, 15, 16, 28, 0, time.UTC) m.startedAt, m.nowFn = now.Add(-20*time.Second), func() time.Time { return now } bound := false var asked []string m.driveLive = func(root string) bool { asked = append(asked, root); return bound } m.captureAllRecoveryUnits(false) if len(*got) != 0 { t.Fatalf("captured while the drive was not bound: %+v", *got) } if len(asked) == 0 || asked[0] != "/mnt/felhom-drives/hdd_1" { t.Fatalf("the drive root asked = %v", asked) } bound = true m.captureAllRecoveryUnits(false) if len(*got) != 1 { t.Fatalf("after the bind the capture must run: %+v", *got) } } // After the window the capture runs whatever the bind says (and says so). func TestDriveReady_AfterTheWindowItRunsAnyway(t *testing.T) { m, got := newUnitNotifyManager(t, []string{"calibre-web"}, map[string]bool{"calibre-web": true}) base := m.stackProvider.(*unitFailProvider) m.stackProvider = &drivePathProvider{*base} now := time.Date(2026, 10, 7, 15, 30, 0, 0, time.UTC) m.startedAt, m.nowFn = now.Add(-DriveWaitWindow), func() time.Time { return now } m.driveLive = func(string) bool { return false } m.captureAllRecoveryUnits(false) if len(*got) != 1 { t.Fatalf("after %s the capture must run anyway: %+v", DriveWaitWindow, *got) } } // A data run WAITS (polls) instead of skipping; a non-drive path and a Manager without a start time never wait. func TestDriveReady_DataRunPollsAndOthersNeverWait(t *testing.T) { m, _ := newUnitNotifyManager(t, nil, nil) now := time.Date(2026, 10, 7, 15, 16, 28, 0, time.UTC) m.startedAt, m.nowFn = now, func() time.Time { return now } n := 0 m.driveLive = func(string) bool { n++; return n >= 3 } polls := 0 m.driveWaitPoll = func(d time.Duration) { polls++; now = now.Add(d) } if !m.driveReady("/mnt/felhom-drives/hdd_1/x", true) || polls != 2 { t.Fatalf("data run: polls=%d", polls) } if !m.driveReady("/var/lib/felhom/system-data", false) { t.Fatal("the system SSD never waits") } m2, _ := newUnitNotifyManager(t, nil, nil) m2.driveLive = func(string) bool { return false } if !m2.driveReady("/mnt/felhom-drives/hdd_1", false) { t.Fatal("no start time → no wait") } if driveRootOf("/mnt/felhom-drives/") != "" || driveRootOf("/mnt/felhom-drives/hdd_2/a/b") != "/mnt/felhom-drives/hdd_2" { t.Fatal("driveRootOf") } }