Files
dbbackup/internal/checks/preflight_test.go
Alexander Renz d0d83b61ef feat: add dry-run mode, GFS retention policies, and notifications
- Add --dry-run/-n flag for backup commands with comprehensive preflight checks
  - Database connectivity validation
  - Required tools availability check
  - Storage target and permissions verification
  - Backup size estimation
  - Encryption and cloud storage configuration validation

- Implement GFS (Grandfather-Father-Son) retention policies
  - Daily/Weekly/Monthly/Yearly tier classification
  - Configurable retention counts per tier
  - Custom weekly day and monthly day settings
  - ISO week handling for proper week boundaries

- Add notification system with SMTP and webhook support
  - SMTP email notifications with TLS/STARTTLS
  - Webhook HTTP notifications with HMAC-SHA256 signing
  - Slack-compatible webhook payload format
  - Event types: backup/restore started/completed/failed, cleanup, verify, PITR
  - Configurable severity levels and retry logic

- Update README.md with documentation for all new features
2025-12-13 19:00:54 +01:00

135 lines
2.9 KiB
Go

package checks
import (
"testing"
)
func TestPreflightResult(t *testing.T) {
result := &PreflightResult{
Checks: []PreflightCheck{},
AllPassed: true,
DatabaseInfo: &DatabaseInfo{
Type: "postgres",
Version: "PostgreSQL 15.0",
Host: "localhost",
Port: 5432,
User: "postgres",
},
StorageInfo: &StorageInfo{
Type: "local",
Path: "/backups",
AvailableBytes: 10 * 1024 * 1024 * 1024,
TotalBytes: 100 * 1024 * 1024 * 1024,
},
EstimatedSize: 1 * 1024 * 1024 * 1024,
}
if !result.AllPassed {
t.Error("Result should be AllPassed")
}
if result.DatabaseInfo.Type != "postgres" {
t.Errorf("DatabaseInfo.Type = %q, expected postgres", result.DatabaseInfo.Type)
}
if result.StorageInfo.Path != "/backups" {
t.Errorf("StorageInfo.Path = %q, expected /backups", result.StorageInfo.Path)
}
}
func TestPreflightCheck(t *testing.T) {
check := PreflightCheck{
Name: "Database Connectivity",
Status: StatusPassed,
Message: "Connected successfully",
Details: "PostgreSQL 15.0",
}
if check.Status != StatusPassed {
t.Error("Check status should be passed")
}
if check.Name != "Database Connectivity" {
t.Errorf("Check name = %q", check.Name)
}
}
func TestCheckStatusString(t *testing.T) {
tests := []struct {
status CheckStatus
expected string
}{
{StatusPassed, "PASSED"},
{StatusFailed, "FAILED"},
{StatusWarning, "WARNING"},
{StatusSkipped, "SKIPPED"},
}
for _, tc := range tests {
result := tc.status.String()
if result != tc.expected {
t.Errorf("Status.String() = %q, expected %q", result, tc.expected)
}
}
}
func TestFormatPreflightReport(t *testing.T) {
result := &PreflightResult{
Checks: []PreflightCheck{
{Name: "Test Check", Status: StatusPassed, Message: "OK"},
},
AllPassed: true,
DatabaseInfo: &DatabaseInfo{
Type: "postgres",
Version: "PostgreSQL 15.0",
Host: "localhost",
Port: 5432,
},
StorageInfo: &StorageInfo{
Type: "local",
Path: "/backups",
AvailableBytes: 10 * 1024 * 1024 * 1024,
},
}
report := FormatPreflightReport(result, "testdb", false)
if report == "" {
t.Error("Report should not be empty")
}
}
func TestFormatPreflightReportPlain(t *testing.T) {
result := &PreflightResult{
Checks: []PreflightCheck{
{Name: "Test Check", Status: StatusFailed, Message: "Connection failed"},
},
AllPassed: false,
FailureCount: 1,
}
report := FormatPreflightReportPlain(result, "testdb")
if report == "" {
t.Error("Report should not be empty")
}
}
func TestFormatPreflightReportJSON(t *testing.T) {
result := &PreflightResult{
Checks: []PreflightCheck{},
AllPassed: true,
}
report, err := FormatPreflightReportJSON(result, "testdb")
if err != nil {
t.Errorf("FormatPreflightReportJSON() error = %v", err)
}
if len(report) == 0 {
t.Error("Report should not be empty")
}
if report[0] != '{' {
t.Error("Report should start with '{'")
}
}