veza/veza-backend-api/internal/services/backup_service_test.go
senke a6cf20e614 fix(tests): fix 2 skipped tests, add clear skip reasons to 11 others
INT-04: Fixed nil UserID panic in AuditService (re-enabled 2 tests).
Added INT-04 comments explaining skip reasons for tests requiring
PostgreSQL, real file headers, or external services.
2026-02-22 17:53:00 +01:00

363 lines
9.5 KiB
Go

package services
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)
func setupTestBackupService(t *testing.T) (*BackupService, string, func()) {
tmpDir, err := os.MkdirTemp("", "backup_test_*")
require.NoError(t, err)
config := BackupConfig{
BackupDir: tmpDir,
RetentionDays: 7,
DatabaseName: "test_db",
DatabaseHost: "localhost",
DatabasePort: "5432",
DatabaseUser: "test_user",
}
logger := zap.NewNop()
service, err := NewBackupService(config, logger)
require.NoError(t, err)
cleanup := func() {
os.RemoveAll(tmpDir)
}
return service, tmpDir, cleanup
}
func TestBackupService_NewBackupService_Success(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "backup_test_*")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
config := BackupConfig{
BackupDir: tmpDir,
RetentionDays: 30,
DatabaseName: "test_db",
}
logger := zap.NewNop()
service, err := NewBackupService(config, logger)
assert.NoError(t, err)
assert.NotNil(t, service)
assert.Equal(t, tmpDir, service.backupDir)
assert.Equal(t, 30, service.retentionDays)
assert.Equal(t, "test_db", service.databaseName)
}
func TestBackupService_NewBackupService_CreatesDirectory(t *testing.T) {
tmpDir := filepath.Join(os.TempDir(), "backup_test_new_*")
defer os.RemoveAll(tmpDir)
config := BackupConfig{
BackupDir: tmpDir,
RetentionDays: 30,
DatabaseName: "test_db",
}
logger := zap.NewNop()
service, err := NewBackupService(config, logger)
assert.NoError(t, err)
assert.NotNil(t, service)
// Verify directory was created
info, err := os.Stat(tmpDir)
assert.NoError(t, err)
assert.True(t, info.IsDir())
}
func TestBackupService_NewBackupService_DefaultRetentionDays(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "backup_test_*")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
config := BackupConfig{
BackupDir: tmpDir,
RetentionDays: 0, // Should default to 30
DatabaseName: "test_db",
}
logger := zap.NewNop()
service, err := NewBackupService(config, logger)
assert.NoError(t, err)
assert.NotNil(t, service)
assert.Equal(t, 30, service.retentionDays)
}
func TestBackupService_NewBackupService_NegativeRetentionDays(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "backup_test_*")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
config := BackupConfig{
BackupDir: tmpDir,
RetentionDays: -5, // Should default to 30
DatabaseName: "test_db",
}
logger := zap.NewNop()
service, err := NewBackupService(config, logger)
assert.NoError(t, err)
assert.NotNil(t, service)
assert.Equal(t, 30, service.retentionDays)
}
func TestBackupService_CleanupOldBackups_NoBackups(t *testing.T) {
service, _, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
err := service.CleanupOldBackups(ctx)
assert.NoError(t, err)
}
func TestBackupService_CleanupOldBackups_DeletesOldBackups(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create old backup file (older than retention period)
oldTime := time.Now().AddDate(0, 0, -10) // 10 days ago
oldBackupPath := filepath.Join(backupDir, "test_db_20200101_000000.sql")
oldFile, err := os.Create(oldBackupPath)
require.NoError(t, err)
oldFile.Close()
// Set modification time to old time
err = os.Chtimes(oldBackupPath, oldTime, oldTime)
require.NoError(t, err)
// Create recent backup file (within retention period)
recentBackupPath := filepath.Join(backupDir, "test_db_20231228_120000.sql")
recentFile, err := os.Create(recentBackupPath)
require.NoError(t, err)
recentFile.Close()
// Run cleanup
err = service.CleanupOldBackups(ctx)
assert.NoError(t, err)
// Verify old backup was deleted
_, err = os.Stat(oldBackupPath)
assert.True(t, os.IsNotExist(err))
// Verify recent backup still exists
_, err = os.Stat(recentBackupPath)
assert.NoError(t, err)
}
func TestBackupService_CleanupOldBackups_IgnoresNonBackupFiles(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create a non-backup file
otherFile := filepath.Join(backupDir, "other_file.txt")
err := os.WriteFile(otherFile, []byte("test"), 0644)
require.NoError(t, err)
// Run cleanup
err = service.CleanupOldBackups(ctx)
assert.NoError(t, err)
// Verify non-backup file still exists
_, err = os.Stat(otherFile)
assert.NoError(t, err)
}
func TestBackupService_CleanupOldBackups_IgnoresDirectories(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create a subdirectory
subDir := filepath.Join(backupDir, "subdir")
err := os.MkdirAll(subDir, 0755)
require.NoError(t, err)
// Run cleanup
err = service.CleanupOldBackups(ctx)
assert.NoError(t, err)
// Verify subdirectory still exists
_, err = os.Stat(subDir)
assert.NoError(t, err)
}
func TestBackupService_CleanupOldBackups_HandlesDumpFiles(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create old .dump file
oldTime := time.Now().AddDate(0, 0, -10)
oldBackupPath := filepath.Join(backupDir, "test_db_20200101_000000.dump")
oldFile, err := os.Create(oldBackupPath)
require.NoError(t, err)
oldFile.Close()
err = os.Chtimes(oldBackupPath, oldTime, oldTime)
require.NoError(t, err)
// Run cleanup
err = service.CleanupOldBackups(ctx)
assert.NoError(t, err)
// Verify old .dump file was deleted
_, err = os.Stat(oldBackupPath)
assert.True(t, os.IsNotExist(err))
}
func TestBackupService_ListBackups_Empty(t *testing.T) {
service, _, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
backups, err := service.ListBackups(ctx)
assert.NoError(t, err)
if backups == nil {
backups = []BackupInfo{} // Initialize empty slice if nil
}
assert.Len(t, backups, 0)
}
func TestBackupService_ListBackups_WithBackups(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create backup files
backup1 := filepath.Join(backupDir, "test_db_20231228_120000.sql")
err := os.WriteFile(backup1, []byte("backup1"), 0644)
require.NoError(t, err)
backup2 := filepath.Join(backupDir, "test_db_20231228_130000.dump")
err = os.WriteFile(backup2, []byte("backup2"), 0644)
require.NoError(t, err)
// Create non-backup file (should be ignored)
otherFile := filepath.Join(backupDir, "other.txt")
err = os.WriteFile(otherFile, []byte("other"), 0644)
require.NoError(t, err)
// List backups
backups, err := service.ListBackups(ctx)
assert.NoError(t, err)
assert.Len(t, backups, 2)
// Verify backup files are listed
backupNames := make(map[string]bool)
for _, backup := range backups {
backupNames[backup.FileName] = true
assert.NotEmpty(t, backup.FilePath)
assert.Greater(t, backup.Size, int64(0))
assert.NotZero(t, backup.CreatedAt)
}
assert.True(t, backupNames["test_db_20231228_120000.sql"])
assert.True(t, backupNames["test_db_20231228_130000.dump"])
}
func TestBackupService_ListBackups_IgnoresDirectories(t *testing.T) {
service, backupDir, cleanup := setupTestBackupService(t)
defer cleanup()
ctx := context.Background()
// Create subdirectory
subDir := filepath.Join(backupDir, "subdir")
err := os.MkdirAll(subDir, 0755)
require.NoError(t, err)
// Create backup file
backup1 := filepath.Join(backupDir, "test_db_20231228_120000.sql")
err = os.WriteFile(backup1, []byte("backup1"), 0644)
require.NoError(t, err)
// List backups
backups, err := service.ListBackups(ctx)
assert.NoError(t, err)
assert.Len(t, backups, 1)
assert.Equal(t, "test_db_20231228_120000.sql", backups[0].FileName)
}
func TestBackupService_CreateBackup_RequiresPostgreSQL(t *testing.T) {
// INT-04: Skip - requires PostgreSQL and pg_dump CLI binary; external dependency.
t.Skip("requires PostgreSQL and pg_dump command")
}
func TestBackupService_BackupResult_Fields(t *testing.T) {
result := &BackupResult{
Success: true,
BackupPath: "/path/to/backup.sql",
BackupSize: 1024,
Duration: 5 * time.Second,
ErrorMessage: "",
CreatedAt: time.Now(),
}
assert.True(t, result.Success)
assert.Equal(t, "/path/to/backup.sql", result.BackupPath)
assert.Equal(t, int64(1024), result.BackupSize)
assert.Equal(t, 5*time.Second, result.Duration)
assert.Empty(t, result.ErrorMessage)
assert.NotZero(t, result.CreatedAt)
}
func TestBackupService_BackupInfo_Fields(t *testing.T) {
info := BackupInfo{
FileName: "test_db_20231228_120000.sql",
FilePath: "/path/to/test_db_20231228_120000.sql",
Size: 2048,
CreatedAt: time.Now(),
}
assert.Equal(t, "test_db_20231228_120000.sql", info.FileName)
assert.Equal(t, "/path/to/test_db_20231228_120000.sql", info.FilePath)
assert.Equal(t, int64(2048), info.Size)
assert.NotZero(t, info.CreatedAt)
}
func TestBackupService_BackupConfig_Fields(t *testing.T) {
config := BackupConfig{
BackupDir: "/backups",
RetentionDays: 30,
DatabaseURL: "postgres://user:pass@localhost/db",
DatabaseName: "test_db",
DatabaseUser: "test_user",
DatabaseHost: "localhost",
DatabasePort: "5432",
}
assert.Equal(t, "/backups", config.BackupDir)
assert.Equal(t, 30, config.RetentionDays)
assert.Equal(t, "postgres://user:pass@localhost/db", config.DatabaseURL)
assert.Equal(t, "test_db", config.DatabaseName)
assert.Equal(t, "test_user", config.DatabaseUser)
assert.Equal(t, "localhost", config.DatabaseHost)
assert.Equal(t, "5432", config.DatabasePort)
}