package user import ( "errors" "testing" "time" memberModel "perms-system-server/internal/model/productmember" roleModel "perms-system-server/internal/model/role" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/testutil" "perms-system-server/internal/testutil/ctxhelper" "perms-system-server/internal/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func insertTestMember(t *testing.T, svcCtx *svc.ServiceContext, productCode string, userId int64) int64 { t.Helper() now := time.Now().Unix() res, err := svcCtx.SysProductMemberModel.Insert(ctxhelper.SuperAdminCtx(), &memberModel.SysProductMember{ ProductCode: productCode, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: now, UpdateTime: now, }) require.NoError(t, err) id, _ := res.LastInsertId() return id } func insertTestRole(t *testing.T, svcCtx *svc.ServiceContext, productCode string, status int64) int64 { t.Helper() now := time.Now().Unix() res, err := svcCtx.SysRoleModel.Insert(ctxhelper.SuperAdminCtx(), &roleModel.SysRole{ ProductCode: productCode, Name: "role_" + testutil.UniqueId(), Status: status, PermsLevel: 1, CreateTime: now, UpdateTime: now, }) require.NoError(t, err) id, _ := res.LastInsertId() return id } // TC-0133: 正常绑定 func TestBindRoles_Success(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) r1 := insertTestRole(t, svcCtx, "test_product", 1) r2 := insertTestRole(t, svcCtx, "test_product", 1) t.Cleanup(func() { testutil.CleanTableByField(ctx, conn, "`sys_user_role`", "userId", userId) testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) testutil.CleanTable(ctx, conn, "`sys_role`", r1, r2) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{r1, r2}, }) require.NoError(t, err) roleIds, err := svcCtx.SysUserRoleModel.FindRoleIdsByUserId(ctx, userId) require.NoError(t, err) assert.ElementsMatch(t, []int64{r1, r2}, roleIds) } // TC-0134: 用户不存在 func TestBindRoles_UserNotFound(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: 999999999, RoleIds: []int64{1}, }) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 404, codeErr.Code()) assert.Equal(t, "用户不存在", codeErr.Error()) } // TC-0135: 清空角色 func TestBindRoles_EmptyRoleIds_ClearsAll(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) r1 := insertTestRole(t, svcCtx, "test_product", 1) t.Cleanup(func() { testutil.CleanTableByField(ctx, conn, "`sys_user_role`", "userId", userId) testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) testutil.CleanTable(ctx, conn, "`sys_role`", r1) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{r1}, }) require.NoError(t, err) err = logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{}, }) require.NoError(t, err) roleIds, err := svcCtx.SysUserRoleModel.FindRoleIdsByUserId(ctx, userId) require.NoError(t, err) assert.Empty(t, roleIds) } // TC-0133: 正常重新绑定 func TestBindRoles_Rebind(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) r1 := insertTestRole(t, svcCtx, "test_product", 1) r2 := insertTestRole(t, svcCtx, "test_product", 1) r3 := insertTestRole(t, svcCtx, "test_product", 1) t.Cleanup(func() { testutil.CleanTableByField(ctx, conn, "`sys_user_role`", "userId", userId) testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) testutil.CleanTable(ctx, conn, "`sys_role`", r1, r2, r3) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{r1, r2}, }) require.NoError(t, err) err = logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{r2, r3}, }) require.NoError(t, err) roleIds, err := svcCtx.SysUserRoleModel.FindRoleIdsByUserId(ctx, userId) require.NoError(t, err) assert.ElementsMatch(t, []int64{r2, r3}, roleIds) } // TC-0515: 角色不属于当前产品 func TestBindRoles_RoleBelongsToOtherProduct(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) otherRole := insertTestRole(t, svcCtx, "other_product", 1) t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) testutil.CleanTable(ctx, conn, "`sys_role`", otherRole) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{otherRole}, }) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "其他产品的角色") } // TC-0516: 角色已禁用 func TestBindRoles_RoleDisabled(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) disabledRole := insertTestRole(t, svcCtx, "test_product", 2) t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) testutil.CleanTable(ctx, conn, "`sys_role`", disabledRole) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{disabledRole}, }) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "已禁用的角色") } // TC-0517: 角色不存在 func TestBindRoles_RoleNotExists(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) mId := insertTestMember(t, svcCtx, "test_product", userId) t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", mId) testutil.CleanTable(ctx, conn, "`sys_user`", userId) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{999999999}, }) require.Error(t, err) var codeErr *response.CodeError require.True(t, errors.As(err, &codeErr)) assert.Equal(t, 400, codeErr.Code()) assert.Contains(t, codeErr.Error(), "无效的角色ID") } // TC-0549: 目标用户不是当前产品成员时拒绝绑定角色(L-4修复验证) func TestBindRoles_NonMemberRejected(t *testing.T) { ctx := ctxhelper.SuperAdminCtx() svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) conn := testutil.GetTestSqlConn() username := testutil.UniqueId() userId := insertTestUser(t, ctx, username, testutil.HashPassword("pass")) t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_user`", userId) }) logic := NewBindRolesLogic(ctx, svcCtx) err := logic.BindRoles(&types.BindRolesReq{ UserId: userId, RoleIds: []int64{}, }) require.Error(t, err) var codeErr2 *response.CodeError require.True(t, errors.As(err, &codeErr2)) assert.Equal(t, 400, codeErr2.Code()) assert.Contains(t, codeErr2.Error(), "不是当前产品的成员") }