guard/internal/usecase/permission_tree_test.go

612 lines
19 KiB
Go
Raw Permalink Normal View History

package usecase
import (
"ark-permission/internal/domain"
"ark-permission/internal/domain/usecase"
"ark-permission/internal/entity"
ers "code.30cm.net/wanderland/library-go/errors"
"fmt"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)
func TestNewPermissionTree(t *testing.T) {
tests := []struct {
name string
want *PermissionTree
}{
{
name: "ok",
want: &PermissionTree{
root: &usecase.Permission{
ID: 0,
Name: "root",
Children: []*usecase.Permission{},
},
nodes: map[int64]*usecase.Permission{0: {
ID: 0,
Name: "root",
Children: []*usecase.Permission{},
}}, // 根節點也加入 nodes 記錄
paths: make(map[int64][]int),
names: make(map[string][]int64),
ids: make(map[int64]string),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tree := NewPermissionTree()
// 驗證 Root 的值
assert.Equal(t, tree.root.ID, tt.want.root.ID)
assert.Equal(t, tree.root.Name, tt.want.root.Name)
assert.Equal(t, len(tree.root.Children), len(tt.want.root.Children))
assert.Equal(t, len(tree.nodes), len(tt.want.nodes))
assert.Equal(t, len(tree.paths), len(tt.want.paths))
assert.Equal(t, len(tree.ids), len(tt.want.ids))
})
}
}
// 測試 AddPermission 函數
func TestAddPermission(t *testing.T) {
tree := NewPermissionTree()
tests := []struct {
name string
parentID int64
permission entity.Permission
expectedError error
}{
{
name: "ok",
parentID: 0,
permission: entity.Permission{ID: 2, Name: "new_permission", HTTPPath: "/new", HTTPMethod: "POST"},
},
{
name: "Invalid Parent ID",
parentID: 99, // 無效的 parentID
permission: entity.Permission{ID: 3, Name: "invalid_parent", HTTPPath: "/invalid", HTTPMethod: "GET"},
expectedError: ers.ResourceNotFound("failed to find ID 99"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tree.AddPermission(tt.parentID, tt.permission)
// 錯誤檢查
if !reflect.DeepEqual(err, tt.expectedError) {
t.Errorf("expected error %v, got %v", tt.expectedError, err)
}
if tt.expectedError == nil {
// 檢查是否已正確插入到 nodes 中
node, ok := tree.nodes[tt.permission.ID]
if !ok {
t.Errorf("expected permission with ID %d to be in nodes map", tt.permission.ID)
}
if node.Name != tt.permission.Name {
t.Errorf("expected permission name %s, got %s", tt.permission.Name, node.Name)
}
// 檢查父節點的子節點是否正確加入
parentNode, _ := tree.FindPermissionByID(tt.parentID)
found := false
for _, child := range parentNode.Children {
if child.ID == tt.permission.ID {
found = true
break
}
}
if !found {
t.Errorf("expected permission ID %d to be child of parent ID %d", tt.permission.ID, tt.parentID)
}
}
})
}
}
// 測試 buildNodePath 函數
func TestBuildNodePath(t *testing.T) {
// ======== 準備測試 ========
tree := NewPermissionTree()
// 插入一些節點
err := tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission"})
assert.NoError(t, err)
// ======== 準備測試 ========
tests := []struct {
name string
nodeID int64
expectedPath []int
}{
{
name: "Grandchild Permission Path",
nodeID: 4,
expectedPath: []int{0, 0, 0}, // 根 -> 子 -> 孫節點的索引
},
{
name: "Child Permission 1 Path",
nodeID: 2,
expectedPath: []int{0, 0}, // 根 -> 子節點的索引
},
{
name: "Child Permission 2 Path",
nodeID: 3,
expectedPath: []int{0, 1}, // 根 -> 子節點的索引
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 查找要測試的節點
node, err := tree.FindPermissionByID(tt.nodeID)
if err != nil {
t.Fatalf("failed to find node with ID %d: %v", tt.nodeID, err)
}
// 構建節點的完整路徑
// Grandchild Permission Path 測試孫節點的完整路徑,這應該包含根節點和子節點的索引,結果為 [0, 0],表示它是根節點的第一個子節點的第一個子節點。
// Child Permission 1 Path 測試子節點 1 的路徑,應該是 [0],表示它是根節點的第一個子節點。
// Child Permission 2 Path 測試子節點 2 的路徑,應該是 [1],表示它是根節點的第二個子節點。
tree.buildNodePath(node, tt.nodeID)
// 從 paths 中獲取構建好的路徑
resultPath, ok := tree.paths[tt.nodeID]
if !ok {
t.Fatalf("path not found for node ID %d", tt.nodeID)
}
// 比較結果路徑與預期路徑
if !reflect.DeepEqual(resultPath, tt.expectedPath) {
t.Errorf("expected path %v, got %v", tt.expectedPath, resultPath)
}
})
}
}
// 測試 GetAllParentPermissionIDs 函數
func TestGetAllParentPermissionIDs(t *testing.T) {
tree := NewPermissionTree()
// ======== 準備測試 ========
// 添加節點
err := tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(0, entity.Permission{ID: 6, Name: "root_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(6, entity.Permission{ID: 6, Name: "child_permission_3"})
assert.NoError(t, err)
// ======== 準備測試 ========
tests := []struct {
name string
permissions domain.Permissions
expectedResult []int64
expectedError error
}{
{
name: "Valid permissions with open status",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedResult: []int64{0, 1, 2, 4}, // 根 -> 子 -> 孫節點
expectedError: nil,
},
{
name: "Valid multiple permissions with open status",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
},
expectedResult: []int64{0, 1, 2, 4, 0, 1, 3, 5}, // 多個權限
expectedError: nil,
},
{
name: "Permission name not found",
permissions: domain.Permissions{
"unknown_permission": domain.PermissionStatusOpenCode,
},
expectedResult: nil,
expectedError: fmt.Errorf("permission with name unknown_permission not found"),
},
{
name: "Permission close by parent node",
permissions: domain.Permissions{
"root_permission_2": domain.PermissionStatusCloseCode,
},
expectedResult: nil,
expectedError: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tree.GetAllParentPermissionIDs(tt.permissions)
// 檢查返回結果
if !reflect.DeepEqual(result, tt.expectedResult) {
t.Errorf("expected %v, got %v", tt.expectedResult, result)
}
// 檢查錯誤
if (err == nil && tt.expectedError != nil) || (err != nil && tt.expectedError == nil) {
t.Errorf("expected error %v, got %v", tt.expectedError, err)
}
})
}
}
// 測試 GetAllParentPermissionStatuses 函數
func TestGetAllParentPermissionStatuses(t *testing.T) {
tree := NewPermissionTree()
// 添加節點
err := tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
assert.NoError(t, err)
tests := []struct {
name string
permissions domain.Permissions
expectedResult domain.Permissions
expectedError error
}{
{
name: "Valid permissions with open status",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedResult: domain.Permissions{
"root_permission": domain.PermissionStatusOpenCode,
"child_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedError: nil,
},
{
name: "Multiple permissions with open status",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
},
expectedResult: domain.Permissions{
"root_permission": domain.PermissionStatusOpenCode,
"child_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"child_permission_2": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
},
expectedError: nil,
},
{
name: "Permission name not found",
permissions: domain.Permissions{
"unknown_permission": domain.PermissionStatusOpenCode,
},
expectedResult: nil,
expectedError: fmt.Errorf("permission with name unknown_permission not found"),
},
{
name: "Closed permissions are ignored",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusCloseCode,
},
expectedResult: domain.Permissions{},
expectedError: nil,
},
{
name: "Multiple permissions with close status",
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusCloseCode,
},
expectedResult: domain.Permissions{},
expectedError: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tree.GetAllParentPermissionStatuses(tt.permissions)
// 檢查返回結果
if !reflect.DeepEqual(result, tt.expectedResult) {
t.Errorf("expected %v, got %v", tt.expectedResult, result)
}
// 檢查錯誤
if (err == nil && tt.expectedError != nil) || (err != nil && tt.expectedError == nil) {
t.Errorf("expected error %v, got %v", tt.expectedError, err)
}
})
}
}
// 測試 isParentPermissionOpen 函數
func TestIsParentPermissionOpen(t *testing.T) {
tree := NewPermissionTree()
// 添加節點
err := tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
assert.NoError(t, err)
tests := []struct {
name string
nodeID int64
permissions domain.Permissions
expectedOpen bool
}{
{
name: "Parent has open child permission",
nodeID: 2,
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedOpen: true,
},
{
name: "Parent has no open child permissions",
nodeID: 2,
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusCloseCode,
},
expectedOpen: false,
},
{
name: "Parent with multiple children, one open",
nodeID: 2,
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusCloseCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
},
expectedOpen: true,
},
{
name: "Parent with no child permissions in list",
nodeID: 3,
permissions: domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedOpen: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
node, err := tree.FindPermissionByID(tt.nodeID)
if err != nil {
t.Fatalf("failed to find node with ID %d: %v", tt.nodeID, err)
}
result := tree.isParentPermissionOpen(node, tt.permissions)
if result != tt.expectedOpen {
t.Errorf("expected %v, got %v", tt.expectedOpen, result)
}
})
}
}
// 測試 GetRolePermissionTree 函數
func TestGetRolePermissionTree(t *testing.T) {
tree := NewPermissionTree()
// 添加節點
err := tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
assert.NoError(t, err)
err = tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
assert.NoError(t, err)
err = tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
assert.NoError(t, err)
// 測試數據
tests := []struct {
name string
rolePermissions []entity.RolePermission
expectedResult domain.Permissions
expectedError error
}{
{
name: "Single role permission with parent and child",
rolePermissions: []entity.RolePermission{
{PermissionID: 4}, // grandchild_permission_1
},
expectedResult: domain.Permissions{
"root_permission": domain.PermissionStatusOpenCode,
"child_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedError: nil,
},
{
name: "Multiple role permissions with parents and children",
rolePermissions: []entity.RolePermission{
{PermissionID: 4}, // grandchild_permission_1
{PermissionID: 5}, // grandchild_permission_2
},
expectedResult: domain.Permissions{
"root_permission": domain.PermissionStatusOpenCode,
"child_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"child_permission_2": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
},
expectedError: nil,
},
{
name: "Role permission with no children",
rolePermissions: []entity.RolePermission{
{PermissionID: 2}, // child_permission_1
},
expectedResult: domain.Permissions{
"root_permission": domain.PermissionStatusOpenCode,
"child_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_1": domain.PermissionStatusOpenCode,
},
expectedError: nil,
},
{
name: "Role permission not found",
rolePermissions: []entity.RolePermission{
{PermissionID: 99}, // non-existent permission
},
expectedResult: nil,
expectedError: fmt.Errorf("permission with ID %d not found", 99),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tree.GetRolePermissionTree(tt.rolePermissions)
// 檢查返回結果
if !reflect.DeepEqual(result, tt.expectedResult) {
t.Errorf("expected %v, got %v", tt.expectedResult, result)
}
// 檢查錯誤
if (err == nil && tt.expectedError != nil) || (err != nil && tt.expectedError == nil) {
t.Errorf("expected error %v, got %v", tt.expectedError, err)
}
})
}
}
func BenchmarkGetAllParentPermissionIDs(b *testing.B) {
tree := NewPermissionTree()
// 添加節點
tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
permissions := domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = tree.GetAllParentPermissionIDs(permissions)
}
}
func BenchmarkGetAllParentPermissionStatuses(b *testing.B) {
tree := NewPermissionTree()
// 添加節點
tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
permissions := domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusOpenCode,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = tree.GetAllParentPermissionStatuses(permissions)
}
}
func BenchmarkIsParentPermissionOpen(b *testing.B) {
tree := NewPermissionTree()
// 添加節點
tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
tree.AddPermission(2, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
permissions := domain.Permissions{
"grandchild_permission_1": domain.PermissionStatusOpenCode,
"grandchild_permission_2": domain.PermissionStatusCloseCode,
}
node, _ := tree.FindPermissionByID(2)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = tree.isParentPermissionOpen(node, permissions)
}
}
func BenchmarkGetRolePermissionTree(b *testing.B) {
tree := NewPermissionTree()
// 添加節點
tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
tree.AddPermission(3, entity.Permission{ID: 5, Name: "grandchild_permission_2"})
rolePermissions := []entity.RolePermission{
{PermissionID: 4}, // grandchild_permission_1
{PermissionID: 5}, // grandchild_permission_2
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = tree.GetRolePermissionTree(rolePermissions)
}
}
func BenchmarkBuildNodePath(b *testing.B) {
tree := NewPermissionTree()
// 添加節點
tree.AddPermission(0, entity.Permission{ID: 1, Name: "root_permission"})
tree.AddPermission(1, entity.Permission{ID: 2, Name: "child_permission_1"})
tree.AddPermission(1, entity.Permission{ID: 3, Name: "child_permission_2"})
tree.AddPermission(2, entity.Permission{ID: 4, Name: "grandchild_permission_1"})
node, _ := tree.FindPermissionByID(4)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tree.buildNodePath(node, 4)
}
}