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.
363 lines
9.5 KiB
Go
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)
|
|
}
|