Ctrl K
ComunidadGuías…

internal/server/backup_schedule_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// 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")
	}
}