1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/repository/data_integrity_repository_test.go

211 lines
6.9 KiB
Go

package repository
import (
"baron-sso-backend/internal/domain"
"context"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
func TestCheckDataIntegrityDetectsTenantAndUserProblems(t *testing.T) {
ctx := context.Background()
suffix := uuid.NewString()
parent := domain.Tenant{
ID: uuid.NewString(),
Name: "Deleted Parent " + suffix,
Slug: "deleted-parent-" + suffix,
Type: domain.TenantTypeCompany,
Status: domain.TenantStatusActive,
}
child := domain.Tenant{
ID: uuid.NewString(),
Name: "Orphan Child " + suffix,
Slug: "orphan-child-" + suffix,
Type: domain.TenantTypeOrganization,
ParentID: &parent.ID,
Status: domain.TenantStatusActive,
}
dupA := domain.Tenant{
ID: uuid.NewString(),
Name: "Duplicate A " + suffix,
Slug: "Dup-" + suffix,
Type: domain.TenantTypeCompany,
Status: domain.TenantStatusActive,
}
dupB := domain.Tenant{
ID: uuid.NewString(),
Name: "Duplicate B " + suffix,
Slug: "dup-" + suffix,
Type: domain.TenantTypeCompany,
Status: domain.TenantStatusActive,
}
require.NoError(t, testDB.Create(&parent).Error)
require.NoError(t, testDB.Create(&child).Error)
require.NoError(t, testDB.Create(&dupA).Error)
require.NoError(t, testDB.Create(&dupB).Error)
require.NoError(t, testDB.Delete(&domain.Tenant{}, "id = ?", parent.ID).Error)
orphanUser := domain.User{
ID: uuid.NewString(),
Email: "orphan-" + suffix + "@example.com",
Name: "Orphan User",
Role: domain.RoleUser,
TenantID: &parent.ID,
Status: domain.UserStatusActive,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
require.NoError(t, testDB.Create(&orphanUser).Error)
require.NoError(t, testDB.Create(&domain.UserLoginID{
ID: uuid.NewString(),
UserID: orphanUser.ID,
TenantID: parent.ID,
FieldKey: "emp_id",
LoginID: "EMP-" + suffix,
}).Error)
require.NoError(t, testDB.Create(&domain.UserLoginID{
ID: uuid.NewString(),
UserID: uuid.NewString(),
TenantID: child.ID,
FieldKey: "emp_id",
LoginID: "MISSING-" + suffix,
}).Error)
report, err := CheckDataIntegrity(ctx, testDB)
require.NoError(t, err)
require.Equal(t, domain.DataIntegrityStatusFail, report.Status)
require.Equal(t, int64(5), report.Summary.Failures)
requireIntegrityCheck(t, report, "tenant_integrity", "duplicate_tenant_slugs", domain.DataIntegrityStatusFail, 1)
requireIntegrityCheck(t, report, "tenant_integrity", "orphan_tenant_parents", domain.DataIntegrityStatusFail, 1)
requireIntegrityCheck(t, report, "user_integrity", "orphan_user_tenant_memberships", domain.DataIntegrityStatusFail, 1)
requireIntegrityCheck(t, report, "user_integrity", "orphan_user_login_id_tenants", domain.DataIntegrityStatusFail, 1)
requireIntegrityCheck(t, report, "user_integrity", "orphan_user_login_id_users", domain.DataIntegrityStatusFail, 1)
}
func TestListAndDeleteOrphanUserLoginIDsOnlyDeletesRevalidatedTargets(t *testing.T) {
ctx := context.Background()
suffix := uuid.NewString()
validTenant := domain.Tenant{
ID: uuid.NewString(),
Name: "Valid Tenant " + suffix,
Slug: "valid-tenant-" + suffix,
Type: domain.TenantTypeCompany,
Status: domain.TenantStatusActive,
}
deletedTenant := domain.Tenant{
ID: uuid.NewString(),
Name: "Deleted Tenant " + suffix,
Slug: "deleted-tenant-" + suffix,
Type: domain.TenantTypeCompany,
Status: domain.TenantStatusActive,
}
require.NoError(t, testDB.Create(&validTenant).Error)
require.NoError(t, testDB.Create(&deletedTenant).Error)
validUser := domain.User{
ID: uuid.NewString(),
Email: "valid-login-" + suffix + "@example.com",
Name: "Valid Login User",
Role: domain.RoleUser,
TenantID: &validTenant.ID,
Status: domain.UserStatusActive,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
deletedUser := domain.User{
ID: uuid.NewString(),
Email: "deleted-login-" + suffix + "@example.com",
Name: "Deleted Login User",
Role: domain.RoleUser,
TenantID: &validTenant.ID,
Status: domain.UserStatusActive,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
require.NoError(t, testDB.Create(&validUser).Error)
require.NoError(t, testDB.Create(&deletedUser).Error)
validLogin := domain.UserLoginID{
ID: uuid.NewString(),
UserID: validUser.ID,
TenantID: validTenant.ID,
FieldKey: "emp_id",
LoginID: "VALID-" + suffix,
}
deletedTenantLogin := domain.UserLoginID{
ID: uuid.NewString(),
UserID: validUser.ID,
TenantID: deletedTenant.ID,
FieldKey: "emp_id",
LoginID: "DELETED-TENANT-" + suffix,
}
deletedUserLogin := domain.UserLoginID{
ID: uuid.NewString(),
UserID: deletedUser.ID,
TenantID: validTenant.ID,
FieldKey: "emp_id",
LoginID: "DELETED-USER-" + suffix,
}
require.NoError(t, testDB.Create(&validLogin).Error)
require.NoError(t, testDB.Create(&deletedTenantLogin).Error)
require.NoError(t, testDB.Create(&deletedUserLogin).Error)
require.NoError(t, testDB.Delete(&domain.Tenant{}, "id = ?", deletedTenant.ID).Error)
require.NoError(t, testDB.Delete(&domain.User{}, "id = ?", deletedUser.ID).Error)
items, err := ListOrphanUserLoginIDs(ctx, testDB, nil)
require.NoError(t, err)
orphanReasons := map[string][]string{}
for _, item := range items {
orphanReasons[item.ID] = item.Reasons
}
require.Equal(t, []string{"deleted_tenant"}, orphanReasons[deletedTenantLogin.ID])
require.Equal(t, []string{"deleted_user"}, orphanReasons[deletedUserLogin.ID])
require.NotContains(t, orphanReasons, validLogin.ID)
result, err := DeleteOrphanUserLoginIDs(ctx, testDB, []string{
deletedTenantLogin.ID,
validLogin.ID,
"00000000-0000-0000-0000-000000000000",
})
require.NoError(t, err)
require.Equal(t, int64(1), result.DeletedCount)
require.Len(t, result.Deleted, 1)
require.Equal(t, deletedTenantLogin.ID, result.Deleted[0].ID)
require.ElementsMatch(t, []string{
validLogin.ID,
"00000000-0000-0000-0000-000000000000",
}, result.SkippedIDs)
var deletedTenantLoginCount int64
require.NoError(t, testDB.Model(&domain.UserLoginID{}).Where("id = ?", deletedTenantLogin.ID).Count(&deletedTenantLoginCount).Error)
require.Equal(t, int64(0), deletedTenantLoginCount)
var validLoginCount int64
require.NoError(t, testDB.Model(&domain.UserLoginID{}).Where("id = ?", validLogin.ID).Count(&validLoginCount).Error)
require.Equal(t, int64(1), validLoginCount)
}
func requireIntegrityCheck(t *testing.T, report domain.DataIntegrityReport, sectionKey, checkKey string, status domain.DataIntegrityStatus, count int64) {
t.Helper()
for _, section := range report.Sections {
if section.Key != sectionKey {
continue
}
for _, check := range section.Checks {
if check.Key == checkKey {
require.Equal(t, status, check.Status)
require.Equal(t, count, check.Count)
return
}
}
}
t.Fatalf("integrity check %s/%s not found", sectionKey, checkKey)
}