package packagepkg import ( "context" "fmt" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func generateUniquePackageCode(prefix string) string { return fmt.Sprintf("%s_%d", prefix, time.Now().UnixNano()) } func TestPackageService_Create(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) t.Run("创建成功", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_CREATE"), PackageName: "创建测试套餐", PackageType: "formal", DurationMonths: 1, } resp, err := svc.Create(ctx, req) require.NoError(t, err) assert.NotZero(t, resp.ID) assert.Equal(t, req.PackageCode, resp.PackageCode) assert.Equal(t, req.PackageName, resp.PackageName) assert.Equal(t, constants.StatusEnabled, resp.Status) assert.Equal(t, 2, resp.ShelfStatus) }) t.Run("编码重复失败", func(t *testing.T) { code := generateUniquePackageCode("PKG_DUP") req1 := &dto.CreatePackageRequest{ PackageCode: code, PackageName: "第一个套餐", PackageType: "formal", DurationMonths: 1, } _, err := svc.Create(ctx, req1) require.NoError(t, err) req2 := &dto.CreatePackageRequest{ PackageCode: code, PackageName: "第二个套餐", PackageType: "formal", DurationMonths: 1, } _, err = svc.Create(ctx, req2) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeConflict, appErr.Code) }) t.Run("系列不存在失败", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_SERIES"), PackageName: "系列测试套餐", PackageType: "formal", DurationMonths: 1, SeriesID: func() *uint { id := uint(99999); return &id }(), } _, err := svc.Create(ctx, req) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeNotFound, appErr.Code) }) } func TestPackageService_UpdateStatus(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_STATUS"), PackageName: "状态测试套餐", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) t.Run("禁用套餐时自动强制下架", func(t *testing.T) { err := svc.UpdateShelfStatus(ctx, created.ID, 1) require.NoError(t, err) pkg, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 1, pkg.ShelfStatus) err = svc.UpdateStatus(ctx, created.ID, constants.StatusDisabled) require.NoError(t, err) pkg, err = svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, constants.StatusDisabled, pkg.Status) assert.Equal(t, 2, pkg.ShelfStatus) }) t.Run("启用套餐时保持原上架状态", func(t *testing.T) { req2 := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_ENABLE"), PackageName: "启用测试套餐", PackageType: "formal", DurationMonths: 1, } created2, err := svc.Create(ctx, req2) require.NoError(t, err) err = svc.UpdateShelfStatus(ctx, created2.ID, 1) require.NoError(t, err) err = svc.UpdateStatus(ctx, created2.ID, constants.StatusDisabled) require.NoError(t, err) pkg, err := svc.Get(ctx, created2.ID) require.NoError(t, err) assert.Equal(t, constants.StatusDisabled, pkg.Status) assert.Equal(t, 2, pkg.ShelfStatus) err = svc.UpdateStatus(ctx, created2.ID, constants.StatusEnabled) require.NoError(t, err) pkg, err = svc.Get(ctx, created2.ID) require.NoError(t, err) assert.Equal(t, constants.StatusEnabled, pkg.Status) assert.Equal(t, 2, pkg.ShelfStatus) }) } func TestPackageService_UpdateShelfStatus(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) t.Run("启用状态的套餐可以上架", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_SHELF_ENABLE"), PackageName: "上架测试-启用", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) pkg, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 1, pkg.Status) assert.Equal(t, 2, pkg.ShelfStatus) err = svc.UpdateShelfStatus(ctx, created.ID, 1) require.NoError(t, err) pkg, err = svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 1, pkg.ShelfStatus) }) t.Run("禁用状态的套餐不能上架", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_SHELF_DISABLE"), PackageName: "上架测试-禁用", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) err = svc.UpdateStatus(ctx, created.ID, constants.StatusDisabled) require.NoError(t, err) err = svc.UpdateShelfStatus(ctx, created.ID, 1) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeInvalidStatus, appErr.Code) pkg, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 2, pkg.ShelfStatus) }) t.Run("下架成功", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_SHELF_OFF"), PackageName: "下架测试", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) err = svc.UpdateShelfStatus(ctx, created.ID, 1) require.NoError(t, err) pkg, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 1, pkg.ShelfStatus) err = svc.UpdateShelfStatus(ctx, created.ID, 2) require.NoError(t, err) pkg, err = svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, 2, pkg.ShelfStatus) }) } func TestPackageService_Get(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_GET"), PackageName: "查询测试套餐", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) t.Run("获取成功", func(t *testing.T) { resp, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.Equal(t, created.PackageCode, resp.PackageCode) assert.Equal(t, created.PackageName, resp.PackageName) assert.Equal(t, created.ID, resp.ID) }) t.Run("不存在返回错误", func(t *testing.T) { _, err := svc.Get(ctx, 99999) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeNotFound, appErr.Code) }) } func TestPackageService_Update(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_UPDATE"), PackageName: "更新测试套餐", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) t.Run("更新成功", func(t *testing.T) { newName := "更新后的套餐名称" updateReq := &dto.UpdatePackageRequest{ PackageName: &newName, } resp, err := svc.Update(ctx, created.ID, updateReq) require.NoError(t, err) assert.Equal(t, newName, resp.PackageName) }) t.Run("更新不存在的套餐", func(t *testing.T) { newName := "test" updateReq := &dto.UpdatePackageRequest{ PackageName: &newName, } _, err := svc.Update(ctx, 99999, updateReq) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeNotFound, appErr.Code) }) } func TestPackageService_Delete(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_DELETE"), PackageName: "删除测试套餐", PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) t.Run("删除成功", func(t *testing.T) { err := svc.Delete(ctx, created.ID) require.NoError(t, err) _, err = svc.Get(ctx, created.ID) require.Error(t, err) }) t.Run("删除不存在的套餐", func(t *testing.T) { err := svc.Delete(ctx, 99999) require.Error(t, err) }) } func TestPackageService_List(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) packages := []dto.CreatePackageRequest{ { PackageCode: generateUniquePackageCode("PKG_LIST_001"), PackageName: "列表测试套餐1", PackageType: "formal", DurationMonths: 1, }, { PackageCode: generateUniquePackageCode("PKG_LIST_002"), PackageName: "列表测试套餐2", PackageType: "addon", DurationMonths: 1, }, { PackageCode: generateUniquePackageCode("PKG_LIST_003"), PackageName: "列表测试套餐3", PackageType: "formal", DurationMonths: 12, }, } for _, p := range packages { _, err := svc.Create(ctx, &p) require.NoError(t, err) } t.Run("列表查询", func(t *testing.T) { req := &dto.PackageListRequest{ Page: 1, PageSize: 10, } resp, total, err := svc.List(ctx, req) require.NoError(t, err) assert.Greater(t, total, int64(0)) assert.Greater(t, len(resp), 0) }) t.Run("按套餐类型过滤", func(t *testing.T) { packageType := "formal" req := &dto.PackageListRequest{ Page: 1, PageSize: 10, PackageType: &packageType, } resp, _, err := svc.List(ctx, req) require.NoError(t, err) for _, p := range resp { assert.Equal(t, packageType, p.PackageType) } }) t.Run("按状态过滤", func(t *testing.T) { status := constants.StatusEnabled req := &dto.PackageListRequest{ Page: 1, PageSize: 10, Status: &status, } resp, _, err := svc.List(ctx, req) require.NoError(t, err) for _, p := range resp { assert.Equal(t, status, p.Status) } }) } func TestPackageService_VirtualDataValidation(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) t.Run("启用虚流量时虚流量必须大于0", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_VDATA_1"), PackageName: "虚流量测试-零值", PackageType: "formal", DurationMonths: 1, EnableVirtualData: true, RealDataMB: func() *int64 { v := int64(1000); return &v }(), VirtualDataMB: func() *int64 { v := int64(0); return &v }(), } _, err := svc.Create(ctx, req) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeInvalidParam, appErr.Code) assert.Contains(t, appErr.Message, "虚流量额度必须大于0") }) t.Run("启用虚流量时虚流量不能超过真流量", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_VDATA_2"), PackageName: "虚流量测试-超过", PackageType: "formal", DurationMonths: 1, EnableVirtualData: true, RealDataMB: func() *int64 { v := int64(1000); return &v }(), VirtualDataMB: func() *int64 { v := int64(2000); return &v }(), } _, err := svc.Create(ctx, req) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeInvalidParam, appErr.Code) assert.Contains(t, appErr.Message, "虚流量额度不能大于真流量额度") }) t.Run("启用虚流量时配置正确则创建成功", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_VDATA_3"), PackageName: "虚流量测试-正确", PackageType: "formal", DurationMonths: 1, EnableVirtualData: true, RealDataMB: func() *int64 { v := int64(1000); return &v }(), VirtualDataMB: func() *int64 { v := int64(500); return &v }(), } resp, err := svc.Create(ctx, req) require.NoError(t, err) assert.True(t, resp.EnableVirtualData) assert.Equal(t, int64(500), resp.VirtualDataMB) }) t.Run("不启用虚流量时可以不填虚流量值", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_VDATA_4"), PackageName: "虚流量测试-不启用", PackageType: "formal", DurationMonths: 1, EnableVirtualData: false, RealDataMB: func() *int64 { v := int64(1000); return &v }(), } resp, err := svc.Create(ctx, req) require.NoError(t, err) assert.False(t, resp.EnableVirtualData) }) t.Run("更新时校验虚流量配置", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_VDATA_5"), PackageName: "虚流量测试-更新", PackageType: "formal", DurationMonths: 1, EnableVirtualData: false, RealDataMB: func() *int64 { v := int64(1000); return &v }(), } created, err := svc.Create(ctx, req) require.NoError(t, err) enableVD := true virtualDataMB := int64(2000) updateReq := &dto.UpdatePackageRequest{ EnableVirtualData: &enableVD, VirtualDataMB: &virtualDataMB, } _, err = svc.Update(ctx, created.ID, updateReq) require.Error(t, err) appErr, ok := err.(*errors.AppError) require.True(t, ok) assert.Equal(t, errors.CodeInvalidParam, appErr.Code) }) } func TestPackageService_SeriesNameInResponse(t *testing.T) { tx := testutils.NewTestTransaction(t) packageStore := postgres.NewPackageStore(tx) packageSeriesStore := postgres.NewPackageSeriesStore(tx) svc := New(packageStore, packageSeriesStore, nil) ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{ UserID: 1, UserType: constants.UserTypePlatform, }) // 创建套餐系列 series := &model.PackageSeries{ SeriesCode: fmt.Sprintf("SERIES_%d", time.Now().UnixNano()), SeriesName: "测试套餐系列", Description: "用于测试系列名称字段", Status: constants.StatusEnabled, } series.Creator = 1 err := packageSeriesStore.Create(ctx, series) require.NoError(t, err) t.Run("创建套餐时返回系列名称", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_SERIES"), PackageName: "带系列的套餐", SeriesID: &series.ID, PackageType: "formal", DurationMonths: 1, } resp, err := svc.Create(ctx, req) require.NoError(t, err) assert.NotNil(t, resp.SeriesName) assert.Equal(t, series.SeriesName, *resp.SeriesName) }) t.Run("获取套餐时返回系列名称", func(t *testing.T) { // 先创建一个套餐 req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_GET_SERIES"), PackageName: "获取测试套餐", SeriesID: &series.ID, PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) // 获取套餐 resp, err := svc.Get(ctx, created.ID) require.NoError(t, err) assert.NotNil(t, resp.SeriesName) assert.Equal(t, series.SeriesName, *resp.SeriesName) }) t.Run("更新套餐时返回系列名称", func(t *testing.T) { // 先创建一个套餐 req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_UPDATE_SERIES"), PackageName: "更新测试套餐", SeriesID: &series.ID, PackageType: "formal", DurationMonths: 1, } created, err := svc.Create(ctx, req) require.NoError(t, err) // 更新套餐 newName := "更新后的套餐" updateReq := &dto.UpdatePackageRequest{ PackageName: &newName, } resp, err := svc.Update(ctx, created.ID, updateReq) require.NoError(t, err) assert.NotNil(t, resp.SeriesName) assert.Equal(t, series.SeriesName, *resp.SeriesName) }) t.Run("列表查询时返回系列名称", func(t *testing.T) { // 创建多个带系列的套餐 for i := 0; i < 3; i++ { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode(fmt.Sprintf("PKG_LIST_SERIES_%d", i)), PackageName: fmt.Sprintf("列表测试套餐%d", i), SeriesID: &series.ID, PackageType: "formal", DurationMonths: 1, } _, err := svc.Create(ctx, req) require.NoError(t, err) } // 查询列表 listReq := &dto.PackageListRequest{ Page: 1, PageSize: 10, SeriesID: &series.ID, } resp, _, err := svc.List(ctx, listReq) require.NoError(t, err) assert.Greater(t, len(resp), 0) // 验证所有套餐都有系列名称 for _, pkg := range resp { if pkg.SeriesID != nil && *pkg.SeriesID == series.ID { assert.NotNil(t, pkg.SeriesName) assert.Equal(t, series.SeriesName, *pkg.SeriesName) } } }) t.Run("没有系列的套餐SeriesName为空", func(t *testing.T) { req := &dto.CreatePackageRequest{ PackageCode: generateUniquePackageCode("PKG_NO_SERIES"), PackageName: "无系列套餐", PackageType: "formal", DurationMonths: 1, } resp, err := svc.Create(ctx, req) require.NoError(t, err) assert.Nil(t, resp.SeriesID) assert.Nil(t, resp.SeriesName) }) }