package role import ( "context" "errors" "testing" permModel "perms-system-server/internal/model/perm" roleModel "perms-system-server/internal/model/role" "perms-system-server/internal/testutil/ctxhelper" "perms-system-server/internal/testutil/mocks" "perms-system-server/internal/types" "github.com/stretchr/testify/assert" "github.com/zeromicro/go-zero/core/stores/sqlx" "go.uber.org/mock/gomock" ) // TC-0133: 事务回滚 func TestBindRolePerms_Mock_BatchInsertFail(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() dbErr := errors.New("db error") pc := "test_product" mockRole := mocks.NewMockSysRoleModel(ctrl) mockRole.EXPECT().FindOne(gomock.Any(), int64(1)). Return(&roleModel.SysRole{Id: 1, ProductCode: pc}, nil) mockPerm := mocks.NewMockSysPermModel(ctrl) mockPerm.EXPECT().FindByIds(gomock.Any(), []int64{10, 20}). Return([]*permModel.SysPerm{ {Id: 10, ProductCode: pc, Code: "perm_10", Status: 1}, {Id: 20, ProductCode: pc, Code: "perm_20", Status: 1}, }, nil) // 事务内以 LockByIdTx 锁 sys_role 行,再走 FindPermIdsByRoleIdTx 读最新 diff 基准 mockRole.EXPECT().LockByIdTx(gomock.Any(), nil, int64(1)). Return(&roleModel.SysRole{Id: 1, ProductCode: pc}, nil) mockRP := mocks.NewMockSysRolePermModel(ctrl) mockRP.EXPECT().FindPermIdsByRoleIdTx(gomock.Any(), nil, int64(1)).Return([]int64{}, nil) mockRP.EXPECT().TableName().Return("`sys_role_perm`").AnyTimes() mockRP.EXPECT().TransactCtx(gomock.Any(), gomock.Any()). DoAndReturn(func(ctx context.Context, fn func(context.Context, sqlx.Session) error) error { return fn(ctx, nil) }) // audit 修复:循环 DELETE 替换为批量 DeleteByRoleIdAndPermIdsTx;toRemove 为空时也被调用 mockRP.EXPECT().DeleteByRoleIdAndPermIdsTx(gomock.Any(), nil, int64(1), []int64(nil)).Return(nil) mockRP.EXPECT().BatchInsertWithTx(gomock.Any(), nil, gomock.Any()).Return(dbErr) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ Role: mockRole, Perm: mockPerm, RolePerm: mockRP, }) logic := NewBindRolePermsLogic(ctxhelper.SuperAdminCtx(), svcCtx) err := logic.BindRolePerms(&types.BindPermsReq{ RoleId: 1, PermIds: []int64{10, 20}, }) assert.Error(t, err) assert.ErrorIs(t, err, dbErr) }