82 lines
2.7 KiB
Go
82 lines
2.7 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/user"
|
|
entity "RenewCMS/internal/infrastructure/persistence/models"
|
|
persistence "RenewCMS/internal/infrastructure/persistence/repositories"
|
|
"errors"
|
|
"testing"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func failAccountDeleteKeyRemoval(t *testing.T, db *gorm.DB, name string, failure error) {
|
|
t.Helper()
|
|
err := db.Callback().Delete().Before("gorm:delete").Register(name, func(tx *gorm.DB) {
|
|
if tx.Statement.Table == "api_keys" {
|
|
_ = tx.AddError(failure)
|
|
}
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Callback().Delete().Remove(name) })
|
|
}
|
|
|
|
func TestAccountDeleteContentionMapping(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
failure string
|
|
guards []uint32
|
|
notDeletable bool
|
|
}{
|
|
{"locked database with a guard role", "database is locked", []uint32{8}, true},
|
|
{"sqlite busy with a guard role", "SQLITE_BUSY: x", []uint32{8}, true},
|
|
{"deadlock with a guard role", "Deadlock found when trying to get lock", []uint32{8}, true},
|
|
{"serialization failure with a guard role", "could not serialize access", []uint32{8}, true},
|
|
{"locked database without a guard role", "database is locked", nil, false},
|
|
{"unrelated failure with a guard role", "disk exploded", []uint32{8}, false},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
seedDeleteAccountRows(t, db, true)
|
|
failure := errors.New(tc.failure)
|
|
failAccountDeleteKeyRemoval(t, db, "test:account_delete_contention", failure)
|
|
|
|
err := persistence.NewAccountEraser(db).Erase(user.Erasure{UserID: 7, GuardRoleIDs: tc.guards})
|
|
|
|
if errors.Is(err, user.ErrAccountNotDeletable) != tc.notDeletable {
|
|
t.Errorf("ErrAccountNotDeletable = %v, want %v (err %v)", !tc.notDeletable, tc.notDeletable, err)
|
|
}
|
|
if !tc.notDeletable && !errors.Is(err, failure) {
|
|
t.Errorf("expected the original failure, got %v", err)
|
|
}
|
|
if deleteAccountRowCount(t, db, &entity.User{}, "id = ?", 7) != 1 {
|
|
t.Error("the user must still exist after a failed erasure")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccountDeleteSQLiteTakesTheWriteLockBeforeCounting(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
seedDeleteAccountRows(t, db, true)
|
|
roleWrites := 0
|
|
err := db.Callback().Update().Before("gorm:update").Register("test:account_delete_role_writes", func(tx *gorm.DB) {
|
|
if tx.Statement.Table == "roles" {
|
|
roleWrites++
|
|
}
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Callback().Update().Remove("test:account_delete_role_writes") })
|
|
|
|
err = persistence.NewAccountEraser(db).Erase(user.Erasure{UserID: 7, GuardRoleIDs: []uint32{8}})
|
|
|
|
if err != nil || roleWrites != 1 {
|
|
t.Errorf("expected one lock write on the guard roles and no error, got %d writes and %v", roleWrites, err)
|
|
}
|
|
}
|