package member import ( "errors" "testing" "perms-system-server/internal/consts" "perms-system-server/internal/loaders" productModel "perms-system-server/internal/model/product" "perms-system-server/internal/model/productmember" "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-1274: 超管查询多产品(mock),正常返回 func TestUserProducts_Mock_SuperAdmin_OK(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockPM := mocks.NewMockSysProductMemberModel(ctrl) mockPM.EXPECT().FindByUserId(gomock.Any(), int64(10)).Return([]*productmember.SysProductMember{ {ProductCode: "crm", UserId: 10, MemberType: "MEMBER", Status: 1}, {ProductCode: "oa", UserId: 10, MemberType: "ADMIN", Status: 1}, }, nil) mockProd := mocks.NewMockSysProductModel(ctrl) mockProd.EXPECT().FindOneByCode(gomock.Any(), "crm").Return(&productModel.SysProduct{Code: "crm", Name: "CRM系统"}, nil) mockProd.EXPECT().FindOneByCode(gomock.Any(), "oa").Return(&productModel.SysProduct{Code: "oa", Name: "OA系统"}, nil) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ ProductMember: mockPM, Product: mockProd, }) logic := NewUserProductsLogic(ctxhelper.SuperAdminCtx(), svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 10}) require.NoError(t, err) require.Len(t, resp.List, 2) assert.Equal(t, "crm", resp.List[0].ProductCode) assert.Equal(t, "CRM系统", resp.List[0].ProductName) assert.Equal(t, "MEMBER", resp.List[0].MemberType) assert.Equal(t, "oa", resp.List[1].ProductCode) assert.Equal(t, "ADMIN", resp.List[1].MemberType) } // TC-1275: 本人查询自己的产品列表(mock),正常返回 func TestUserProducts_Mock_Self_OK(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockPM := mocks.NewMockSysProductMemberModel(ctrl) mockPM.EXPECT().FindByUserId(gomock.Any(), int64(20)).Return([]*productmember.SysProductMember{ {ProductCode: "crm", UserId: 20, MemberType: "MEMBER", Status: 1}, }, nil) mockProd := mocks.NewMockSysProductModel(ctrl) mockProd.EXPECT().FindOneByCode(gomock.Any(), "crm").Return(&productModel.SysProduct{Code: "crm", Name: "CRM系统"}, nil) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ ProductMember: mockPM, Product: mockProd, }) ctx := ctxhelper.CustomCtx(&loaders.UserDetails{ UserId: 20, Username: "user20", IsSuperAdmin: false, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, ProductCode: "crm", }) logic := NewUserProductsLogic(ctx, svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 20}) require.NoError(t, err) require.Len(t, resp.List, 1) assert.Equal(t, "crm", resp.List[0].ProductCode) } // TC-1276: 非超管查询他人产品列表(mock),返回 403 func TestUserProducts_Mock_OtherUser_Forbidden(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() svcCtx := mocks.NewMockServiceContext(mocks.MockModels{}) ctx := ctxhelper.CustomCtx(&loaders.UserDetails{ UserId: 20, Username: "user20", IsSuperAdmin: false, MemberType: consts.MemberTypeMember, Status: consts.StatusEnabled, ProductCode: "crm", }) logic := NewUserProductsLogic(ctx, svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 99}) assert.Nil(t, resp) assert.Error(t, err) assert.Contains(t, err.Error(), "无权查看他人") } // TC-1277: FindByUserId 数据库错误,向上透传(mock) func TestUserProducts_Mock_DBError(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() dbErr := errors.New("db error") mockPM := mocks.NewMockSysProductMemberModel(ctrl) mockPM.EXPECT().FindByUserId(gomock.Any(), int64(10)).Return(nil, dbErr) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ ProductMember: mockPM, }) logic := NewUserProductsLogic(ctxhelper.SuperAdminCtx(), svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 10}) assert.Nil(t, resp) assert.ErrorIs(t, err, dbErr) } // TC-1278: 产品查询失败时跳过该条记录(mock,容错) func TestUserProducts_Mock_ProductNotFound_Skip(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockPM := mocks.NewMockSysProductMemberModel(ctrl) mockPM.EXPECT().FindByUserId(gomock.Any(), int64(10)).Return([]*productmember.SysProductMember{ {ProductCode: "crm", UserId: 10, MemberType: "MEMBER", Status: 1}, {ProductCode: "ghost", UserId: 10, MemberType: "MEMBER", Status: 1}, }, nil) mockProd := mocks.NewMockSysProductModel(ctrl) mockProd.EXPECT().FindOneByCode(gomock.Any(), "crm").Return(&productModel.SysProduct{Code: "crm", Name: "CRM系统"}, nil) mockProd.EXPECT().FindOneByCode(gomock.Any(), "ghost").Return(nil, errors.New("not found")) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ ProductMember: mockPM, Product: mockProd, }) logic := NewUserProductsLogic(ctxhelper.SuperAdminCtx(), svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 10}) require.NoError(t, err) require.Len(t, resp.List, 1) assert.Equal(t, "crm", resp.List[0].ProductCode) } // TC-1279: 用户未加入任何产品,返回空列表(mock) func TestUserProducts_Mock_Empty(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockPM := mocks.NewMockSysProductMemberModel(ctrl) mockPM.EXPECT().FindByUserId(gomock.Any(), int64(10)).Return([]*productmember.SysProductMember{}, nil) svcCtx := mocks.NewMockServiceContext(mocks.MockModels{ ProductMember: mockPM, }) logic := NewUserProductsLogic(ctxhelper.SuperAdminCtx(), svcCtx) resp, err := logic.UserProducts(&types.UserProductsReq{UserId: 10}) require.NoError(t, err) assert.Empty(t, resp.List) }