mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
1783 lines
51 KiB
Go
1783 lines
51 KiB
Go
package backups_config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"databasus-backend/internal/config"
|
|
"databasus-backend/internal/features/databases"
|
|
"databasus-backend/internal/features/databases/databases/postgresql"
|
|
"databasus-backend/internal/features/intervals"
|
|
"databasus-backend/internal/features/notifiers"
|
|
"databasus-backend/internal/features/storages"
|
|
local_storage "databasus-backend/internal/features/storages/models/local"
|
|
users_enums "databasus-backend/internal/features/users/enums"
|
|
users_testing "databasus-backend/internal/features/users/testing"
|
|
workspaces_controllers "databasus-backend/internal/features/workspaces/controllers"
|
|
workspaces_testing "databasus-backend/internal/features/workspaces/testing"
|
|
"databasus-backend/internal/util/period"
|
|
test_utils "databasus-backend/internal/util/testing"
|
|
"databasus-backend/internal/util/tools"
|
|
)
|
|
|
|
func createTestRouter() *gin.Engine {
|
|
router := workspaces_testing.CreateTestRouter(
|
|
workspaces_controllers.GetWorkspaceController(),
|
|
workspaces_controllers.GetMembershipController(),
|
|
databases.GetDatabaseController(),
|
|
GetBackupConfigController(),
|
|
)
|
|
return router
|
|
}
|
|
|
|
func Test_SaveBackupConfig_PermissionsEnforced(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
workspaceRole *users_enums.WorkspaceRole
|
|
isGlobalAdmin bool
|
|
expectSuccess bool
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
name: "workspace owner can save backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleOwner; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace admin can save backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleAdmin; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace member can save backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleMember; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace viewer cannot save backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleViewer; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: false,
|
|
expectedStatusCode: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "global admin can save backup config",
|
|
workspaceRole: nil,
|
|
isGlobalAdmin: true,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
var testUserToken string
|
|
if tt.isGlobalAdmin {
|
|
admin := users_testing.CreateTestUser(users_enums.UserRoleAdmin)
|
|
testUserToken = admin.Token
|
|
} else if tt.workspaceRole != nil && *tt.workspaceRole == users_enums.WorkspaceRoleOwner {
|
|
testUserToken = owner.Token
|
|
} else if tt.workspaceRole != nil {
|
|
member := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspaces_testing.AddMemberToWorkspace(
|
|
workspace,
|
|
member,
|
|
*tt.workspaceRole,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
testUserToken = member.Token
|
|
}
|
|
|
|
timeOfDay := "04:00"
|
|
request := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
}
|
|
|
|
var response BackupConfig
|
|
testResp := test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+testUserToken,
|
|
request,
|
|
tt.expectedStatusCode,
|
|
&response,
|
|
)
|
|
|
|
if tt.expectSuccess {
|
|
assert.Equal(t, database.ID, response.DatabaseID)
|
|
assert.True(t, response.IsBackupsEnabled)
|
|
assert.Equal(t, period.PeriodWeek, response.RetentionTimePeriod)
|
|
} else {
|
|
assert.Contains(t, string(testResp.Body), "insufficient permissions")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_SaveBackupConfig_WhenUserIsNotWorkspaceMember_ReturnsForbidden(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
nonMember := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
|
|
timeOfDay := "04:00"
|
|
request := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+nonMember.Token,
|
|
request,
|
|
http.StatusBadRequest,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "insufficient permissions")
|
|
}
|
|
|
|
func Test_GetBackupConfigByDbID_PermissionsEnforced(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
workspaceRole *users_enums.WorkspaceRole
|
|
isGlobalAdmin bool
|
|
expectSuccess bool
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
name: "workspace owner can get backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleOwner; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace admin can get backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleAdmin; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace member can get backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleMember; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "workspace viewer can get backup config",
|
|
workspaceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleViewer; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "global admin can get backup config",
|
|
workspaceRole: nil,
|
|
isGlobalAdmin: true,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "non-member cannot get backup config",
|
|
workspaceRole: nil,
|
|
isGlobalAdmin: false,
|
|
expectSuccess: false,
|
|
expectedStatusCode: http.StatusNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
var testUserToken string
|
|
if tt.isGlobalAdmin {
|
|
admin := users_testing.CreateTestUser(users_enums.UserRoleAdmin)
|
|
testUserToken = admin.Token
|
|
} else if tt.workspaceRole != nil && *tt.workspaceRole == users_enums.WorkspaceRoleOwner {
|
|
testUserToken = owner.Token
|
|
} else if tt.workspaceRole != nil {
|
|
member := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspaces_testing.AddMemberToWorkspace(
|
|
workspace,
|
|
member,
|
|
*tt.workspaceRole,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
testUserToken = member.Token
|
|
} else {
|
|
nonMember := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
testUserToken = nonMember.Token
|
|
}
|
|
|
|
var response BackupConfig
|
|
testResp := test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String(),
|
|
"Bearer "+testUserToken,
|
|
tt.expectedStatusCode,
|
|
&response,
|
|
)
|
|
|
|
if tt.expectSuccess {
|
|
assert.Equal(t, database.ID, response.DatabaseID)
|
|
assert.NotNil(t, response.BackupInterval)
|
|
} else {
|
|
assert.Contains(t, string(testResp.Body), "backup configuration not found")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_GetBackupConfigByDbID_ReturnsDefaultConfigForNewDatabase(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
var response BackupConfig
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&response,
|
|
)
|
|
|
|
assert.Equal(t, database.ID, response.DatabaseID)
|
|
assert.False(t, response.IsBackupsEnabled)
|
|
assert.True(t, response.IsRetryIfFailed)
|
|
assert.Equal(t, 3, response.MaxFailedTriesCount)
|
|
assert.NotNil(t, response.BackupInterval)
|
|
}
|
|
|
|
func Test_IsStorageUsing_PermissionsEnforced(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
isStorageOwner bool
|
|
expectSuccess bool
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
name: "storage owner can check storage usage",
|
|
isStorageOwner: true,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "non-storage-owner cannot check storage usage",
|
|
isStorageOwner: false,
|
|
expectSuccess: false,
|
|
expectedStatusCode: http.StatusInternalServerError,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
router := createTestRouter()
|
|
storageOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace(
|
|
"Test Workspace",
|
|
storageOwner,
|
|
router,
|
|
)
|
|
storage := createTestStorage(workspace.ID)
|
|
|
|
defer func() {
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
var testUserToken string
|
|
if tt.isStorageOwner {
|
|
testUserToken = storageOwner.Token
|
|
} else {
|
|
otherUser := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
testUserToken = otherUser.Token
|
|
}
|
|
|
|
if tt.expectSuccess {
|
|
var response map[string]bool
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/storage/"+storage.ID.String()+"/is-using",
|
|
"Bearer "+testUserToken,
|
|
tt.expectedStatusCode,
|
|
&response,
|
|
)
|
|
|
|
isUsing, exists := response["isUsing"]
|
|
assert.True(t, exists)
|
|
assert.False(t, isUsing)
|
|
} else {
|
|
testResp := test_utils.MakeGetRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/storage/"+storage.ID.String()+"/is-using",
|
|
"Bearer "+testUserToken,
|
|
tt.expectedStatusCode,
|
|
)
|
|
assert.Contains(t, string(testResp.Body), "error")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_SaveBackupConfig_WithEncryptionNone_ConfigSaved(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
request := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
var response BackupConfig
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
&response,
|
|
)
|
|
|
|
assert.Equal(t, database.ID, response.DatabaseID)
|
|
assert.Equal(t, BackupEncryptionNone, response.Encryption)
|
|
}
|
|
|
|
func Test_SaveBackupConfig_WithEncryptionEncrypted_ConfigSaved(t *testing.T) {
|
|
router := createTestRouter()
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
workspace := workspaces_testing.CreateTestWorkspace("Test Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", workspace.ID, owner.Token, router)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(workspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
request := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionEncrypted,
|
|
}
|
|
|
|
var response BackupConfig
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
&response,
|
|
)
|
|
|
|
assert.Equal(t, database.ID, response.DatabaseID)
|
|
assert.Equal(t, BackupEncryptionEncrypted, response.Encryption)
|
|
}
|
|
|
|
func Test_TransferDatabase_PermissionsEnforced(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
sourceRole *users_enums.WorkspaceRole
|
|
targetRole *users_enums.WorkspaceRole
|
|
isGlobalAdmin bool
|
|
expectSuccess bool
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
name: "owner in both workspaces can transfer",
|
|
sourceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleOwner; return &r }(),
|
|
targetRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleOwner; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "admin in both workspaces can transfer",
|
|
sourceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleAdmin; return &r }(),
|
|
targetRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleAdmin; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "member in both workspaces can transfer",
|
|
sourceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleMember; return &r }(),
|
|
targetRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleMember; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
{
|
|
name: "viewer in both workspaces cannot transfer",
|
|
sourceRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleViewer; return &r }(),
|
|
targetRole: func() *users_enums.WorkspaceRole { r := users_enums.WorkspaceRoleViewer; return &r }(),
|
|
isGlobalAdmin: false,
|
|
expectSuccess: false,
|
|
expectedStatusCode: http.StatusForbidden,
|
|
},
|
|
{
|
|
name: "global admin can transfer",
|
|
sourceRole: nil,
|
|
targetRole: nil,
|
|
isGlobalAdmin: true,
|
|
expectSuccess: true,
|
|
expectedStatusCode: http.StatusOK,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
sourceOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
targetOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Source Workspace",
|
|
sourceOwner,
|
|
router,
|
|
)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Target Workspace",
|
|
targetOwner,
|
|
router,
|
|
)
|
|
|
|
database := createTestDatabaseViaAPI(
|
|
"Test Database",
|
|
sourceWorkspace.ID,
|
|
sourceOwner.Token,
|
|
router,
|
|
)
|
|
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
|
|
defer func() {
|
|
// Cleanup in correct order to avoid foreign key violations
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(50 * time.Millisecond) // Wait for cascade delete of backup_config
|
|
storages.RemoveTestStorage(targetStorage.ID)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
var testUserToken string
|
|
if tt.isGlobalAdmin {
|
|
admin := users_testing.CreateTestUser(users_enums.UserRoleAdmin)
|
|
testUserToken = admin.Token
|
|
} else if tt.sourceRole != nil {
|
|
testUser := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
if *tt.sourceRole == users_enums.WorkspaceRoleOwner {
|
|
testUserToken = sourceOwner.Token
|
|
workspaces_testing.AddMemberToWorkspace(
|
|
targetWorkspace,
|
|
sourceOwner,
|
|
*tt.targetRole,
|
|
targetOwner.Token,
|
|
router,
|
|
)
|
|
} else {
|
|
workspaces_testing.AddMemberToWorkspace(
|
|
sourceWorkspace,
|
|
testUser,
|
|
*tt.sourceRole,
|
|
sourceOwner.Token,
|
|
router,
|
|
)
|
|
workspaces_testing.AddMemberToWorkspace(
|
|
targetWorkspace,
|
|
testUser,
|
|
*tt.targetRole,
|
|
targetOwner.Token,
|
|
router,
|
|
)
|
|
testUserToken = testUser.Token
|
|
}
|
|
}
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+testUserToken,
|
|
request,
|
|
tt.expectedStatusCode,
|
|
)
|
|
|
|
if tt.expectSuccess {
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database.ID.String(),
|
|
"Bearer "+targetOwner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
} else {
|
|
assert.Contains(t, string(testResp.Body), "insufficient permissions")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_TransferDatabase_NonMemberInSourceWorkspace_CannotTransfer(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
sourceOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
targetOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Source Workspace",
|
|
sourceOwner,
|
|
router,
|
|
)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Target Workspace",
|
|
targetOwner,
|
|
router,
|
|
)
|
|
|
|
database := createTestDatabaseViaAPI(
|
|
"Test Database",
|
|
sourceWorkspace.ID,
|
|
sourceOwner.Token,
|
|
router,
|
|
)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+targetOwner.Token,
|
|
request,
|
|
http.StatusForbidden,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "insufficient permissions")
|
|
}
|
|
|
|
func Test_TransferDatabase_NonMemberInTargetWorkspace_CannotTransfer(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
sourceOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
targetOwner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Source Workspace",
|
|
sourceOwner,
|
|
router,
|
|
)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace(
|
|
"Target Workspace",
|
|
targetOwner,
|
|
router,
|
|
)
|
|
|
|
database := createTestDatabaseViaAPI(
|
|
"Test Database",
|
|
sourceWorkspace.ID,
|
|
sourceOwner.Token,
|
|
router,
|
|
)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+sourceOwner.Token,
|
|
request,
|
|
http.StatusForbidden,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "insufficient permissions")
|
|
}
|
|
|
|
func Test_TransferDatabase_ToNewStorage_DatabaseTransferd(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond) // Wait for cascading deletes
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
var savedConfig BackupConfig
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
&savedConfig,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
|
|
var retrievedConfig BackupConfig
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedConfig,
|
|
)
|
|
assert.NotNil(t, retrievedConfig.StorageID)
|
|
assert.Equal(t, targetStorage.ID, *retrievedConfig.StorageID)
|
|
}
|
|
|
|
func Test_TransferDatabase_WithExistingStorage_DatabaseAndStorageTransferd(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
storage := createTestStorage(sourceWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond) // Wait for cascading deletes
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: storage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
var savedConfig BackupConfig
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
&savedConfig,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
IsTransferWithStorage: true,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
|
|
var retrievedStorage storages.Storage
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/storages/"+storage.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedStorage,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, retrievedStorage.WorkspaceID)
|
|
}
|
|
|
|
func Test_TransferDatabase_StorageHasOtherDBs_CannotTransfer(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database1 := createTestDatabaseViaAPI(
|
|
"Test Database 1",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
database2 := createTestDatabaseViaAPI(
|
|
"Test Database 2",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
storage := createTestStorage(sourceWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database1)
|
|
databases.RemoveTestDatabase(database2)
|
|
time.Sleep(200 * time.Millisecond) // Wait for cascading deletes
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest1 := BackupConfig{
|
|
DatabaseID: database1.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: storage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest1,
|
|
http.StatusOK,
|
|
)
|
|
|
|
backupConfigRequest2 := BackupConfig{
|
|
DatabaseID: database2.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: storage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest2,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
IsTransferWithStorage: true,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database1.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusBadRequest,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "storage has other attached databases")
|
|
}
|
|
|
|
func Test_TransferDatabase_WithNotifiers_NotifiersTransferred(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
notifier := notifiers.CreateTestNotifier(sourceWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond)
|
|
notifiers.RemoveTestNotifier(notifier)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
database.Notifiers = []notifiers.Notifier{*notifier}
|
|
var updatedDatabase databases.Database
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/update",
|
|
"Bearer "+owner.Token,
|
|
database,
|
|
http.StatusOK,
|
|
&updatedDatabase,
|
|
)
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
IsTransferWithNotifiers: true,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
assert.Len(t, retrievedDatabase.Notifiers, 1)
|
|
|
|
var retrievedNotifier notifiers.Notifier
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/notifiers/"+notifier.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedNotifier,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, retrievedNotifier.WorkspaceID)
|
|
}
|
|
|
|
func Test_TransferDatabase_NotifierHasOtherDBs_NotifierSkipped(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database1 := createTestDatabaseViaAPI(
|
|
"Test Database 1",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
database2 := createTestDatabaseViaAPI(
|
|
"Test Database 2",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
sharedNotifier := notifiers.CreateTestNotifier(sourceWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database1)
|
|
databases.RemoveTestDatabase(database2)
|
|
time.Sleep(200 * time.Millisecond)
|
|
notifiers.RemoveTestNotifier(sharedNotifier)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
database1.Notifiers = []notifiers.Notifier{*sharedNotifier}
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/update",
|
|
"Bearer "+owner.Token,
|
|
database1,
|
|
http.StatusOK,
|
|
)
|
|
|
|
database2.Notifiers = []notifiers.Notifier{*sharedNotifier}
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/update",
|
|
"Bearer "+owner.Token,
|
|
database2,
|
|
http.StatusOK,
|
|
)
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database1.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
IsTransferWithNotifiers: true,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database1.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database1.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
|
|
var retrievedNotifier notifiers.Notifier
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/notifiers/"+sharedNotifier.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedNotifier,
|
|
)
|
|
assert.Equal(t, sourceWorkspace.ID, retrievedNotifier.WorkspaceID)
|
|
}
|
|
|
|
func Test_TransferDatabase_WithMultipleNotifiers_OnlyExclusiveOnesTransferred(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database1 := createTestDatabaseViaAPI(
|
|
"Test Database 1",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
database2 := createTestDatabaseViaAPI(
|
|
"Test Database 2",
|
|
sourceWorkspace.ID,
|
|
owner.Token,
|
|
router,
|
|
)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
|
|
exclusiveNotifier := notifiers.CreateTestNotifier(sourceWorkspace.ID)
|
|
sharedNotifier := notifiers.CreateTestNotifier(sourceWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database1)
|
|
databases.RemoveTestDatabase(database2)
|
|
time.Sleep(200 * time.Millisecond)
|
|
notifiers.RemoveTestNotifier(exclusiveNotifier)
|
|
notifiers.RemoveTestNotifier(sharedNotifier)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
database1.Notifiers = []notifiers.Notifier{*exclusiveNotifier, *sharedNotifier}
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/update",
|
|
"Bearer "+owner.Token,
|
|
database1,
|
|
http.StatusOK,
|
|
)
|
|
|
|
database2.Notifiers = []notifiers.Notifier{*sharedNotifier}
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/update",
|
|
"Bearer "+owner.Token,
|
|
database2,
|
|
http.StatusOK,
|
|
)
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database1.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
IsTransferWithNotifiers: true,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database1.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database1.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
assert.Len(t, retrievedDatabase.Notifiers, 2)
|
|
|
|
var retrievedExclusiveNotifier notifiers.Notifier
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/notifiers/"+exclusiveNotifier.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedExclusiveNotifier,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, retrievedExclusiveNotifier.WorkspaceID)
|
|
|
|
var retrievedSharedNotifier notifiers.Notifier
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/notifiers/"+sharedNotifier.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedSharedNotifier,
|
|
)
|
|
assert.Equal(t, sourceWorkspace.ID, retrievedSharedNotifier.WorkspaceID)
|
|
}
|
|
|
|
func Test_TransferDatabase_WithTargetNotifiers_NotifiersAssigned(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
targetNotifier := notifiers.CreateTestNotifier(targetWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond)
|
|
notifiers.RemoveTestNotifier(targetNotifier)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
TargetNotifierIDs: []uuid.UUID{targetNotifier.ID},
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusOK,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "database transferred successfully")
|
|
|
|
var retrievedDatabase databases.Database
|
|
test_utils.MakeGetRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/databases/"+database.ID.String(),
|
|
"Bearer "+owner.Token,
|
|
http.StatusOK,
|
|
&retrievedDatabase,
|
|
)
|
|
assert.Equal(t, targetWorkspace.ID, *retrievedDatabase.WorkspaceID)
|
|
assert.Len(t, retrievedDatabase.Notifiers, 1)
|
|
assert.Equal(t, targetNotifier.ID, retrievedDatabase.Notifiers[0].ID)
|
|
}
|
|
|
|
func Test_TransferDatabase_TargetNotifierFromDifferentWorkspace_ReturnsBadRequest(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
otherWorkspace := workspaces_testing.CreateTestWorkspace("Other Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
targetStorage := createTestStorage(targetWorkspace.ID)
|
|
wrongNotifier := notifiers.CreateTestNotifier(otherWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond)
|
|
notifiers.RemoveTestNotifier(wrongNotifier)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(otherWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &targetStorage.ID,
|
|
TargetNotifierIDs: []uuid.UUID{wrongNotifier.ID},
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusBadRequest,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "target notifier does not belong to target workspace")
|
|
}
|
|
|
|
func Test_TransferDatabase_TargetStorageFromDifferentWorkspace_ReturnsBadRequest(t *testing.T) {
|
|
router := createTestRouterWithNotifiersForTransfer()
|
|
|
|
owner := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
sourceWorkspace := workspaces_testing.CreateTestWorkspace("Source Workspace", owner, router)
|
|
targetWorkspace := workspaces_testing.CreateTestWorkspace("Target Workspace", owner, router)
|
|
otherWorkspace := workspaces_testing.CreateTestWorkspace("Other Workspace", owner, router)
|
|
|
|
database := createTestDatabaseViaAPI("Test Database", sourceWorkspace.ID, owner.Token, router)
|
|
sourceStorage := createTestStorage(sourceWorkspace.ID)
|
|
wrongStorage := createTestStorage(otherWorkspace.ID)
|
|
|
|
defer func() {
|
|
databases.RemoveTestDatabase(database)
|
|
time.Sleep(200 * time.Millisecond)
|
|
workspaces_testing.RemoveTestWorkspace(sourceWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(targetWorkspace, router)
|
|
workspaces_testing.RemoveTestWorkspace(otherWorkspace, router)
|
|
}()
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigRequest := BackupConfig{
|
|
DatabaseID: database.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
Storage: sourceStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner.Token,
|
|
backupConfigRequest,
|
|
http.StatusOK,
|
|
)
|
|
|
|
request := TransferDatabaseRequest{
|
|
TargetWorkspaceID: targetWorkspace.ID,
|
|
TargetStorageID: &wrongStorage.ID,
|
|
}
|
|
|
|
testResp := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/database/"+database.ID.String()+"/transfer",
|
|
"Bearer "+owner.Token,
|
|
request,
|
|
http.StatusBadRequest,
|
|
)
|
|
|
|
assert.Contains(t, string(testResp.Body), "target storage does not belong to target workspace")
|
|
}
|
|
|
|
func Test_SaveBackupConfig_WithSystemStorage_CanBeUsedByAnyDatabase(t *testing.T) {
|
|
router := createTestRouterWithStorageForTransfer()
|
|
|
|
owner1 := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
owner2 := users_testing.CreateTestUser(users_enums.UserRoleMember)
|
|
admin := users_testing.CreateTestUser(users_enums.UserRoleAdmin)
|
|
|
|
workspaceA := workspaces_testing.CreateTestWorkspace("Workspace A", owner1, router)
|
|
workspaceB := workspaces_testing.CreateTestWorkspace("Workspace B", owner2, router)
|
|
|
|
databaseA := createTestDatabaseViaAPI("Database A", workspaceA.ID, owner1.Token, router)
|
|
|
|
// Test 1: Regular storage from workspace B cannot be used by database in workspace A
|
|
regularStorageB := createTestStorage(workspaceB.ID)
|
|
|
|
timeOfDay := "04:00"
|
|
backupConfigWithRegularStorage := BackupConfig{
|
|
DatabaseID: databaseA.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
StorageID: ®ularStorageB.ID,
|
|
Storage: regularStorageB,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
respRegular := test_utils.MakePostRequest(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner1.Token,
|
|
backupConfigWithRegularStorage,
|
|
http.StatusBadRequest,
|
|
)
|
|
|
|
assert.Contains(t, string(respRegular.Body), "storage does not belong to the same workspace")
|
|
|
|
// Test 2: System storage from workspace B CAN be used by database in workspace A
|
|
systemStorageB := &storages.Storage{
|
|
WorkspaceID: workspaceB.ID,
|
|
Type: storages.StorageTypeLocal,
|
|
Name: "Test System Storage " + uuid.New().String(),
|
|
IsSystem: true,
|
|
LocalStorage: &local_storage.LocalStorage{},
|
|
}
|
|
|
|
var savedSystemStorage storages.Storage
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/storages",
|
|
"Bearer "+admin.Token,
|
|
*systemStorageB,
|
|
http.StatusOK,
|
|
&savedSystemStorage,
|
|
)
|
|
|
|
assert.True(t, savedSystemStorage.IsSystem)
|
|
|
|
backupConfigWithSystemStorage := BackupConfig{
|
|
DatabaseID: databaseA.ID,
|
|
IsBackupsEnabled: true,
|
|
RetentionPolicyType: RetentionPolicyTypeTimePeriod,
|
|
RetentionTimePeriod: period.PeriodWeek,
|
|
BackupInterval: &intervals.Interval{
|
|
Interval: intervals.IntervalDaily,
|
|
TimeOfDay: &timeOfDay,
|
|
},
|
|
StorageID: &savedSystemStorage.ID,
|
|
Storage: &savedSystemStorage,
|
|
SendNotificationsOn: []BackupNotificationType{
|
|
NotificationBackupFailed,
|
|
},
|
|
IsRetryIfFailed: true,
|
|
MaxFailedTriesCount: 3,
|
|
Encryption: BackupEncryptionNone,
|
|
}
|
|
|
|
var savedConfig BackupConfig
|
|
test_utils.MakePostRequestAndUnmarshal(
|
|
t,
|
|
router,
|
|
"/api/v1/backup-configs/save",
|
|
"Bearer "+owner1.Token,
|
|
backupConfigWithSystemStorage,
|
|
http.StatusOK,
|
|
&savedConfig,
|
|
)
|
|
|
|
assert.Equal(t, databaseA.ID, savedConfig.DatabaseID)
|
|
assert.NotNil(t, savedConfig.StorageID)
|
|
assert.Equal(t, savedSystemStorage.ID, *savedConfig.StorageID)
|
|
assert.True(t, savedConfig.IsBackupsEnabled)
|
|
|
|
// Cleanup: database first (cascades to backup_config), then storages, then workspaces
|
|
databases.RemoveTestDatabase(databaseA)
|
|
storages.RemoveTestStorage(regularStorageB.ID)
|
|
storages.RemoveTestStorage(savedSystemStorage.ID)
|
|
workspaces_testing.RemoveTestWorkspace(workspaceA, router)
|
|
workspaces_testing.RemoveTestWorkspace(workspaceB, router)
|
|
}
|
|
|
|
func createTestDatabaseViaAPI(
|
|
name string,
|
|
workspaceID uuid.UUID,
|
|
token string,
|
|
router *gin.Engine,
|
|
) *databases.Database {
|
|
env := config.GetEnv()
|
|
port, err := strconv.Atoi(env.TestPostgres16Port)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Failed to parse TEST_POSTGRES_16_PORT: %v", err))
|
|
}
|
|
|
|
testDbName := "testdb"
|
|
request := databases.Database{
|
|
WorkspaceID: &workspaceID,
|
|
Name: name,
|
|
Type: databases.DatabaseTypePostgres,
|
|
Postgresql: &postgresql.PostgresqlDatabase{
|
|
Version: tools.PostgresqlVersion16,
|
|
Host: config.GetEnv().TestLocalhost,
|
|
Port: port,
|
|
Username: "testuser",
|
|
Password: "testpassword",
|
|
Database: &testDbName,
|
|
CpuCount: 1,
|
|
},
|
|
}
|
|
|
|
w := workspaces_testing.MakeAPIRequest(
|
|
router,
|
|
"POST",
|
|
"/api/v1/databases/create",
|
|
"Bearer "+token,
|
|
request,
|
|
)
|
|
|
|
if w.Code != http.StatusCreated {
|
|
panic(
|
|
fmt.Sprintf("Failed to create database. Status: %d, Body: %s", w.Code, w.Body.String()),
|
|
)
|
|
}
|
|
|
|
var database databases.Database
|
|
if err := json.Unmarshal(w.Body.Bytes(), &database); err != nil {
|
|
panic(err)
|
|
}
|
|
return &database
|
|
}
|
|
|
|
func createTestStorage(workspaceID uuid.UUID) *storages.Storage {
|
|
return storages.CreateTestStorage(workspaceID)
|
|
}
|
|
|
|
func createTestRouterWithStorageForTransfer() *gin.Engine {
|
|
router := workspaces_testing.CreateTestRouter(
|
|
workspaces_controllers.GetWorkspaceController(),
|
|
workspaces_controllers.GetMembershipController(),
|
|
databases.GetDatabaseController(),
|
|
GetBackupConfigController(),
|
|
storages.GetStorageController(),
|
|
)
|
|
|
|
storages.SetupDependencies()
|
|
databases.SetupDependencies()
|
|
SetupDependencies()
|
|
|
|
return router
|
|
}
|
|
|
|
func createTestRouterWithNotifiersForTransfer() *gin.Engine {
|
|
router := workspaces_testing.CreateTestRouter(
|
|
workspaces_controllers.GetWorkspaceController(),
|
|
workspaces_controllers.GetMembershipController(),
|
|
databases.GetDatabaseController(),
|
|
GetBackupConfigController(),
|
|
storages.GetStorageController(),
|
|
notifiers.GetNotifierController(),
|
|
)
|
|
|
|
storages.SetupDependencies()
|
|
databases.SetupDependencies()
|
|
notifiers.SetupDependencies()
|
|
SetupDependencies()
|
|
|
|
return router
|
|
}
|