package loaders import ( "context" "database/sql" "fmt" "math" "math/rand" "sort" "testing" "time" "perms-system-server/internal/consts" "perms-system-server/internal/model" deptModel "perms-system-server/internal/model/dept" permModel "perms-system-server/internal/model/perm" productModel "perms-system-server/internal/model/product" memberModel "perms-system-server/internal/model/productmember" roleModel "perms-system-server/internal/model/role" rolePermModel "perms-system-server/internal/model/roleperm" userModel "perms-system-server/internal/model/user" userPermModel "perms-system-server/internal/model/userperm" userRoleModel "perms-system-server/internal/model/userrole" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlx" "golang.org/x/crypto/bcrypt" ) // --------------- inline test config (avoid circular import with testutil) --------------- var testCacheConf = cache.CacheConf{ { RedisConf: redis.RedisConf{Host: "127.0.0.1:6379", Pass: "NsDmWyM@312", Type: "node"}, Weight: 100, }, } var testKeyPrefix = "test_perms" var testDataSource = "root:NsDmWyM@312@tcp(127.0.0.1:3306)/perms_system?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai" func testConn() sqlx.SqlConn { return sqlx.NewMysql(testDataSource) } func testRedis() *redis.Redis { return redis.MustNewRedis(testCacheConf[0].RedisConf) } func testModels() *model.Models { conn := testConn() return model.NewModels(conn, testCacheConf, testKeyPrefix) } func uniqueId() string { return fmt.Sprintf("t_%d_%d", time.Now().UnixNano(), rand.Intn(100000)) } func hashPwd(p string) string { h, _ := bcrypt.GenerateFromPassword([]byte(p), bcrypt.MinCost) return string(h) } func cleanTable(ctx context.Context, conn sqlx.SqlConn, table string, ids ...int64) { for _, id := range ids { conn.ExecCtx(ctx, fmt.Sprintf("DELETE FROM %s WHERE `id` = ?", table), id) } } func cleanTableByField(ctx context.Context, conn sqlx.SqlConn, table, field string, value interface{}) { conn.ExecCtx(ctx, fmt.Sprintf("DELETE FROM %s WHERE `%s` = ?", table, field), value) } func newTestLoader() *UserDetailsLoader { rds := testRedis() m := testModels() return NewUserDetailsLoader(rds, testKeyPrefix, m) } func now() int64 { return time.Now().Unix() } // --------------- helpers: insert test data --------------- func insertUser(ctx context.Context, t *testing.T, m *model.Models, u *userModel.SysUser) int64 { t.Helper() res, err := m.SysUserModel.Insert(ctx, u) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertDept(ctx context.Context, t *testing.T, m *model.Models, d *deptModel.SysDept) int64 { t.Helper() res, err := m.SysDeptModel.Insert(ctx, d) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertProduct(ctx context.Context, t *testing.T, m *model.Models, p *productModel.SysProduct) int64 { t.Helper() res, err := m.SysProductModel.Insert(ctx, p) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertMember(ctx context.Context, t *testing.T, m *model.Models, mb *memberModel.SysProductMember) int64 { t.Helper() res, err := m.SysProductMemberModel.Insert(ctx, mb) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertRole(ctx context.Context, t *testing.T, m *model.Models, r *roleModel.SysRole) int64 { t.Helper() res, err := m.SysRoleModel.Insert(ctx, r) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertPerm(ctx context.Context, t *testing.T, m *model.Models, p *permModel.SysPerm) int64 { t.Helper() res, err := m.SysPermModel.Insert(ctx, p) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertUserRole(ctx context.Context, t *testing.T, m *model.Models, ur *userRoleModel.SysUserRole) int64 { t.Helper() res, err := m.SysUserRoleModel.Insert(ctx, ur) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertRolePerm(ctx context.Context, t *testing.T, m *model.Models, rp *rolePermModel.SysRolePerm) int64 { t.Helper() res, err := m.SysRolePermModel.Insert(ctx, rp) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertUserPerm(ctx context.Context, t *testing.T, m *model.Models, up *userPermModel.SysUserPerm) int64 { t.Helper() res, err := m.SysUserPermModel.Insert(ctx, up) require.NoError(t, err) id, _ := res.LastInsertId() return id } // --------------- TC-0458: Load-DB加载(缓存miss) --------------- func TestLoad_DBMiss(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid deptId := insertDept(ctx, t, m, &deptModel.SysDept{ ParentId: 0, Name: "dept_" + uid, Path: "/1/", Sort: 1, DeptType: consts.DeptTypeNormal, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Avatar: sql.NullString{}, Email: uid + "@test.com", Phone: "13800000001", Remark: "remark", DeptId: deptId, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) productId := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) roleId := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "role_" + uid, Remark: "test", Status: consts.StatusEnabled, PermsLevel: 10, CreateTime: ts, UpdateTime: ts, }) permId := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "perm_" + uid, Code: "perm:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) urId := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleId, CreateTime: ts, UpdateTime: ts, }) rpId := insertRolePerm(ctx, t, m, &rolePermModel.SysRolePerm{ RoleId: roleId, PermId: permId, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_role_perm`", rpId) cleanTable(ctx, conn, "`sys_user_role`", urId) cleanTable(ctx, conn, "`sys_perm`", permId) cleanTable(ctx, conn, "`sys_role`", roleId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", productId) cleanTable(ctx, conn, "`sys_user`", userId) cleanTable(ctx, conn, "`sys_dept`", deptId) }) // clear any leftover cache loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, userId, ud.UserId) assert.Equal(t, uid, ud.Username) assert.Equal(t, "nick_"+uid, ud.Nickname) assert.Equal(t, uid+"@test.com", ud.Email) assert.Equal(t, int64(consts.StatusEnabled), ud.Status) assert.Equal(t, deptId, ud.DeptId) assert.Equal(t, "dept_"+uid, ud.DeptName) assert.Equal(t, pcode, ud.ProductCode) assert.Equal(t, "prod_"+uid, ud.ProductName) assert.Equal(t, consts.MemberTypeMember, ud.MemberType) assert.Len(t, ud.Roles, 1) assert.Equal(t, roleId, ud.Roles[0].Id) assert.Equal(t, int64(10), ud.MinPermsLevel) assert.Contains(t, ud.Perms, "perm:"+uid) } // --------------- TC-0459: Load-缓存命中 --------------- func TestLoad_CacheHit(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000002", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) productId := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product`", productId) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud1 := loader.Load(ctx, userId, pcode) require.NotNil(t, ud1) ud2 := loader.Load(ctx, userId, pcode) require.NotNil(t, ud2) assert.Equal(t, ud1.UserId, ud2.UserId) assert.Equal(t, ud1.Username, ud2.Username) assert.Equal(t, ud1.ProductName, ud2.ProductName) } // --------------- TC-0460: Load-用户不存在 --------------- func TestLoad_UserNotExist(t *testing.T) { ctx := context.Background() loader := newTestLoader() nonExistId := int64(999999999) loader.Del(ctx, nonExistId, "nonexist_product") ud := loader.Load(ctx, nonExistId, "nonexist_product") require.NotNil(t, ud) assert.Equal(t, int64(0), ud.Status) assert.Empty(t, ud.Username) assert.Empty(t, ud.Perms) assert.Empty(t, ud.Roles) loader.Del(ctx, nonExistId, "nonexist_product") } // --------------- TC-0461: Load-productCode为空 --------------- func TestLoad_EmptyProductCode(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000003", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, "") cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, "") ud := loader.Load(ctx, userId, "") require.NotNil(t, ud) assert.Equal(t, uid, ud.Username) assert.Equal(t, int64(consts.StatusEnabled), ud.Status) assert.Empty(t, ud.ProductCode) assert.Empty(t, ud.ProductName) assert.Empty(t, ud.MemberType) assert.Empty(t, ud.Roles) assert.Empty(t, ud.Perms) } // --------------- TC-0462: Del删除指定缓存 --------------- func TestDel(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000004", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) productId := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product`", productId) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud1 := loader.Load(ctx, userId, pcode) require.NotNil(t, ud1) assert.Equal(t, uid, ud1.Username) loader.Del(ctx, userId, pcode) ud2 := loader.Load(ctx, userId, pcode) require.NotNil(t, ud2) assert.Equal(t, uid, ud2.Username) } // --------------- TC-0463: Clean清除用户所有产品缓存 --------------- func TestClean(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode1 := "p1_" + uid pcode2 := "p2_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000005", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid1 := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode1, Name: "prod1_" + uid, AppKey: "ak1_" + uid, AppSecret: "as1_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid2 := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode2, Name: "prod2_" + uid, AppKey: "ak2_" + uid, AppSecret: "as2_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode1) loader.Del(ctx, userId, pcode2) cleanTable(ctx, conn, "`sys_product`", pid1, pid2) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode1) loader.Del(ctx, userId, pcode2) ud1 := loader.Load(ctx, userId, pcode1) ud2 := loader.Load(ctx, userId, pcode2) require.NotNil(t, ud1) require.NotNil(t, ud2) rds := testRedis() key1 := loader.cacheKey(userId, pcode1) key2 := loader.cacheKey(userId, pcode2) v1, _ := rds.GetCtx(ctx, key1) v2, _ := rds.GetCtx(ctx, key2) assert.NotEmpty(t, v1) assert.NotEmpty(t, v2) loader.Clean(ctx, userId) v1After, _ := rds.GetCtx(ctx, key1) v2After, _ := rds.GetCtx(ctx, key2) assert.Empty(t, v1After) assert.Empty(t, v2After) } // --------------- TC-0464: CleanByProduct清除产品所有用户 --------------- func TestCleanByProduct(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid1 := uniqueId() uid2 := uniqueId() ts := now() pcode := "p_" + uid1 userId1 := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid1, Password: hashPwd("pass123"), Nickname: "nick_" + uid1, Email: uid1 + "@test.com", Phone: "13800000006", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) userId2 := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid2, Password: hashPwd("pass123"), Nickname: "nick_" + uid2, Email: uid2 + "@test.com", Phone: "13800000007", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid1, AppKey: "ak_" + uid1, AppSecret: "as_" + uid1, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId1, pcode) loader.Del(ctx, userId2, pcode) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId1, userId2) }) loader.Del(ctx, userId1, pcode) loader.Del(ctx, userId2, pcode) loader.Load(ctx, userId1, pcode) loader.Load(ctx, userId2, pcode) rds := testRedis() k1 := loader.cacheKey(userId1, pcode) k2 := loader.cacheKey(userId2, pcode) v1, _ := rds.GetCtx(ctx, k1) v2, _ := rds.GetCtx(ctx, k2) assert.NotEmpty(t, v1) assert.NotEmpty(t, v2) loader.CleanByProduct(ctx, pcode) v1After, _ := rds.GetCtx(ctx, k1) v2After, _ := rds.GetCtx(ctx, k2) assert.Empty(t, v1After) assert.Empty(t, v2After) } // --------------- TC-0465: BatchDel批量删除 --------------- func TestBatchDel(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid1 := uniqueId() uid2 := uniqueId() ts := now() pcode := "p_" + uid1 userId1 := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid1, Password: hashPwd("pass123"), Nickname: "nick_" + uid1, Email: uid1 + "@test.com", Phone: "13800000008", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) userId2 := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid2, Password: hashPwd("pass123"), Nickname: "nick_" + uid2, Email: uid2 + "@test.com", Phone: "13800000009", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid1, AppKey: "ak_" + uid1, AppSecret: "as_" + uid1, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId1, pcode) loader.Del(ctx, userId2, pcode) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId1, userId2) }) loader.Del(ctx, userId1, pcode) loader.Del(ctx, userId2, pcode) loader.Load(ctx, userId1, pcode) loader.Load(ctx, userId2, pcode) rds := testRedis() k1 := loader.cacheKey(userId1, pcode) k2 := loader.cacheKey(userId2, pcode) v1, _ := rds.GetCtx(ctx, k1) v2, _ := rds.GetCtx(ctx, k2) assert.NotEmpty(t, v1) assert.NotEmpty(t, v2) loader.BatchDel(ctx, []int64{userId1, userId2}, pcode) v1After, _ := rds.GetCtx(ctx, k1) v2After, _ := rds.GetCtx(ctx, k2) assert.Empty(t, v1After) assert.Empty(t, v2After) } // --------------- TC-0466: BatchDel空数组 --------------- func TestBatchDel_EmptySlice(t *testing.T) { ctx := context.Background() loader := newTestLoader() loader.BatchDel(ctx, []int64{}, "some_code") } // --------------- TC-0467: loadPerms-超管拥有全部权限 --------------- func TestLoadPerms_SuperAdmin(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000010", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminYes, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permCode1 := "perm1:" + uid permCode2 := "perm2:" + uid permId1 := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p1_" + uid, Code: permCode1, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permId2 := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p2_" + uid, Code: permCode2, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_perm`", permId1, permId2) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.True(t, ud.IsSuperAdmin) assert.Equal(t, consts.MemberTypeSuperAdmin, ud.MemberType) sort.Strings(ud.Perms) expected := []string{permCode1, permCode2} sort.Strings(expected) assert.Equal(t, expected, ud.Perms) } // --------------- TC-0468: loadPerms-ADMIN成员拥有全部权限 --------------- func TestLoadPerms_AdminMember(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000011", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeAdmin, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permCode := "perm:" + uid permId := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p_" + uid, Code: permCode, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_perm`", permId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, consts.MemberTypeAdmin, ud.MemberType) assert.Contains(t, ud.Perms, permCode) } // --------------- TC-0469: loadPerms-DEVELOPER成员拥有全部权限 --------------- func TestLoadPerms_DeveloperMember(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000012", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeDeveloper, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permCode := "perm:" + uid permId := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p_" + uid, Code: permCode, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_perm`", permId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, consts.MemberTypeDeveloper, ud.MemberType) assert.Contains(t, ud.Perms, permCode) } // --------------- TC-0470: loadPerms-DEV部门成员拥有全部权限 --------------- func TestLoadPerms_DevDept(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid deptId := insertDept(ctx, t, m, &deptModel.SysDept{ ParentId: 0, Name: "devdept_" + uid, Path: "/1/", Sort: 1, DeptType: consts.DeptTypeDev, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000013", DeptId: deptId, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permCode := "perm:" + uid permId := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p_" + uid, Code: permCode, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_perm`", permId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) cleanTable(ctx, conn, "`sys_dept`", deptId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, consts.DeptTypeDev, ud.DeptType) assert.Contains(t, ud.Perms, permCode) } // --------------- TC-0471: MEMBER角色权限+ALLOW-DENY --------------- func TestLoadPerms_MemberRolePermWithAllowDeny(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000014", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) roleId := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "role_" + uid, Remark: "test", Status: consts.StatusEnabled, PermsLevel: 10, CreateTime: ts, UpdateTime: ts, }) urId := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleId, CreateTime: ts, UpdateTime: ts, }) // role perm: permA, permB permIdA := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "permA_" + uid, Code: "permA:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permIdB := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "permB_" + uid, Code: "permB:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) // user ALLOW perm: permC permIdC := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "permC_" + uid, Code: "permC:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) // user DENY perm: permB (should remove permB from result) rpIdA := insertRolePerm(ctx, t, m, &rolePermModel.SysRolePerm{ RoleId: roleId, PermId: permIdA, CreateTime: ts, UpdateTime: ts, }) rpIdB := insertRolePerm(ctx, t, m, &rolePermModel.SysRolePerm{ RoleId: roleId, PermId: permIdB, CreateTime: ts, UpdateTime: ts, }) upAllow := insertUserPerm(ctx, t, m, &userPermModel.SysUserPerm{ UserId: userId, PermId: permIdC, Effect: consts.PermEffectAllow, CreateTime: ts, UpdateTime: ts, }) upDeny := insertUserPerm(ctx, t, m, &userPermModel.SysUserPerm{ UserId: userId, PermId: permIdB, Effect: consts.PermEffectDeny, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_user_perm`", upAllow, upDeny) cleanTable(ctx, conn, "`sys_role_perm`", rpIdA, rpIdB) cleanTable(ctx, conn, "`sys_perm`", permIdA, permIdB, permIdC) cleanTable(ctx, conn, "`sys_user_role`", urId) cleanTable(ctx, conn, "`sys_role`", roleId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) // permA (from role) + permC (from ALLOW) should be present // permB (denied) should NOT be present assert.Contains(t, ud.Perms, "permA:"+uid) assert.Contains(t, ud.Perms, "permC:"+uid) assert.NotContains(t, ud.Perms, "permB:"+uid) } // --------------- TC-0472: loadRoles-多角色取最小permsLevel --------------- func TestLoadRoles_MinPermsLevel(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000015", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) roleId1 := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "roleH_" + uid, Remark: "high", Status: consts.StatusEnabled, PermsLevel: 10, CreateTime: ts, UpdateTime: ts, }) roleId2 := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "roleL_" + uid, Remark: "low", Status: consts.StatusEnabled, PermsLevel: 5, CreateTime: ts, UpdateTime: ts, }) urId1 := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleId1, CreateTime: ts, UpdateTime: ts, }) urId2 := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleId2, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_user_role`", urId1, urId2) cleanTable(ctx, conn, "`sys_role`", roleId1, roleId2) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Len(t, ud.Roles, 2) assert.Equal(t, int64(5), ud.MinPermsLevel) } // --------------- TC-0473: loadRoles-无角色 --------------- func TestLoadRoles_NoRoles(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000016", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, int64(math.MaxInt64), ud.MinPermsLevel) } // --------------- TC-0474: loadRoles-角色跨产品过滤 --------------- func TestLoadRoles_CrossProductFilter(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcodeA := "pA_" + uid pcodeB := "pB_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000017", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pidA := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcodeA, Name: "prodA_" + uid, AppKey: "akA_" + uid, AppSecret: "asA_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pidB := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcodeB, Name: "prodB_" + uid, AppKey: "akB_" + uid, AppSecret: "asB_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memA := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcodeA, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) roleA := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcodeA, Name: "roleA_" + uid, Remark: "A", Status: consts.StatusEnabled, PermsLevel: 10, CreateTime: ts, UpdateTime: ts, }) roleB := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcodeB, Name: "roleB_" + uid, Remark: "B", Status: consts.StatusEnabled, PermsLevel: 20, CreateTime: ts, UpdateTime: ts, }) urA := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleA, CreateTime: ts, UpdateTime: ts, }) urB := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: roleB, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcodeA) loader.Del(ctx, userId, pcodeB) cleanTable(ctx, conn, "`sys_user_role`", urA, urB) cleanTable(ctx, conn, "`sys_role`", roleA, roleB) cleanTable(ctx, conn, "`sys_product_member`", memA) cleanTable(ctx, conn, "`sys_product`", pidA, pidB) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcodeA) ud := loader.Load(ctx, userId, pcodeA) require.NotNil(t, ud) assert.Len(t, ud.Roles, 1) assert.Equal(t, roleA, ud.Roles[0].Id) assert.Equal(t, int64(10), ud.MinPermsLevel) } // --------------- TC-0475: loadRoles-禁用角色不计入 --------------- func TestLoadRoles_DisabledRoleExcluded(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000018", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) enabledRole := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "rEnabled_" + uid, Remark: "enabled", Status: consts.StatusEnabled, PermsLevel: 5, CreateTime: ts, UpdateTime: ts, }) disabledRole := insertRole(ctx, t, m, &roleModel.SysRole{ ProductCode: pcode, Name: "rDisabled_" + uid, Remark: "disabled", Status: consts.StatusDisabled, PermsLevel: 1, CreateTime: ts, UpdateTime: ts, }) ur1 := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: enabledRole, CreateTime: ts, UpdateTime: ts, }) ur2 := insertUserRole(ctx, t, m, &userRoleModel.SysUserRole{ UserId: userId, RoleId: disabledRole, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_user_role`", ur1, ur2) cleanTable(ctx, conn, "`sys_role`", enabledRole, disabledRole) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Len(t, ud.Roles, 1) assert.Equal(t, enabledRole, ud.Roles[0].Id) assert.Equal(t, int64(5), ud.MinPermsLevel) } // --------------- TC-0476: loadMembership-超管自动SUPER_ADMIN --------------- func TestLoadMembership_SuperAdminAuto(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000019", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminYes, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.True(t, ud.IsSuperAdmin) assert.Equal(t, consts.MemberTypeSuperAdmin, ud.MemberType) } // --------------- TC-0477: loadMembership-非成员MemberType为空 --------------- func TestLoadMembership_NonMemberEmpty(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000020", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.False(t, ud.IsSuperAdmin) assert.Empty(t, ud.MemberType) } // --------------- TC-0551: loadPerms-用户ALLOW权限不跨产品泄漏(H-1修复验证) --------------- func TestLoadPerms_CrossProductPermIsolation(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcodeA := "pA_" + uid pcodeB := "pB_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000030", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pidA := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcodeA, Name: "prodA_" + uid, AppKey: "akA_" + uid, AppSecret: "asA_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pidB := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcodeB, Name: "prodB_" + uid, AppKey: "akB_" + uid, AppSecret: "asB_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memA := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcodeA, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memB := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcodeB, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permA := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcodeA, Name: "permA_" + uid, Code: "permA:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permB := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcodeB, Name: "permB_" + uid, Code: "permB:" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) upA := insertUserPerm(ctx, t, m, &userPermModel.SysUserPerm{ UserId: userId, PermId: permA, Effect: consts.PermEffectAllow, CreateTime: ts, UpdateTime: ts, }) upB := insertUserPerm(ctx, t, m, &userPermModel.SysUserPerm{ UserId: userId, PermId: permB, Effect: consts.PermEffectAllow, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcodeA) loader.Del(ctx, userId, pcodeB) cleanTable(ctx, conn, "`sys_user_perm`", upA, upB) cleanTable(ctx, conn, "`sys_perm`", permA, permB) cleanTable(ctx, conn, "`sys_product_member`", memA, memB) cleanTable(ctx, conn, "`sys_product`", pidA, pidB) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcodeA) udA := loader.Load(ctx, userId, pcodeA) require.NotNil(t, udA) assert.Contains(t, udA.Perms, "permA:"+uid, "产品A应包含自身权限") assert.NotContains(t, udA.Perms, "permB:"+uid, "产品A不应包含产品B的权限(H-1)") loader.Del(ctx, userId, pcodeB) udB := loader.Load(ctx, userId, pcodeB) require.NotNil(t, udB) assert.Contains(t, udB.Perms, "permB:"+uid, "产品B应包含自身权限") assert.NotContains(t, udB.Perms, "permA:"+uid, "产品B不应包含产品A的权限(H-1)") } // --------------- TC-0552: loadMembership-禁用成员MemberType为空(H-3修复验证) --------------- func TestLoadMembership_DisabledMemberEmpty(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000031", DeptId: 0, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusDisabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Empty(t, ud.MemberType, "禁用成员的MemberType应为空(H-3)") } // --------------- TC-0553: loadPerms-DEV部门禁用后不再拥有全部权限(M-3修复验证) --------------- func TestLoadPerms_DisabledDevDeptNoFullPerms(t *testing.T) { ctx := context.Background() conn := testConn() m := testModels() loader := newTestLoader() uid := uniqueId() ts := now() pcode := "p_" + uid deptId := insertDept(ctx, t, m, &deptModel.SysDept{ ParentId: 0, Name: "devdept_disabled_" + uid, Path: "/1/", Sort: 1, DeptType: consts.DeptTypeDev, Status: consts.StatusDisabled, CreateTime: ts, UpdateTime: ts, }) userId := insertUser(ctx, t, m, &userModel.SysUser{ Username: uid, Password: hashPwd("pass123"), Nickname: "nick_" + uid, Email: uid + "@test.com", Phone: "13800000032", DeptId: deptId, IsSuperAdmin: consts.IsSuperAdminNo, MustChangePassword: consts.MustChangePasswordNo, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) pid := insertProduct(ctx, t, m, &productModel.SysProduct{ Code: pcode, Name: "prod_" + uid, AppKey: "ak_" + uid, AppSecret: "as_" + uid, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) memberId := insertMember(ctx, t, m, &memberModel.SysProductMember{ ProductCode: pcode, UserId: userId, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) permCode := "perm_devtest:" + uid permId := insertPerm(ctx, t, m, &permModel.SysPerm{ ProductCode: pcode, Name: "p_" + uid, Code: permCode, Status: consts.StatusEnabled, CreateTime: ts, UpdateTime: ts, }) t.Cleanup(func() { loader.Del(ctx, userId, pcode) cleanTable(ctx, conn, "`sys_perm`", permId) cleanTable(ctx, conn, "`sys_product_member`", memberId) cleanTable(ctx, conn, "`sys_product`", pid) cleanTable(ctx, conn, "`sys_user`", userId) cleanTable(ctx, conn, "`sys_dept`", deptId) }) loader.Del(ctx, userId, pcode) ud := loader.Load(ctx, userId, pcode) require.NotNil(t, ud) assert.Equal(t, consts.DeptTypeDev, ud.DeptType) assert.Equal(t, int64(consts.StatusDisabled), ud.DeptStatus) assert.Empty(t, ud.Perms, "禁用的DEV部门成员不应拥有全部权限(M-3)") }