package restoretest import ( "context" "os" "os/exec" "path/filepath" "testing" "time" "gitea.perlbach24.de/scripte/nexarch/archive/internal/backup" "gitea.perlbach24.de/scripte/nexarch/archive/internal/objectbackup" ) func requireDBTestConfig(t *testing.T) backup.Config { t.Helper() user := os.Getenv("TEST_BACKUP_PG_USER") if user == "" { t.Skip("TEST_BACKUP_PG_USER nicht gesetzt, Integrationstest uebersprungen") } if _, err := exec.LookPath("pg_combinebackup"); err != nil { t.Skip("pg_combinebackup nicht installiert, Integrationstest uebersprungen") } if _, err := exec.LookPath("pg_ctl"); err != nil { t.Skip("pg_ctl nicht installiert, Integrationstest uebersprungen") } return backup.Config{ Host: envOrT("TEST_BACKUP_PG_HOST", "localhost"), Port: envOrT("TEST_BACKUP_PG_PORT", "5432"), User: user, Password: os.Getenv("TEST_BACKUP_PG_PASSWORD"), BackupDir: t.TempDir(), } } func envOrT(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } // TestRunDatabaseTest_SucceedsAgainstRealBackup ist Pruefung 1: geplanter // Testlauf gegen aktuelle Sicherung erfolgreich durchgefuehrt. func TestRunDatabaseTest_SucceedsAgainstRealBackup(t *testing.T) { cfg := requireDBTestConfig(t) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() genID := backup.NewGenerationID(time.Now()) if _, err := backup.FullBackup(ctx, cfg, genID); err != nil { t.Fatalf("fullbackup: %v", err) } res := RunDatabaseTest(ctx, cfg, PgConfig{TestPort: "55434"}, t.TempDir()) if !res.Success { t.Fatalf("erwartet erfolgreichen testlauf, habe: %+v", res) } if res.Source != genID { t.Fatalf("source = %q, want %q", res.Source, genID) } } // TestRunDatabaseTest_DetectsCorruptedBackup ist Pruefung 2: absichtlich // beschaedigte Sicherung laesst den Testlauf sichtbar fehlschlagen. func TestRunDatabaseTest_DetectsCorruptedBackup(t *testing.T) { cfg := requireDBTestConfig(t) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() genID := backup.NewGenerationID(time.Now()) manifest, err := backup.FullBackup(ctx, cfg, genID) if err != nil { t.Fatalf("fullbackup: %v", err) } // Absichtliche Beschaedigung: base.tar.gz durch Muell ersetzen. tarPath := filepath.Join(filepath.Dir(manifest), backup.BaseTarGzFile) if err := os.WriteFile(tarPath, []byte("das ist kein gueltiges tar.gz"), 0o600); err != nil { t.Fatal(err) } res := RunDatabaseTest(ctx, cfg, PgConfig{TestPort: "55435"}, t.TempDir()) if res.Success { t.Fatal("erwartet fehlschlag bei beschaedigter sicherung, testlauf meldete erfolg") } if res.Detail == "" { t.Fatal("erwartet aussagekraeftiges detail zum fehlschlag") } } func requireObjTestConfig(t *testing.T) objectbackup.Config { t.Helper() if _, err := exec.LookPath("restic"); err != nil { t.Skip("restic nicht installiert, Integrationstest uebersprungen") } cfg := objectbackup.Config{RepoDir: filepath.Join(t.TempDir(), "repo"), Password: "restoretest-passwort"} if err := objectbackup.InitRepo(context.Background(), cfg); err != nil { t.Fatalf("initrepo: %v", err) } return cfg } // TestRunObjectTest_SucceedsAgainstRealSnapshot ist Pruefung 1 fuer den // Objekt-Storage-Teil. func TestRunObjectTest_SucceedsAgainstRealSnapshot(t *testing.T) { cfg := requireObjTestConfig(t) ctx := context.Background() sourceDir := t.TempDir() if err := os.WriteFile(filepath.Join(sourceDir, "datei.txt"), []byte("inhalt"), 0o600); err != nil { t.Fatal(err) } if _, err := objectbackup.Backup(ctx, cfg, sourceDir); err != nil { t.Fatalf("backup: %v", err) } res := RunObjectTest(ctx, cfg, t.TempDir()) if !res.Success { t.Fatalf("erwartet erfolgreichen testlauf, habe: %+v", res) } }