db25b469ba
gates / gates (push) Successful in 1m7s
Found in the 2026-10-09 kernel-night read-back: - demo-felhom: the kernel step restarted the host 4 minutes after the night backup; the in-memory backup list was empty after the restart, so the hub alarmed "host tier: newest backup is 48h old". The report now adds R-894's saved newest success per tier (one shared instance). - demo-hp: proxmox-secure-boot-support pulled shim-signed-common into the ring-0 Proxmox plan; the step was refused R6 and the kernel step skipped. It joins HOST_SLOW_RE with shim and GRUB. Red-proved: TestCollectBackups_SavedSuccessSurvivesARestart, TestR894_LastKnownBackupsIsWiredIntoTheDaemon, test_ring0_pending_pve_leaves_the_secure_boot_meta_out. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
63 lines
2.8 KiB
Go
63 lines
2.8 KiB
Go
package hub
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
type fakeMemBackups []Backup
|
|
|
|
func (f fakeMemBackups) Backups(context.Context) []Backup { return f }
|
|
|
|
type fakeKnownBackups []Backup
|
|
|
|
func (f fakeKnownBackups) KnownBackupSuccesses() []Backup { return f }
|
|
|
|
// The consequence, not the mechanism: after a restart (empty in-memory list) the host report still carries
|
|
// the night's backup, so the hub's freshness check sees it. Measured 2026-10-09 on demo-felhom: without this
|
|
// the report carried backups: [] and the hub alarmed „newest backup is 48h old" an hour after a good backup.
|
|
// RED-PROOF: return before the saved-success loop in collectBackups → the first case reports nothing → fails.
|
|
func TestCollectBackups_SavedSuccessSurvivesARestart(t *testing.T) {
|
|
saved := Backup{TargetID: "felhom-backup", VMID: 9201, Success: true, StartedAt: "2026-10-09T02:40:16Z"}
|
|
|
|
t.Run("restart: memory empty, the saved success is reported", func(t *testing.T) {
|
|
c := &Collector{backups: fakeMemBackups(nil), knownBackups: fakeKnownBackups{saved}}
|
|
got := c.collectBackups(context.Background())
|
|
if len(got) != 1 || got[0].StartedAt != saved.StartedAt || !got[0].Success || got[0].TargetID != "felhom-backup" {
|
|
t.Fatalf("want the saved success, got %+v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("memory holds the same or a newer success: no second entry", func(t *testing.T) {
|
|
mem := Backup{TargetID: "felhom-backup", VMID: 9201, Success: true, StartedAt: "2026-10-09T02:40:16Z", Archive: "a"}
|
|
c := &Collector{backups: fakeMemBackups{mem}, knownBackups: fakeKnownBackups{saved}}
|
|
if got := c.collectBackups(context.Background()); len(got) != 1 || got[0].Archive != "a" {
|
|
t.Fatalf("want only the in-memory record, got %+v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("a newer FAILURE in memory never hides the saved success, and is kept", func(t *testing.T) {
|
|
fail := Backup{TargetID: "felhom-backup", VMID: 9201, Success: false, StartedAt: "2026-10-10T02:40:00Z", Error: "x"}
|
|
c := &Collector{backups: fakeMemBackups{fail}, knownBackups: fakeKnownBackups{saved}}
|
|
got := c.collectBackups(context.Background())
|
|
if len(got) != 2 || got[0].Success || !got[1].Success {
|
|
t.Fatalf("want the failure and the saved success, got %+v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("another tier's success does not cover this tier", func(t *testing.T) {
|
|
other := Backup{TargetID: "felhom-pbs", VMID: 9201, Success: true, StartedAt: "2026-10-10T00:00:00Z"}
|
|
c := &Collector{backups: fakeMemBackups{other}, knownBackups: fakeKnownBackups{saved}}
|
|
if got := c.collectBackups(context.Background()); len(got) != 2 {
|
|
t.Fatalf("want both tiers, got %+v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("no saved state wired: the in-memory list as before, never nil", func(t *testing.T) {
|
|
c := &Collector{}
|
|
if got := c.collectBackups(context.Background()); got == nil || len(got) != 0 {
|
|
t.Fatalf("want an empty non-nil list, got %#v", got)
|
|
}
|
|
})
|
|
}
|