app-cloudep-permission-server/pkg/usecase/permission_tree_test.go

360 lines
8.9 KiB
Go
Raw Normal View History

package usecase
import (
"sync"
"testing"
"code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/entity"
"code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/permission"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// TestGeneratePermissionTree 測試 GeneratePermissionTree 函數的建立樹功能
func TestGeneratePermissionTree(t *testing.T) {
// 準備測試資料
// p1 為根節點Parent 為空)
p1ID := primitive.NewObjectID()
p1 := entity.Permission{
ID: p1ID,
Parent: "",
Name: "A",
}
// p2 的父節點為 p1
p2ID := primitive.NewObjectID()
p2 := entity.Permission{
ID: p2ID,
Parent: p1ID.Hex(),
Name: "B",
}
// p3 為另一個根節點Parent 為空)
p3ID := primitive.NewObjectID()
p3 := entity.Permission{
ID: p3ID,
Parent: "",
Name: "C",
}
// p4 的 Parent 填寫一個不存在的 id預期會掛在 dummy root 下
p4ID := primitive.NewObjectID()
p4 := entity.Permission{
ID: p4ID,
Parent: "nonexistent",
Name: "D",
}
permissions := []entity.Permission{p1, p2, p3, p4}
// 建立樹
tree := GeneratePermissionTree(permissions)
// 驗證 dummy root 下的子節點
// 預期 p1、p3、p4 均掛在 dummy root 下
if len(tree.root.Children) != 3 {
t.Errorf("expected 3 children under dummy root, got %d", len(tree.root.Children))
}
// 驗證 p1 的節點是否正確
nodeP1, ok := tree.nodes[p1ID.Hex()]
if !ok {
t.Errorf("node for permission A (p1) not found")
} else {
// p1 應該有一個子節點 p2
if len(nodeP1.Children) != 1 {
t.Errorf("expected node A to have 1 child, got %d", len(nodeP1.Children))
} else {
if nodeP1.Children[0].Data.ID != p2ID {
t.Errorf("expected node A child to be permission B (p2), got %v", nodeP1.Children[0].Data.ID.Hex())
}
}
}
// 驗證 tree.names 的對應關係
checkNames := []struct {
name string
expectedID string
}{
{"A", p1ID.Hex()},
{"B", p2ID.Hex()},
{"C", p3ID.Hex()},
{"D", p4ID.Hex()},
}
for _, cn := range checkNames {
ids, ok := tree.names[cn.name]
if !ok {
t.Errorf("name mapping for %s not found", cn.name)
continue
}
if len(ids) != 1 || ids[0] != cn.expectedID {
t.Errorf("expected name mapping for %s to be [%s], got %v", cn.name, cn.expectedID, ids)
}
}
}
func TestGetNode(t *testing.T) {
// 建立一個測試用的 PermissionTree
tree := &PermissionTree{
nodes: make(map[string]*PermissionNode),
names: make(map[string][]string),
}
id := primitive.NewObjectID()
// 建立一個測試節點ID 為 "testID"
perm := entity.Permission{
ID: id,
Name: "Test Permission",
}
node := &PermissionNode{
Data: perm,
}
// 將測試節點插入 tree 的 nodes map
tree.mu.Lock()
tree.nodes["testID"] = node
tree.mu.Unlock()
// 測試 getNode 返回存在的節點
got := tree.getNode("testID")
if got == nil {
t.Error("Expected to find node with id 'testID', but got nil")
} else if got.Data.ID.Hex() != id.Hex() {
t.Errorf("Expected node ID 'testID', got '%s'", got.Data.ID)
}
// 測試對不存在的 id應回傳 nil
gotNil := tree.getNode("nonexistent")
if gotNil != nil {
t.Errorf("Expected nil for non-existent node, got %+v", gotNil)
}
}
func TestPut(t *testing.T) {
// 建立一個 PermissionTree並初始化 dummy root
tree := &PermissionTree{
nodes: make(map[string]*PermissionNode),
names: make(map[string][]string),
}
// 建立 dummy root 節點,其 ID 為一個隨機 ObjectID但不參與 mapping
dummyRootPerm := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "",
Name: "root",
}
tree.root = &PermissionNode{
Data: dummyRootPerm,
Children: make([]*PermissionNode, 0),
}
// 測試 1放入一筆 Parent 為空的節點,預期掛在 dummy root 下
permA := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "", // 無父節點
Name: "A",
}
tree.put(permA)
nodeA := tree.getNode(permA.ID.Hex())
if nodeA == nil {
t.Errorf("Expected to find node A in tree.nodes")
}
if nodeA.Parent != tree.root {
t.Errorf("Expected node A's parent to be dummy root, got %v", nodeA.Parent.Data.Name)
}
if ids, ok := tree.names["A"]; !ok || len(ids) != 1 || ids[0] != permA.ID.Hex() {
t.Errorf("Expected tree.names for 'A' to contain %s, got %v", permA.ID.Hex(), tree.names["A"])
}
// 測試 2放入一筆 Parent 為存在節點的節點
// 先放入父節點 permB
permB := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "", // 掛在 dummy root 下
Name: "B",
}
tree.put(permB)
nodeB := tree.getNode(permB.ID.Hex())
if nodeB == nil {
t.Errorf("Expected to find node B in tree.nodes")
}
// 再放入子節點 permC其 Parent 為 permB.ID.Hex()
permC := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permB.ID.Hex(),
Name: "C",
}
tree.put(permC)
nodeC := tree.getNode(permC.ID.Hex())
if nodeC == nil {
t.Errorf("Expected to find node C in tree.nodes")
}
if nodeC.Parent != nodeB {
t.Errorf("Expected node C's parent to be node B")
}
// 驗證 nodeB 的 Children 是否包含 nodeC
found := false
for _, child := range nodeB.Children {
if child.Data.ID == permC.ID {
found = true
break
}
}
if !found {
t.Errorf("Expected node B's children to contain node C")
}
}
func TestFilterOpenNodes(t *testing.T) {
// 建立一個 PermissionTree初始化 nodes 與 names並建立 dummy root 節點
tree := &PermissionTree{
nodes: make(map[string]*PermissionNode),
names: make(map[string][]string),
mu: sync.RWMutex{},
}
// 建立 dummy root 節點
dummyRootPerm := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "",
Name: "root",
Status: permission.Open, // dummy root 狀態不影響結果
}
tree.root = &PermissionNode{
Data: dummyRootPerm,
Children: make([]*PermissionNode, 0),
}
// 建立測試節點
// Node AOpen, leaf
permA := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "", // 無父節點 → 掛在 dummy root 下
Name: "A",
Status: permission.Open,
}
tree.put(permA)
// Node BOpen, non-leaf
permB := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "", // 掛在 dummy root 下
Name: "B",
Status: permission.Open,
}
tree.put(permB)
// Node B1Open, leaf, Parent = B
permB1 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permB.ID.Hex(),
Name: "B1",
Status: permission.Open,
}
tree.put(permB1)
// Node B2Closed, leaf, Parent = B
permB2 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permB.ID.Hex(),
Name: "B2",
Status: permission.Close,
}
tree.put(permB2)
// Node COpen, non-leaf但其子節點皆 Closed → C 不會展開
permC := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "", // 掛在 dummy root 下
Name: "C",
Status: permission.Close,
}
tree.put(permC)
// Node C1Closed, leaf, Parent = C
permC1 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permC.ID.Hex(),
Name: "C1",
Status: permission.Open,
}
tree.put(permC1)
// Node C2Closed, leaf, Parent = C
permC2 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permC.ID.Hex(),
Name: "C2",
Status: permission.Open,
}
tree.put(permC2)
// Node DClosed, leaf, 無父節點
permD := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "",
Name: "D",
Status: permission.Close,
}
tree.put(permD)
// Node EClosed, leaf, 無父節點
permE := entity.Permission{
ID: primitive.NewObjectID(),
Parent: "",
Name: "E",
Status: permission.Open,
}
tree.put(permE)
// Node E1Closed, leaf, Parent = E
permE1 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permE.ID.Hex(),
Name: "E1",
Status: permission.Close,
}
tree.put(permE1)
// Node E2Closed, leaf, Parent = E
permE2 := entity.Permission{
ID: primitive.NewObjectID(),
Parent: permE.ID.Hex(),
Name: "E2",
Status: permission.Close,
}
tree.put(permE2)
// 執行 filterOpenNodes
openNodes, err := tree.filterOpenNodes()
if err != nil {
t.Fatalf("filterOpenNodes returned error: %v", err)
}
// 預期結果:
// - Node A 應該包含open 且為葉節點)
// - Node B 應該包含open 且其子節點 B1 為 open
// - Node B1 應該包含open, leaf
// - Node B2 不包含closed
// - Node C 不包含closed
// - Node C1, C2 不包含C Node Close
// - Node D 不包含closed
// - Node E 包含open
// - Node E1, E2 不包含本身Close
expectedIDs := map[string]bool{
permA.ID.Hex(): true,
permB.ID.Hex(): true,
permB1.ID.Hex(): true,
permE.ID.Hex(): true,
}
// 檢查結果是否只包含預期的節點
for id, perm := range openNodes {
if !expectedIDs[id] {
t.Errorf("Unexpected node in openNodes: id=%s, name=%s", id, perm.Name)
}
delete(expectedIDs, id)
}
if len(expectedIDs) != 0 {
t.Errorf("Expected nodes not found in openNodes: %v", expectedIDs)
}
}