backend/pkg/permission/repository/role_test.go

463 lines
9.6 KiB
Go

package repository
import (
"backend/pkg/permission/domain"
"backend/pkg/permission/domain/entity"
domainRepo "backend/pkg/permission/domain/repository"
"context"
"fmt"
"github.com/alicebob/miniredis/v2"
"github.com/zeromicro/go-zero/core/stores/redis"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zeromicro/go-zero/core/stores/cache"
"go.mongodb.org/mongo-driver/v2/bson"
mgo "backend/pkg/library/mongo"
)
func setupRoleRepo(db string) (domainRepo.RoleRepository, func(), error) {
h, p, tearDown, err := startMongoContainer()
if err != nil {
return nil, nil, err
}
s, _ := miniredis.Run()
conf := &mgo.Conf{
Schema: mongoSchema,
Host: fmt.Sprintf("%s:%s", h, p),
Database: db,
MaxStaleness: 300,
MaxPoolSize: 100,
MinPoolSize: 100,
MaxConnIdleTime: 300,
Compressors: []string{},
EnableStandardReadWriteSplitMode: false,
ConnectTimeoutMs: 3000,
}
cacheConf := cache.CacheConf{
cache.NodeConf{
RedisConf: redis.RedisConf{
Host: s.Addr(),
Type: redis.NodeType,
},
Weight: 100,
},
}
cacheOpts := []cache.Option{
cache.WithExpiry(1000 * time.Microsecond),
cache.WithNotFoundExpiry(1000 * time.Microsecond),
}
param := RoleRepositoryParam{
Conf: conf,
CacheConf: cacheConf,
CacheOpts: cacheOpts,
}
repo := NewRoleRepository(param)
_, _ = repo.Index20251009002UP(context.Background())
return repo, tearDown, nil
}
func TestRoleRepository_CreateAndGet(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
tests := []struct {
name string
role *entity.Role
wantErr bool
}{
{
name: "成功創建角色",
role: &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "管理員",
Status: domain.RecordActive,
},
wantErr: false,
},
{
name: "創建另一個角色",
role: &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000002",
ClientID: 1,
Name: "一般使用者",
Status: domain.RecordActive,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := repo.Create(ctx, tt.role)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
// 驗證可以找到創建的角色
retrieved, err := repo.GetByUID(ctx, tt.role.UID)
assert.NoError(t, err)
assert.Equal(t, tt.role.UID, retrieved.UID)
assert.Equal(t, tt.role.Name, retrieved.Name)
assert.Equal(t, tt.role.ClientID, retrieved.ClientID)
}
})
}
}
func TestRoleRepository_GetByUID(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據
testRole := &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "測試角色",
Status: domain.RecordActive,
}
err = repo.Create(ctx, testRole)
require.NoError(t, err)
tests := []struct {
name string
uid string
wantErr error
check func(*testing.T, *entity.Role)
}{
{
name: "找到存在的角色",
uid: "ROLE0000000001",
wantErr: nil,
check: func(t *testing.T, role *entity.Role) {
assert.Equal(t, "測試角色", role.Name)
assert.Equal(t, 1, role.ClientID)
},
},
{
name: "不存在的角色",
uid: "ROLE9999999999",
wantErr: ErrNotFound,
check: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
role, err := repo.GetByUID(ctx, tt.uid)
if tt.wantErr != nil {
assert.ErrorIs(t, err, tt.wantErr)
assert.Nil(t, role)
} else {
assert.NoError(t, err)
assert.NotNil(t, role)
if tt.check != nil {
tt.check(t, role)
}
}
})
}
}
func TestRoleRepository_Update(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據
testRole := &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "原始名稱",
Status: domain.RecordActive,
}
err = repo.Create(ctx, testRole)
require.NoError(t, err)
tests := []struct {
name string
update func(*entity.Role)
wantErr bool
check func(*testing.T, *entity.Role)
}{
{
name: "更新角色名稱",
update: func(role *entity.Role) {
role.Name = "新的名稱"
},
wantErr: false,
check: func(t *testing.T, role *entity.Role) {
assert.Equal(t, "新的名稱", role.Name)
},
},
{
name: "更新角色狀態",
update: func(role *entity.Role) {
role.Status = domain.RecordInactive
},
wantErr: false,
check: func(t *testing.T, role *entity.Role) {
assert.Equal(t, domain.RecordInactive, role.Status)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 獲取當前角色
role, err := repo.GetByUID(ctx, testRole.UID)
require.NoError(t, err)
// 應用更新
tt.update(role)
// 執行更新
err = repo.Update(ctx, role)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
// 驗證更新
updated, err := repo.GetByUID(ctx, testRole.UID)
assert.NoError(t, err)
if tt.check != nil {
tt.check(t, updated)
}
}
})
}
}
func TestRoleRepository_Delete(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據
testRole := &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "要刪除的角色",
Status: domain.RecordActive,
}
err = repo.Create(ctx, testRole)
require.NoError(t, err)
t.Run("軟刪除角色", func(t *testing.T) {
err := repo.Delete(ctx, testRole.UID)
assert.NoError(t, err)
// 驗證角色狀態變為已刪除
role, err := repo.GetByUID(ctx, testRole.UID)
assert.NoError(t, err)
assert.Equal(t, domain.RecordDeleted, role.Status)
})
}
func TestRoleRepository_List(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據
testRoles := []*entity.Role{
{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "管理員",
Status: domain.RecordActive,
},
{
ID: bson.NewObjectID(),
UID: "ROLE0000000002",
ClientID: 1,
Name: "編輯者",
Status: domain.RecordActive,
},
{
ID: bson.NewObjectID(),
UID: "ROLE0000000003",
ClientID: 2,
Name: "訪客",
Status: domain.RecordInactive,
},
}
for _, role := range testRoles {
err := repo.Create(ctx, role)
require.NoError(t, err)
}
tests := []struct {
name string
filter domainRepo.RoleFilter
wantCount int
}{
{
name: "列出所有角色",
filter: domainRepo.RoleFilter{},
wantCount: 3,
},
{
name: "按 ClientID 過濾",
filter: domainRepo.RoleFilter{
ClientID: 1,
},
wantCount: 2,
},
{
name: "按名稱模糊搜尋",
filter: domainRepo.RoleFilter{
Name: "管理",
},
wantCount: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
roles, err := repo.List(ctx, tt.filter)
assert.NoError(t, err)
assert.Len(t, roles, tt.wantCount)
})
}
}
func TestRoleRepository_Page(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據 - 創建 15 個角色
for i := 1; i <= 15; i++ {
role := &entity.Role{
ID: bson.NewObjectID(),
UID: bson.NewObjectID().Hex(),
ClientID: 1,
Name: bson.NewObjectID().Hex(),
Status: domain.RecordActive,
}
err := repo.Create(ctx, role)
require.NoError(t, err)
}
tests := []struct {
name string
page int
size int
wantCount int
wantTotal int64
}{
{
name: "第一頁,每頁 10 筆",
page: 1,
size: 10,
wantCount: 10,
wantTotal: 15,
},
{
name: "第二頁,每頁 10 筆",
page: 2,
size: 10,
wantCount: 5,
wantTotal: 15,
},
{
name: "第一頁,每頁 5 筆",
page: 1,
size: 5,
wantCount: 5,
wantTotal: 15,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
roles, total, err := repo.Page(ctx, domainRepo.RoleFilter{}, tt.page, tt.size)
assert.NoError(t, err)
assert.Len(t, roles, tt.wantCount)
assert.Equal(t, tt.wantTotal, total)
})
}
}
func TestRoleRepository_Exists(t *testing.T) {
repo, tearDown, err := setupRoleRepo("testDB")
defer tearDown()
assert.NoError(t, err)
ctx := context.Background()
// 準備測試數據
testRole := &entity.Role{
ID: bson.NewObjectID(),
UID: "ROLE0000000001",
ClientID: 1,
Name: "測試角色",
Status: domain.RecordActive,
}
err = repo.Create(ctx, testRole)
require.NoError(t, err)
tests := []struct {
name string
uid string
exists bool
}{
{
name: "存在的角色",
uid: "ROLE0000000001",
exists: true,
},
{
name: "不存在的角色",
uid: "ROLE9999999999",
exists: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exists, err := repo.Exists(ctx, tt.uid)
assert.NoError(t, err)
assert.Equal(t, tt.exists, exists)
})
}
}