package services import ( "context" "database/sql" "testing" "quyun/v2/app/commands/testx" creator_dto "quyun/v2/app/http/v1/dto" "quyun/v2/database" "quyun/v2/database/models" "quyun/v2/pkg/consts" . "github.com/smartystreets/goconvey/convey" "github.com/spf13/cast" "github.com/stretchr/testify/suite" "go.ipao.vip/atom/contracts" "go.uber.org/dig" ) type CreatorTestSuiteInjectParams struct { dig.In DB *sql.DB Initials []contracts.Initial `group:"initials"` } type CreatorTestSuite struct { suite.Suite CreatorTestSuiteInjectParams } func Test_Creator(t *testing.T) { providers := testx.Default().With(Provide) testx.Serve(providers, t, func(p CreatorTestSuiteInjectParams) { suite.Run(t, &CreatorTestSuite{CreatorTestSuiteInjectParams: p}) }) } func (s *CreatorTestSuite) Test_Apply() { Convey("Apply", s.T(), func() { ctx := s.T().Context() database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameTenantUser, models.TableNameUser) u := &models.User{Username: "creator1", Phone: "13700000001"} models.UserQuery.WithContext(ctx).Create(u) ctx = context.WithValue(ctx, consts.CtxKeyUser, u.ID) Convey("should create tenant", func() { form := &creator_dto.ApplyForm{ Name: "My Channel", } err := Creator.Apply(ctx, form) So(err, ShouldBeNil) t, _ := models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.UserID.Eq(u.ID)).First() So(t, ShouldNotBeNil) So(t.Name, ShouldEqual, "My Channel") So(t.Status, ShouldEqual, consts.TenantStatusPendingVerify) // Check admin role tu, _ := models.TenantUserQuery.WithContext(ctx).Where(models.TenantUserQuery.TenantID.Eq(t.ID)).First() So(tu, ShouldNotBeNil) // Role is array, check contains? Or first element? // types.Array is likely []T. So(len(tu.Role), ShouldEqual, 1) So(tu.Role[0], ShouldEqual, consts.TenantUserRoleTenantAdmin) }) }) } func (s *CreatorTestSuite) Test_CreateContent() { Convey("CreateContent", s.T(), func() { ctx := s.T().Context() database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameContent, models.TableNameContentAsset, models.TableNameContentPrice, models.TableNameUser) u := &models.User{Username: "creator2", Phone: "13700000002"} models.UserQuery.WithContext(ctx).Create(u) ctx = context.WithValue(ctx, consts.CtxKeyUser, u.ID) // Create Tenant manually t := &models.Tenant{UserID: u.ID, Name: "Channel 2", Code: "123", Status: consts.TenantStatusVerified} models.TenantQuery.WithContext(ctx).Create(t) Convey("should create content and assets", func() { form := &creator_dto.ContentCreateForm{ Title: "New Song", Genre: "audio", Price: 9.99, // MediaIDs: ... need media asset } err := Creator.CreateContent(ctx, form) So(err, ShouldBeNil) c, _ := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.Title.Eq("New Song")).First() So(c, ShouldNotBeNil) So(c.UserID, ShouldEqual, u.ID) So(c.TenantID, ShouldEqual, t.ID) // Check Price p, _ := models.ContentPriceQuery.WithContext(ctx).Where(models.ContentPriceQuery.ContentID.Eq(c.ID)).First() So(p, ShouldNotBeNil) So(p.PriceAmount, ShouldEqual, 999) }) }) } func (s *CreatorTestSuite) Test_UpdateContent() { Convey("UpdateContent", s.T(), func() { ctx := s.T().Context() database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameContent, models.TableNameContentAsset, models.TableNameContentPrice, models.TableNameUser) u := &models.User{Username: "creator3", Phone: "13700000003"} models.UserQuery.WithContext(ctx).Create(u) ctx = context.WithValue(ctx, consts.CtxKeyUser, u.ID) t := &models.Tenant{UserID: u.ID, Name: "Channel 3", Code: "124", Status: consts.TenantStatusVerified} models.TenantQuery.WithContext(ctx).Create(t) c := &models.Content{TenantID: t.ID, UserID: u.ID, Title: "Old Title", Genre: "audio"} models.ContentQuery.WithContext(ctx).Create(c) models.ContentPriceQuery.WithContext(ctx).Create(&models.ContentPrice{TenantID: t.ID, UserID: u.ID, ContentID: c.ID, PriceAmount: 100}) Convey("should update content", func() { form := &creator_dto.ContentUpdateForm{ Title: "New Title", Genre: "video", Price: 20.00, } err := Creator.UpdateContent(ctx, cast.ToString(c.ID), form) So(err, ShouldBeNil) // Verify cReload, _ := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(c.ID)).First() So(cReload.Title, ShouldEqual, "New Title") So(cReload.Genre, ShouldEqual, "video") p, _ := models.ContentPriceQuery.WithContext(ctx).Where(models.ContentPriceQuery.ContentID.Eq(c.ID)).First() So(p.PriceAmount, ShouldEqual, 2000) }) }) } func (s *CreatorTestSuite) Test_Dashboard() { Convey("Dashboard", s.T(), func() { ctx := s.T().Context() database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameTenantUser, models.TableNameTenantLedger, models.TableNameUser, models.TableNameOrder) u := &models.User{Username: "creator4", Phone: "13700000004"} models.UserQuery.WithContext(ctx).Create(u) ctx = context.WithValue(ctx, consts.CtxKeyUser, u.ID) t := &models.Tenant{UserID: u.ID, Name: "Channel 4", Code: "125", Status: consts.TenantStatusVerified} models.TenantQuery.WithContext(ctx).Create(t) // Mock Data // 1. Followers models.TenantUserQuery.WithContext(ctx).Create( &models.TenantUser{TenantID: t.ID, UserID: 100}, &models.TenantUser{TenantID: t.ID, UserID: 101}, ) // 2. Revenue (Ledgers) models.TenantLedgerQuery.WithContext(ctx).Create( &models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeDebitPurchase, Amount: 1000}, // 10.00 &models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeDebitPurchase, Amount: 2000}, // 20.00 &models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeCreditRefund, Amount: 500}, // -5.00 (Refund, currently Dashboard sums DebitPurchase only, ideally should subtract refunds, but let's stick to implementation) ) Convey("should get stats", func() { stats, err := Creator.Dashboard(ctx) So(err, ShouldBeNil) So(stats.TotalFollowers.Value, ShouldEqual, 2) // Implementation sums 'debit_purchase' only based on my code So(stats.TotalRevenue.Value, ShouldEqual, 30.00) }) }) }