168 lines
6.6 KiB
Go
168 lines
6.6 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/user-management-system/internal/cache"
|
|
"github.com/user-management-system/internal/domain"
|
|
"github.com/user-management-system/internal/repository"
|
|
"github.com/user-management-system/internal/service"
|
|
gormsqlite "gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
type cacheInvalidatorHarness struct {
|
|
l1 *cache.L1Cache
|
|
}
|
|
|
|
func (h *cacheInvalidatorHarness) InvalidateUserState(userID int64) {
|
|
h.l1.Delete("user_state:" + strconv.FormatInt(userID, 10))
|
|
}
|
|
|
|
func (h *cacheInvalidatorHarness) InvalidateUserPerms(userID int64) {
|
|
h.l1.Delete("user_perms:" + strconv.FormatInt(userID, 10))
|
|
}
|
|
|
|
func setupCacheInvalidationDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
|
|
DriverName: "sqlite",
|
|
DSN: "file:cache_invalidation?mode=memory&cache=shared",
|
|
}), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
|
|
if err != nil {
|
|
t.Fatalf("open sqlite failed: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(&domain.User{}, &domain.Role{}, &domain.UserRole{}, &domain.Permission{}, &domain.RolePermission{}); err != nil {
|
|
t.Fatalf("migrate failed: %v", err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestUserService_InvalidateStateCacheOnStatusChange(t *testing.T) {
|
|
db := setupCacheInvalidationDB(t)
|
|
userRepo := repository.NewUserRepository(db)
|
|
userRoleRepo := repository.NewUserRoleRepository(db)
|
|
roleRepo := repository.NewRoleRepository(db)
|
|
userSvc := service.NewUserService(userRepo, userRoleRepo, roleRepo, nil)
|
|
l1 := cache.NewL1Cache()
|
|
userSvc.SetAuthCacheInvalidator(&cacheInvalidatorHarness{l1: l1})
|
|
|
|
user := &domain.User{Username: "statecache", Password: "x", Status: domain.UserStatusActive}
|
|
if err := db.Create(user).Error; err != nil {
|
|
t.Fatalf("create user failed: %v", err)
|
|
}
|
|
l1.Set("user_state:"+strconv.FormatInt(user.ID, 10), "cached", time.Minute)
|
|
|
|
if err := userSvc.UpdateStatus(context.Background(), user.ID, domain.UserStatusInactive); err != nil {
|
|
t.Fatalf("UpdateStatus failed: %v", err)
|
|
}
|
|
if _, ok := l1.Get("user_state:" + strconv.FormatInt(user.ID, 10)); ok {
|
|
t.Fatal("expected user_state cache to be invalidated")
|
|
}
|
|
}
|
|
|
|
func TestUserService_InvalidatePermCacheOnAssignRoles(t *testing.T) {
|
|
db := setupCacheInvalidationDB(t)
|
|
userRepo := repository.NewUserRepository(db)
|
|
userRoleRepo := repository.NewUserRoleRepository(db)
|
|
roleRepo := repository.NewRoleRepository(db)
|
|
userSvc := service.NewUserService(userRepo, userRoleRepo, roleRepo, nil)
|
|
l1 := cache.NewL1Cache()
|
|
userSvc.SetAuthCacheInvalidator(&cacheInvalidatorHarness{l1: l1})
|
|
|
|
user := &domain.User{Username: "permcache", Password: "x", Status: domain.UserStatusActive}
|
|
role := &domain.Role{Name: "role1", Code: "role1", Status: domain.RoleStatusEnabled}
|
|
if err := db.Create(user).Error; err != nil {
|
|
t.Fatalf("create user failed: %v", err)
|
|
}
|
|
if err := db.Create(role).Error; err != nil {
|
|
t.Fatalf("create role failed: %v", err)
|
|
}
|
|
l1.Set("user_perms:"+strconv.FormatInt(user.ID, 10), "cached", time.Minute)
|
|
|
|
if err := userSvc.AssignRoles(context.Background(), user.ID, []int64{role.ID}); err != nil {
|
|
t.Fatalf("AssignRoles failed: %v", err)
|
|
}
|
|
if _, ok := l1.Get("user_perms:" + strconv.FormatInt(user.ID, 10)); ok {
|
|
t.Fatal("expected user_perms cache to be invalidated")
|
|
}
|
|
}
|
|
|
|
func TestRoleService_InvalidatePermCacheOnAssignPermissions(t *testing.T) {
|
|
db := setupCacheInvalidationDB(t)
|
|
roleRepo := repository.NewRoleRepository(db)
|
|
rolePermRepo := repository.NewRolePermissionRepository(db)
|
|
userRoleRepo := repository.NewUserRoleRepository(db)
|
|
roleSvc := service.NewRoleService(roleRepo, rolePermRepo)
|
|
roleSvc.SetUserRoleRepository(userRoleRepo)
|
|
l1 := cache.NewL1Cache()
|
|
roleSvc.SetAuthCacheInvalidator(&cacheInvalidatorHarness{l1: l1})
|
|
|
|
user := &domain.User{Username: "rolepermcache", Password: "x", Status: domain.UserStatusActive}
|
|
role := &domain.Role{Name: "role2", Code: "role2", Status: domain.RoleStatusEnabled}
|
|
perm := &domain.Permission{Name: "perm1", Code: "perm1", Type: domain.PermissionTypeMenu, Status: domain.PermissionStatusEnabled}
|
|
if err := db.Create(user).Error; err != nil {
|
|
t.Fatalf("create user failed: %v", err)
|
|
}
|
|
if err := db.Create(role).Error; err != nil {
|
|
t.Fatalf("create role failed: %v", err)
|
|
}
|
|
if err := db.Create(perm).Error; err != nil {
|
|
t.Fatalf("create permission failed: %v", err)
|
|
}
|
|
if err := db.Create(&domain.UserRole{UserID: user.ID, RoleID: role.ID}).Error; err != nil {
|
|
t.Fatalf("create user role failed: %v", err)
|
|
}
|
|
l1.Set("user_perms:"+strconv.FormatInt(user.ID, 10), "cached", time.Minute)
|
|
|
|
if err := roleSvc.AssignPermissions(context.Background(), role.ID, []int64{perm.ID}); err != nil {
|
|
t.Fatalf("AssignPermissions failed: %v", err)
|
|
}
|
|
if _, ok := l1.Get("user_perms:" + strconv.FormatInt(user.ID, 10)); ok {
|
|
t.Fatal("expected user_perms cache to be invalidated after role permission change")
|
|
}
|
|
}
|
|
|
|
func TestPermissionService_InvalidatePermCacheOnStatusChange(t *testing.T) {
|
|
db := setupCacheInvalidationDB(t)
|
|
permRepo := repository.NewPermissionRepository(db)
|
|
rolePermRepo := repository.NewRolePermissionRepository(db)
|
|
userRoleRepo := repository.NewUserRoleRepository(db)
|
|
permSvc := service.NewPermissionService(permRepo)
|
|
permSvc.SetRolePermissionRepository(rolePermRepo)
|
|
permSvc.SetUserRoleRepository(userRoleRepo)
|
|
l1 := cache.NewL1Cache()
|
|
permSvc.SetAuthCacheInvalidator(&cacheInvalidatorHarness{l1: l1})
|
|
|
|
user := &domain.User{Username: "permstatuscache", Password: "x", Status: domain.UserStatusActive}
|
|
role := &domain.Role{Name: "role3", Code: "role3", Status: domain.RoleStatusEnabled}
|
|
perm := &domain.Permission{Name: "perm2", Code: "perm2", Type: domain.PermissionTypeMenu, Status: domain.PermissionStatusEnabled}
|
|
if err := db.Create(user).Error; err != nil {
|
|
t.Fatalf("create user failed: %v", err)
|
|
}
|
|
if err := db.Create(role).Error; err != nil {
|
|
t.Fatalf("create role failed: %v", err)
|
|
}
|
|
if err := db.Create(perm).Error; err != nil {
|
|
t.Fatalf("create permission failed: %v", err)
|
|
}
|
|
if err := db.Create(&domain.UserRole{UserID: user.ID, RoleID: role.ID}).Error; err != nil {
|
|
t.Fatalf("create user role failed: %v", err)
|
|
}
|
|
if err := db.Create(&domain.RolePermission{RoleID: role.ID, PermissionID: perm.ID}).Error; err != nil {
|
|
t.Fatalf("create role permission failed: %v", err)
|
|
}
|
|
l1.Set("user_perms:"+strconv.FormatInt(user.ID, 10), "cached", time.Minute)
|
|
|
|
if err := permSvc.UpdatePermissionStatus(context.Background(), perm.ID, domain.PermissionStatusDisabled); err != nil {
|
|
t.Fatalf("UpdatePermissionStatus failed: %v", err)
|
|
}
|
|
if _, ok := l1.Get("user_perms:" + strconv.FormatInt(user.ID, 10)); ok {
|
|
t.Fatal("expected user_perms cache to be invalidated after permission status change")
|
|
}
|
|
}
|