internal/server/backup_schedule_test.go
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: Apache-2.0
package server
import (
"os"
"path/filepath"
"testing"
"time"
appdb "github.com/X4Applegate/caddyui/internal/db"
)
func TestLoadBackupScheduleConfig(t *testing.T) {
vals := map[string]string{
settingBackupScheduleEnabled: "1",
settingBackupScheduleDir: " /backups ",
settingBackupScheduleInterval: "24",
settingBackupScheduleKeep: "7",
}
cfg := loadBackupScheduleConfig(func(k string) string { return vals[k] })
if !cfg.Enabled || cfg.Dir != "/backups" || cfg.IntervalHours != 24 || cfg.Keep != 7 {
t.Fatalf("cfg = %+v", cfg)
}
// Disabled + junk numbers default to zero.
cfg = loadBackupScheduleConfig(func(k string) string {
if k == settingBackupScheduleInterval {
return "nope"
}
return ""
})
if cfg.Enabled || cfg.Dir != "" || cfg.IntervalHours != 0 || cfg.Keep != 0 {
t.Fatalf("empty cfg = %+v", cfg)
}
}
func TestPruneBackupsKeepsNewest(t *testing.T) {
dir := t.TempDir()
base := time.Now().Add(-10 * time.Hour)
// Create 5 backups with increasing mod times: bk0 oldest … bk4 newest.
for i := 0; i < 5; i++ {
p := filepath.Join(dir, backupFilePrefix+string(rune('a'+i))+backupFileSuffix)
if err := os.WriteFile(p, []byte("x"), 0o640); err != nil {
t.Fatal(err)
}
mt := base.Add(time.Duration(i) * time.Hour)
if err := os.Chtimes(p, mt, mt); err != nil {
t.Fatal(err)
}
}
// A non-backup file must never be touched.
other := filepath.Join(dir, "keepme.txt")
_ = os.WriteFile(other, []byte("x"), 0o640)
pruneBackups(dir, 2)
remaining := backupFiles(dir)
if len(remaining) != 2 {
t.Fatalf("kept %d backups, want 2", len(remaining))
}
// The two newest (e, d) must survive; ordered newest-first.
if remaining[0].Name() != backupFilePrefix+"e"+backupFileSuffix || remaining[1].Name() != backupFilePrefix+"d"+backupFileSuffix {
t.Fatalf("kept the wrong files: %s, %s", remaining[0].Name(), remaining[1].Name())
}
if _, err := os.Stat(other); err != nil {
t.Fatalf("non-backup file was removed: %v", err)
}
// keep=0 keeps everything.
pruneBackups(dir, 0)
if len(backupFiles(dir)) != 2 {
t.Fatalf("keep=0 should not prune")
}
}
func TestRunScheduledBackupOnce(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "caddyui.db")
conn, err := appdb.Open(dbPath)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = conn.Close() })
s := &Server{DB: conn, DBPath: dbPath}
dir := filepath.Join(t.TempDir(), "backups")
// Three backups, keep 2 → the oldest is pruned.
var last string
for i := 0; i < 3; i++ {
p, err := s.runScheduledBackupOnce(dir, 2)
if err != nil {
t.Fatal(err)
}
last = p
if fi, err := os.Stat(p); err != nil || fi.Size() == 0 {
t.Fatalf("backup %q not written: %v", p, err)
}
time.Sleep(1100 * time.Millisecond) // distinct second-resolution timestamps
}
files := backupFiles(dir)
if len(files) != 2 {
t.Fatalf("kept %d backups, want 2", len(files))
}
if filepath.Base(last) != files[0].Name() {
t.Fatalf("newest backup %q not first in %v", filepath.Base(last), files[0].Name())
}
// newestBackupModTime should be recent.
if time.Since(newestBackupModTime(dir)) > time.Minute {
t.Fatalf("newestBackupModTime looks stale")
}
}