package repository import ( "context" "fmt" "testing" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/permission" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/repository" mgo "code.30cm.net/digimon/library-go/mongo" "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson/primitive" ) func SetupTestRoleRepository(db string) (repository.RoleRepository, func(), error) { h, p, tearDown, err := startMongoContainer() if err != nil { return nil, nil, err } conf := &mgo.Conf{ Schema: Schema, Host: fmt.Sprintf("%s:%s", h, p), Database: db, MaxStaleness: 300, MaxPoolSize: 100, MinPoolSize: 100, MaxConnIdleTime: 300, Compressors: []string{}, EnableStandardReadWriteSplitMode: false, ConnectTimeoutMs: 3000, } param := RoleRepositoryParam{ Conf: conf, } repo := NewRoleRepository(param) _, _ = repo.Index20250224UP(context.Background()) return repo, tearDown, nil } func TestRoleRepository_Create(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() testCases := []struct { name string input *entity.Role expectErr bool }{ { name: "成功建立新的角色", input: &entity.Role{ Name: "Admin", UID: "user123", ClientID: "client456", Status: 1, }, expectErr: false, }, { name: "自動生成 ID 及時間戳", input: &entity.Role{ Name: "User", UID: "user789", ClientID: "client987", Status: 1, }, expectErr: false, }, { name: "當角色為 nil 時應返回錯誤", input: nil, expectErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := repo.Create(context.Background(), tc.input) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") assert.NotEqual(t, primitive.NilObjectID, tc.input.ID, "應該自動生成 ObjectID") assert.True(t, tc.input.CreateAt > 0, "應該自動設定 CreateAt") assert.True(t, tc.input.UpdateAt > 0, "應該自動設定 UpdateAt") } }) } } func TestRoleRepository_Update(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() // 預先建立一個角色 existingRole := &entity.Role{ Name: "Old Name", UID: "old_uid", ClientID: "old_client_id", Status: 1, } err = repo.Create(context.Background(), existingRole) assert.NoError(t, err) newName := "New Name" newStatus := permission.Close newUID := "new_uid" newClientID := "new_client_id" testCases := []struct { name string input repository.UpdateReq expectErr bool }{ { name: "成功更新角色", input: repository.UpdateReq{ ID: existingRole.ID.Hex(), Name: &newName, Status: &newStatus, UID: &newUID, ClientID: &newClientID, }, expectErr: false, }, { name: "更新部分欄位", input: repository.UpdateReq{ ID: existingRole.ID.Hex(), Name: &newName, Status: &newStatus, }, expectErr: false, }, { name: "無效的 ObjectID 應返回錯誤", input: repository.UpdateReq{ ID: "invalid_object_id", }, expectErr: true, }, { name: "當 UpdateOne 失敗時應返回錯誤", input: repository.UpdateReq{ ID: primitive.NewObjectID().Hex(), // 模擬一個不存在的 ID }, expectErr: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := repo.Update(context.Background(), tc.input) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") // 驗證更新結果 updatedRole, err := repo.GetByID(context.Background(), existingRole.ID.Hex()) assert.NoError(t, err) if tc.input.Name != nil { assert.Equal(t, *tc.input.Name, updatedRole.Name, "名稱應該被更新") } if tc.input.Status != nil { assert.Equal(t, *tc.input.Status, updatedRole.Status, "狀態應該被更新") } if tc.input.UID != nil { assert.Equal(t, *tc.input.UID, updatedRole.UID, "UID 應該被更新") } if tc.input.ClientID != nil { assert.Equal(t, *tc.input.ClientID, updatedRole.ClientID, "ClientID 應該被更新") } } }) } } func TestRoleRepository_Delete(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() // 預先建立一個角色 existingRole := &entity.Role{ Name: "Test Role", UID: "test_uid", ClientID: "test_client_id", Status: 1, } err = repo.Create(context.Background(), existingRole) assert.NoError(t, err) testCases := []struct { name string inputID string expectErr bool }{ { name: "成功刪除角色", inputID: existingRole.ID.Hex(), expectErr: false, }, { name: "刪除不存在的角色不應報錯", inputID: primitive.NewObjectID().Hex(), expectErr: false, }, { name: "無效的 ObjectID 應返回錯誤", inputID: "invalid_object_id", expectErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := repo.Delete(context.Background(), tc.inputID) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") // 驗證角色是否已刪除 if tc.inputID == existingRole.ID.Hex() { _, err := repo.GetByID(context.Background(), existingRole.ID.Hex()) assert.Error(t, err, "應該找不到該角色") } } }) } } func TestRoleRepository_All(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() clientID1 := "client_1" clientID2 := "client_2" // 預先建立角色資料 roles := []*entity.Role{ { ID: primitive.NewObjectID(), Name: "Admin", UID: "admin_uid", ClientID: clientID1, Status: 1, }, { ID: primitive.NewObjectID(), Name: "User", UID: "user_uid", ClientID: clientID1, Status: 1, }, { ID: primitive.NewObjectID(), Name: "Manager", UID: "manager_uid", ClientID: clientID2, Status: 1, }, } // 插入測試資料 for _, role := range roles { err := repo.Create(context.Background(), role) assert.NoError(t, err) } testCases := []struct { name string clientID *string expectLen int expectErr bool }{ { name: "查詢所有角色", clientID: nil, expectLen: len(roles), expectErr: false, }, { name: "根據 clientID 查詢角色", clientID: &clientID1, expectLen: 2, expectErr: false, }, { name: "clientID 無匹配時應返回空", clientID: new(string), expectLen: 0, expectErr: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result, err := repo.All(context.Background(), tc.clientID) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") assert.Len(t, result, tc.expectLen, "返回的角色數量應符合預期") } }) } } func TestRoleRepository_GetByUID(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() // 預先建立測試角色 existingRole := &entity.Role{ ID: primitive.NewObjectID(), Name: "Admin", UID: "admin_uid", ClientID: "client_1", Status: 1, } err = repo.Create(context.Background(), existingRole) assert.NoError(t, err) testCases := []struct { name string uid string expectErr bool expectNil bool }{ { name: "成功查詢角色", uid: "admin_uid", expectErr: false, expectNil: false, }, { name: "查詢不存在的角色", uid: "non_existent_uid", expectErr: true, expectNil: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result, err := repo.GetByUID(context.Background(), tc.uid) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") } if tc.expectNil { assert.Nil(t, result, "應該返回 nil") } else { assert.NotNil(t, result, "不應該返回 nil") assert.Equal(t, existingRole.UID, result.UID, "UID 應相符") assert.Equal(t, existingRole.Name, result.Name, "名稱應相符") } }) } } func TestRoleRepository_GetByID(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() // 預先建立測試角色 existingRole := &entity.Role{ ID: primitive.NewObjectID(), Name: "Admin", UID: "admin_uid", ClientID: "client_1", Status: 1, } err = repo.Create(context.Background(), existingRole) assert.NoError(t, err) testCases := []struct { name string id string expectErr bool expectNil bool }{ { name: "成功查詢角色", id: existingRole.ID.Hex(), expectErr: false, expectNil: false, }, { name: "查詢不存在的角色", id: primitive.NewObjectID().Hex(), expectErr: true, expectNil: true, }, { name: "提供無效的 ObjectID", id: "invalid_id", expectErr: true, expectNil: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result, err := repo.GetByID(context.Background(), tc.id) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") } if tc.expectNil { assert.Nil(t, result, "應該返回 nil") } else { assert.NotNil(t, result, "不應該返回 nil") assert.Equal(t, existingRole.ID, result.ID, "ID 應相符") assert.Equal(t, existingRole.Name, result.Name, "名稱應相符") } }) } } func TestRoleRepository_List(t *testing.T) { repo, tearDown, err := SetupTestRoleRepository("testDB") assert.NoError(t, err) defer tearDown() // 預先建立測試角色 roles := []*entity.Role{ { ID: primitive.NewObjectID(), Name: "Admin", UID: "admin_uid", ClientID: "client_1", Status: 1, }, { ID: primitive.NewObjectID(), Name: "User", UID: "user_uid", ClientID: "client_1", Status: 1, }, { ID: primitive.NewObjectID(), Name: "Guest", UID: "guest_uid", ClientID: "client_2", Status: 0, }, } // 插入測試資料 for _, role := range roles { err := repo.Create(context.Background(), role) assert.NoError(t, err) } testCases := []struct { name string query repository.ListQuery expectLen int expectErr bool }{ { name: "查詢所有角色", query: repository.ListQuery{PageSize: 10, PageIndex: 1}, expectLen: 3, expectErr: false, }, { name: "篩選名稱為 Admin", query: repository.ListQuery{Name: ToPointer("Admin"), PageSize: 10, PageIndex: 1}, expectLen: 1, expectErr: false, }, { name: "篩選特定 ClientID", query: repository.ListQuery{ClientID: ToPointer("client_1"), PageSize: 10, PageIndex: 1}, expectLen: 2, expectErr: false, }, { name: "篩選啟用 (Status=1) 的角色", query: repository.ListQuery{Status: ToPointer(permission.Open), PageSize: 10, PageIndex: 1}, expectLen: 2, expectErr: false, }, { name: "篩選特定 UID", query: repository.ListQuery{UID: ToPointer("guest_uid"), PageSize: 10, PageIndex: 1}, expectLen: 1, expectErr: false, }, { name: "測試分頁 PageSize=1, PageIndex=1", query: repository.ListQuery{PageSize: 1, PageIndex: 1}, expectLen: 1, expectErr: false, }, { name: "查詢無符合條件的角色", query: repository.ListQuery{Name: ToPointer("NonExist"), PageSize: 10, PageIndex: 1}, expectLen: 0, expectErr: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result, _, err := repo.List(context.Background(), tc.query) if tc.expectErr { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "不應該返回錯誤") assert.Len(t, result, tc.expectLen, "返回的角色數量應符合預期") } }) } }