| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package role
- import (
- "errors"
- "testing"
- "time"
- "perms-system-server/internal/consts"
- 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/testutil/mocks"
- "perms-system-server/internal/types"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/mock/gomock"
- )
- // TC-0120: 正常更新
- func TestUpdateRole_Normal(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- now := time.Now().Unix()
- pc := testutil.UniqueId()
- res, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
- ProductCode: pc, Name: testutil.UniqueId(), Status: 1, PermsLevel: 1,
- CreateTime: now, UpdateTime: now,
- })
- require.NoError(t, err)
- roleId, _ := res.LastInsertId()
- t.Cleanup(func() {
- testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
- })
- newName := testutil.UniqueId()
- logic := NewUpdateRoleLogic(ctx, svcCtx)
- err = logic.UpdateRole(&types.UpdateRoleReq{
- Id: roleId,
- Name: newName,
- Remark: "updated remark",
- PermsLevel: 2,
- Status: 2,
- })
- require.NoError(t, err)
- updated, err := svcCtx.SysRoleModel.FindOne(ctx, roleId)
- require.NoError(t, err)
- assert.Equal(t, newName, updated.Name)
- assert.Equal(t, "updated remark", updated.Remark)
- assert.Equal(t, int64(2), updated.PermsLevel)
- assert.Equal(t, int64(2), updated.Status)
- }
- // TC-0121: 不存在
- func TestUpdateRole_NotFound(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- logic := NewUpdateRoleLogic(ctx, svcCtx)
- err := logic.UpdateRole(&types.UpdateRoleReq{
- Id: 999999999,
- Name: "whatever",
- PermsLevel: 1,
- })
- require.Error(t, err)
- var ce *response.CodeError
- require.True(t, errors.As(err, &ce))
- assert.Equal(t, 404, ce.Code())
- assert.Equal(t, "角色不存在", ce.Error())
- }
- // TC-0539: updateRole非管理员拒绝
- func TestUpdateRole_MemberRejected(t *testing.T) {
- pc := "test_product"
- ctx := ctxhelper.MemberCtx(pc)
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- now := time.Now().Unix()
- roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
- ProductCode: pc, Name: testutil.UniqueId(), Status: 1, PermsLevel: 1,
- CreateTime: now, UpdateTime: now,
- })
- require.NoError(t, err)
- roleId, _ := roleRes.LastInsertId()
- t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_role`", roleId) })
- logic := NewUpdateRoleLogic(ctx, svcCtx)
- err = logic.UpdateRole(&types.UpdateRoleReq{Id: roleId, Name: "test", PermsLevel: 1})
- require.Error(t, err)
- var ce *response.CodeError
- require.True(t, errors.As(err, &ce))
- assert.Equal(t, 403, ce.Code())
- }
- // 覆盖目标:事务已 COMMIT 成功后,
- // 任何缓存清理路径的失败只应记 Errorf,不得把 degraded 成功映射成 5xx 让客户端误触发重试。
- // adminCtx helper 定义于 bindRolePermsLogic_test.go (同 package role)。
- // TC-1119: L-R14-1 非超管 UpdateRole 访问别产品的 roleId 必须返回 404 "角色不存在",
- // 与 RoleDetail 的 M-N3 口径一致,消除 404 vs 403 的跨产品 roleId 枚举 oracle。
- func TestUpdateRole_L_R14_1_CrossProductReturns404(t *testing.T) {
- ctx := ctxhelper.SuperAdminCtx()
- svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
- conn := testutil.GetTestSqlConn()
- now := time.Now().Unix()
- otherProduct := "l_r14_1_upd_" + testutil.UniqueId()
- res, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
- ProductCode: otherProduct, Name: testutil.UniqueId(), Status: 1, PermsLevel: 1,
- CreateTime: now, UpdateTime: now,
- })
- require.NoError(t, err)
- roleId, _ := res.LastInsertId()
- t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_role`", roleId) })
- adminCtx := ctxhelper.AdminCtx("test_product")
- err = NewUpdateRoleLogic(adminCtx, svcCtx).UpdateRole(&types.UpdateRoleReq{
- Id: roleId, Name: "should_not_update", PermsLevel: 1,
- })
- require.Error(t, err)
- var ce *response.CodeError
- require.True(t, errors.As(err, &ce))
- assert.Equal(t, 404, ce.Code(),
- "L-R14-1:跨产品 roleId 必须 404,不得以 403 暴露存在性")
- assert.Equal(t, "角色不存在", ce.Error(),
- "L-R14-1:文案必须与 'id 不存在' 完全一致,彻底消除枚举 oracle")
- // DB 不得被污染
- after, err := svcCtx.SysRoleModel.FindOne(ctx, roleId)
- require.NoError(t, err)
- assert.NotEqual(t, "should_not_update", after.Name,
- "跨产品被拒绝的请求不得对 DB 产生任何副作用")
- }
- // TC-0859: UpdateRole —— UpdateWithOptLock 成功,FindUserIdsByRoleId 失败,handler 返回 nil。
- func TestUpdateRole_PostCommitUserIdsError_StaysSuccess(t *testing.T) {
- ctrl := gomock.NewController(t)
- t.Cleanup(ctrl.Finish)
- roleMock := mocks.NewMockSysRoleModel(ctrl)
- urMock := mocks.NewMockSysUserRoleModel(ctrl)
- roleMock.EXPECT().FindOne(gomock.Any(), int64(9)).
- Return(&roleModel.SysRole{
- Id: 9, ProductCode: "pc_m4u", Name: "before",
- PermsLevel: 50, Status: consts.StatusEnabled, UpdateTime: 100,
- }, nil)
- // UpdateWithOptLock 成功;签名:UpdateWithOptLock(ctx, role, prevUpdateTime)。
- roleMock.EXPECT().UpdateWithOptLock(gomock.Any(), gomock.Any(), int64(100)).Return(nil)
- // 关键断言:post-commit transient err 不应导致 handler 失败。
- urMock.EXPECT().FindUserIdsByRoleId(gomock.Any(), int64(9)).
- Return(nil, errors.New("boom"))
- svcCtx := mocks.NewMockServiceContext(mocks.MockModels{
- Role: roleMock, UserRole: urMock,
- })
- err := NewUpdateRoleLogic(adminCtx("pc_m4u"), svcCtx).UpdateRole(&types.UpdateRoleReq{
- Id: 9, Name: "after", Remark: "r", PermsLevel: 60, Status: 0,
- })
- assert.NoError(t, err,
- "UpdateRole 已提交成功,post-commit 缓存失败只记日志,handler 必须返回 nil")
- }
|