Files
admin 06e0bc9c25 agent v0.51.0: local vzdump retention default (--prune-backups keep-last=3)
The preventive counterpart to host_disk + storage_fill detectors: the periodic local
whole-guest vzdump now prunes its own old archives (keep-last=3, clamped >=1) so a box
can't refill its own root via its own backups. Local target only — PBS never pruned
(resolved via ListStorage; fail-safe skip on unknown). Seeded in host-install.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxLA1mZurFq9kt8hneFeCs
2026-06-30 19:44:07 +02:00

73 lines
2.5 KiB
Go

package backup
import (
"context"
"sync/atomic"
"testing"
"time"
"gitea.dooplex.hu/admin/felhom-agent/internal/proxmox"
)
// 8B.2: in snapshot mode, the runner fires onSnapshot when the storage-snapshot marker appears in
// the task log — mid-backup, before completion.
func TestBackupWithSnapshotHook_FiresOnMarker(t *testing.T) {
old := snapshotWatchInterval
snapshotWatchInterval = 2 * time.Millisecond
defer func() { snapshotWatchInterval = old }()
api := &fakeBackupAPI{
vzdumpUPID: "UPID:backup",
waitGate: make(chan struct{}), // hold the backup open so the watcher gets to poll
logLines: []string{"INFO: backup mode: snapshot", "INFO: create storage snapshot 'vzdump'"},
content: []proxmox.StorageContent{{VolID: "local:backup/vzdump-lxc-9001-x", Content: "backup", VMID: 9001, Size: 100, CTime: 1}},
}
r := NewBackupRunner(api, "local", "", "", "", quiet())
var fired int32
done := make(chan struct{})
go func() {
_, _ = r.BackupWithSnapshotHook(context.Background(), 9001, func() { atomic.StoreInt32(&fired, 1) })
close(done)
}()
// the watcher should fire onSnapshot well before we release the backup
deadline := time.Now().Add(time.Second)
for time.Now().Before(deadline) && atomic.LoadInt32(&fired) == 0 {
time.Sleep(2 * time.Millisecond)
}
if atomic.LoadInt32(&fired) != 1 {
t.Fatal("onSnapshot did not fire on the storage-snapshot marker")
}
close(api.waitGate) // let the backup complete
<-done
}
// Stop/downgraded mode → no storage-snapshot marker → onSnapshot never fires (the 8B.2 fallback).
func TestBackupWithSnapshotHook_StopMode_NeverFires(t *testing.T) {
old := snapshotWatchInterval
snapshotWatchInterval = 2 * time.Millisecond
defer func() { snapshotWatchInterval = old }()
api := &fakeBackupAPI{
vzdumpUPID: "UPID:backup",
waitGate: make(chan struct{}),
logLines: []string{"INFO: backup mode: stop"}, // downgraded; no snapshot marker
content: []proxmox.StorageContent{{VolID: "local:backup/vzdump-lxc-9001-x", Content: "backup", VMID: 9001, Size: 100, CTime: 1}},
}
r := NewBackupRunner(api, "local", "", "", "", quiet())
var fired int32
done := make(chan struct{})
go func() {
_, _ = r.BackupWithSnapshotHook(context.Background(), 9001, func() { atomic.StoreInt32(&fired, 1) })
close(done)
}()
time.Sleep(40 * time.Millisecond) // the watcher polls several times + sees stop mode → returns
if atomic.LoadInt32(&fired) != 0 {
t.Fatal("onSnapshot fired in stop mode (must not)")
}
close(api.waitGate)
<-done
}