diff --git a/backend/app/services/content_test.go b/backend/app/services/content_test.go index cbd3fc3..09c6cb0 100644 --- a/backend/app/services/content_test.go +++ b/backend/app/services/content_test.go @@ -195,6 +195,54 @@ func (s *ContentTestSuite) Test_AttachAsset() { So(m.AssetID, ShouldEqual, asset.ID) So(m.Role, ShouldEqual, consts.ContentAssetRoleMain) }) + + Convey("preview role 只能绑定 preview variant,且必须有 source_asset_id", func() { + previewAsset := &models.MediaAsset{ + TenantID: tenantID, + UserID: userID, + Type: consts.MediaAssetTypeVideo, + Status: consts.MediaAssetStatusReady, + Provider: "test", + Bucket: "bucket", + ObjectKey: "obj-preview", + Meta: types.JSON([]byte("{}")), + } + So(previewAsset.Create(ctx), ShouldBeNil) + + // 标记为 preview 产物,但不设置 source_asset_id,应被拒绝。 + _, err := s.DB.ExecContext(ctx, "UPDATE media_assets SET variant = 'preview', source_asset_id = NULL WHERE tenant_id = $1 AND id = $2", tenantID, previewAsset.ID) + So(err, ShouldBeNil) + + _, err = Content.AttachAsset(ctx, tenantID, userID, content.ID, previewAsset.ID, consts.ContentAssetRolePreview, 1, now) + So(err, ShouldNotBeNil) + var appErr *errorx.AppError + So(errors.As(err, &appErr), ShouldBeTrue) + So(appErr.Code, ShouldEqual, errorx.ErrPreconditionFailed.Code) + }) + + Convey("main role 绑定 preview variant 应被拒绝", func() { + previewAsset := &models.MediaAsset{ + TenantID: tenantID, + UserID: userID, + Type: consts.MediaAssetTypeVideo, + Status: consts.MediaAssetStatusReady, + Provider: "test", + Bucket: "bucket", + ObjectKey: "obj-preview2", + Meta: types.JSON([]byte("{}")), + } + So(previewAsset.Create(ctx), ShouldBeNil) + + // 将该资源标记为 preview 产物,并设置一个合法来源(指向已有 main 资源 asset)。 + _, err := s.DB.ExecContext(ctx, "UPDATE media_assets SET variant = 'preview', source_asset_id = $1 WHERE tenant_id = $2 AND id = $3", asset.ID, tenantID, previewAsset.ID) + So(err, ShouldBeNil) + + _, err = Content.AttachAsset(ctx, tenantID, userID, content.ID, previewAsset.ID, consts.ContentAssetRoleMain, 1, now) + So(err, ShouldNotBeNil) + var appErr *errorx.AppError + So(errors.As(err, &appErr), ShouldBeTrue) + So(appErr.Code, ShouldEqual, errorx.ErrPreconditionFailed.Code) + }) }) } diff --git a/backend/app/services/media_asset_test.go b/backend/app/services/media_asset_test.go new file mode 100644 index 0000000..8d6afea --- /dev/null +++ b/backend/app/services/media_asset_test.go @@ -0,0 +1,109 @@ +package services + +import ( + "database/sql" + "errors" + "testing" + "time" + + "quyun/v2/app/commands/testx" + "quyun/v2/app/errorx" + tenant_dto "quyun/v2/app/http/tenant/dto" + "quyun/v2/database" + "quyun/v2/database/models" + "quyun/v2/pkg/consts" + + . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/suite" + + _ "go.ipao.vip/atom" + "go.ipao.vip/atom/contracts" + "go.ipao.vip/gen/types" + "go.uber.org/dig" +) + +type MediaAssetTestSuiteInjectParams struct { + dig.In + + DB *sql.DB + Initials []contracts.Initial `group:"initials"` // nolint:structcheck +} + +type MediaAssetTestSuite struct { + suite.Suite + MediaAssetTestSuiteInjectParams +} + +func Test_MediaAsset(t *testing.T) { + providers := testx.Default().With(Provide) + + testx.Serve(providers, t, func(p MediaAssetTestSuiteInjectParams) { + suite.Run(t, &MediaAssetTestSuite{MediaAssetTestSuiteInjectParams: p}) + }) +} + +func (s *MediaAssetTestSuite) Test_AdminUploadInit_VariantAndSource() { + Convey("MediaAsset.AdminUploadInit variant/source_asset_id", s.T(), func() { + ctx := s.T().Context() + now := time.Now().UTC() + tenantID := int64(1) + userID := int64(2) + + database.Truncate(ctx, s.DB, models.TableNameMediaAsset) + + Convey("main variant 不允许 source_asset_id", func() { + src := int64(123) + _, err := MediaAsset.AdminUploadInit(ctx, tenantID, userID, &tenant_dto.AdminMediaAssetUploadInitForm{ + Type: "video", + Variant: "main", + SourceAssetID: &src, + }, now) + So(err, ShouldNotBeNil) + var appErr *errorx.AppError + So(errors.As(err, &appErr), ShouldBeTrue) + So(appErr.Code, ShouldEqual, errorx.ErrInvalidParameter.Code) + }) + + Convey("preview variant 必须带 source_asset_id", func() { + _, err := MediaAsset.AdminUploadInit(ctx, tenantID, userID, &tenant_dto.AdminMediaAssetUploadInitForm{ + Type: "video", + Variant: "preview", + }, now) + So(err, ShouldNotBeNil) + var appErr *errorx.AppError + So(errors.As(err, &appErr), ShouldBeTrue) + So(appErr.Code, ShouldEqual, errorx.ErrInvalidParameter.Code) + }) + + Convey("preview variant 的 source_asset_id 必须存在且为 main variant", func() { + src := &models.MediaAsset{ + TenantID: tenantID, + UserID: userID, + Type: consts.MediaAssetTypeVideo, + Status: consts.MediaAssetStatusReady, + Provider: "test", + Bucket: "b", + ObjectKey: "k", + Meta: types.JSON([]byte("{}")), + CreatedAt: now, + UpdatedAt: now, + } + So(src.Create(ctx), ShouldBeNil) + + // 将来源资源标记为 preview,模拟“来源不是 main”的非法情况。 + _, err := s.DB.ExecContext(ctx, "UPDATE media_assets SET variant = 'preview' WHERE tenant_id = $1 AND id = $2", tenantID, src.ID) + So(err, ShouldBeNil) + + _, err = MediaAsset.AdminUploadInit(ctx, tenantID, userID, &tenant_dto.AdminMediaAssetUploadInitForm{ + Type: "video", + Variant: "preview", + SourceAssetID: &src.ID, + }, now) + So(err, ShouldNotBeNil) + var appErr *errorx.AppError + So(errors.As(err, &appErr), ShouldBeTrue) + So(appErr.Code, ShouldEqual, errorx.ErrPreconditionFailed.Code) + }) + }) +} +