databasus--databasus
75f3dd141c
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CI and Release / lint-frontend (push) Has been cancelled
CI and Release / dockerfile-scan (push) Has been cancelled
CI and Release / test-frontend (push) Has been cancelled
CI and Release / lint-verification-agent (push) Has been cancelled
CI and Release / test-verification-agent (push) Has been cancelled
CI and Release / e2e-verification-agent (push) Has been cancelled
CI and Release / test-backend (push) Has been cancelled
CI and Release / build-dev-image (push) Has been cancelled
CI and Release / push-dev-image (push) Has been cancelled
CI and Release / build-image (push) Has been cancelled
CI and Release / build-verification-image (push) Has been cancelled
CI and Release / determine-version (push) Has been cancelled
CI and Release / push-image (push) Has been cancelled
CI and Release / push-verification-image (12) (push) Has been cancelled
CI and Release / lint-backend (push) Has been cancelled
CI and Release / push-verification-image (17) (push) Has been cancelled
CI and Release / push-verification-image (18) (push) Has been cancelled
CI and Release / release (push) Has been cancelled
CI and Release / publish-helm-chart (push) Has been cancelled
CI and Release / push-verification-image (13) (push) Has been cancelled
CI and Release / push-verification-image (14) (push) Has been cancelled
CI and Release / push-verification-image (15) (push) Has been cancelled
CI and Release / push-verification-image (16) (push) Has been cancelled
193 行
5.5 KiB
Go
193 行
5.5 KiB
Go
package restoring
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
|
|
"databasus-backend/internal/config"
|
|
backups_core_logical "databasus-backend/internal/features/backups/backups/core/logical"
|
|
backups_services "databasus-backend/internal/features/backups/backups/services"
|
|
backups_config_logical "databasus-backend/internal/features/backups/config/logical"
|
|
"databasus-backend/internal/features/databases"
|
|
postgresql_logical "databasus-backend/internal/features/databases/databases/postgresql/logical"
|
|
restores_core "databasus-backend/internal/features/restores/core"
|
|
"databasus-backend/internal/features/restores/usecases"
|
|
"databasus-backend/internal/features/storages"
|
|
tasks_cancellation "databasus-backend/internal/features/tasks/cancellation"
|
|
workspaces_controllers "databasus-backend/internal/features/workspaces/controllers"
|
|
workspaces_testing "databasus-backend/internal/features/workspaces/testing"
|
|
"databasus-backend/internal/util/encryption"
|
|
"databasus-backend/internal/util/logger"
|
|
)
|
|
|
|
func CreateTestRouter() *gin.Engine {
|
|
router := workspaces_testing.CreateTestRouter(
|
|
workspaces_controllers.GetWorkspaceController(),
|
|
workspaces_controllers.GetMembershipController(),
|
|
databases.GetDatabaseController(),
|
|
backups_config_logical.GetBackupConfigController(),
|
|
)
|
|
|
|
return router
|
|
}
|
|
|
|
func CreateTestRestorer() *Restorer {
|
|
return &Restorer{
|
|
databases.GetDatabaseService(),
|
|
backups_services.GetBackupService(),
|
|
encryption.GetFieldEncryptor(),
|
|
restoreRepository,
|
|
backups_config_logical.GetBackupConfigService(),
|
|
storages.GetStorageService(),
|
|
logger.GetLogger(),
|
|
usecases.GetRestoreBackupUsecase(),
|
|
restoreDatabaseCache,
|
|
tasks_cancellation.GetTaskCancelManager(),
|
|
}
|
|
}
|
|
|
|
func CreateTestRestorerWithUsecase(usecase restores_core.RestoreBackupUsecase) *Restorer {
|
|
return &Restorer{
|
|
databases.GetDatabaseService(),
|
|
backups_services.GetBackupService(),
|
|
encryption.GetFieldEncryptor(),
|
|
restoreRepository,
|
|
backups_config_logical.GetBackupConfigService(),
|
|
storages.GetStorageService(),
|
|
logger.GetLogger(),
|
|
usecase,
|
|
restoreDatabaseCache,
|
|
tasks_cancellation.GetTaskCancelManager(),
|
|
}
|
|
}
|
|
|
|
func CreateTestRestoresScheduler() *RestoresScheduler {
|
|
return &RestoresScheduler{
|
|
restoreRepository,
|
|
time.Now().UTC(),
|
|
logger.GetLogger(),
|
|
restorer,
|
|
restoreDatabaseCache,
|
|
atomic.Bool{},
|
|
}
|
|
}
|
|
|
|
// WaitForRestoreCompletion waits for a restore to be completed (or failed)
|
|
func WaitForRestoreCompletion(
|
|
t *testing.T,
|
|
restoreID uuid.UUID,
|
|
timeout time.Duration,
|
|
) {
|
|
deadline := time.Now().UTC().Add(timeout)
|
|
|
|
for time.Now().UTC().Before(deadline) {
|
|
restore, err := restoreRepository.FindByID(restoreID)
|
|
if err != nil {
|
|
t.Logf("WaitForRestoreCompletion: error finding restore: %v", err)
|
|
time.Sleep(50 * time.Millisecond)
|
|
continue
|
|
}
|
|
|
|
t.Logf("WaitForRestoreCompletion: restore status: %s", restore.Status)
|
|
|
|
if restore.Status == restores_core.RestoreStatusCompleted ||
|
|
restore.Status == restores_core.RestoreStatusFailed {
|
|
t.Logf(
|
|
"WaitForRestoreCompletion: restore finished with status %s",
|
|
restore.Status,
|
|
)
|
|
return
|
|
}
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
}
|
|
|
|
t.Logf("WaitForRestoreCompletion: timeout waiting for restore to complete")
|
|
}
|
|
|
|
// StartRestorerForTest installs the given restorer as the DI scheduler's
|
|
// in-process executor for the duration of a test, so a test-injected usecase
|
|
// (e.g. a blocking or capturing mock) actually runs when StartRestore dispatches.
|
|
// Returns a cancel function that restores the original executor.
|
|
func StartRestorerForTest(_ *testing.T, restorerForTest *Restorer) context.CancelFunc {
|
|
previous := restoresScheduler.restorer
|
|
restoresScheduler.restorer = restorerForTest
|
|
|
|
return func() {
|
|
restoresScheduler.restorer = previous
|
|
}
|
|
}
|
|
|
|
// StartSchedulerForTest starts the RestoresScheduler in a goroutine for testing.
|
|
// Returns a context cancel function that should be deferred to stop the scheduler.
|
|
func StartSchedulerForTest(t *testing.T, scheduler *RestoresScheduler) context.CancelFunc {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
scheduler.Run(ctx)
|
|
close(done)
|
|
}()
|
|
|
|
deadline := time.Now().UTC().Add(5 * time.Second)
|
|
for time.Now().UTC().Before(deadline) {
|
|
if scheduler.IsSchedulerRunning() {
|
|
t.Log("RestoresScheduler started")
|
|
|
|
return func() {
|
|
cancel()
|
|
select {
|
|
case <-done:
|
|
t.Log("RestoresScheduler stopped gracefully")
|
|
case <-time.After(2 * time.Second):
|
|
t.Log("RestoresScheduler stop timeout")
|
|
}
|
|
}
|
|
}
|
|
|
|
time.Sleep(25 * time.Millisecond)
|
|
}
|
|
|
|
t.Fatal("RestoresScheduler failed to start within timeout")
|
|
|
|
return nil
|
|
}
|
|
|
|
// StopRestorerForTest restores the DI scheduler's original executor.
|
|
func StopRestorerForTest(_ *testing.T, cancel context.CancelFunc, _ *Restorer) {
|
|
cancel()
|
|
}
|
|
|
|
// CreateTestRestore creates a test restore with the given backup and status
|
|
func CreateTestRestore(
|
|
t *testing.T,
|
|
backup *backups_core_logical.LogicalBackup,
|
|
status restores_core.RestoreStatus,
|
|
) *restores_core.Restore {
|
|
restore := &restores_core.Restore{
|
|
BackupID: backup.ID,
|
|
Status: status,
|
|
PostgresqlLogicalDatabase: &postgresql_logical.PostgresqlLogicalDatabase{
|
|
Host: config.GetEnv().TestLocalhost,
|
|
Port: 5432,
|
|
Username: "test",
|
|
Password: "test",
|
|
Database: func() *string { s := "testdb"; return &s }(),
|
|
Version: "16",
|
|
},
|
|
}
|
|
|
|
err := restoreRepository.Save(restore)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create test restore: %v", err)
|
|
}
|
|
|
|
return restore
|
|
}
|