package creator import ( "fmt" "testing" "time" ) func TestCreatorPostgresWorkAnalysisSourcesFiltersAndOrdering(t *testing.T) { store, accounts, ctx := openCreatorIntegrationStore(t) ownedID := createIntegrationAccount(t, ctx, accounts, "analysis-owned") competitor, err := store.CreateCompetitor(ctx, CompetitorInput{Platform: PlatformDouyin, PlatformAccountKey: "analysis-competitor", Nickname: "分析竞品", HomepageURL: "https://www.douyin.com/user/analysis-competitor"}) if err != nil { t.Fatal(err) } now := time.Now().UTC() older := now.Add(-72 * time.Hour) newer := now.Add(-48 * time.Hour) inputs := []WorkInput{ {Platform: PlatformDouyin, WorkKey: "zero", SourceType: SourceOwned, SourceID: ownedID, PublishedAt: &older, Likes: int64Ptr(0), CommentsCount: int64Ptr(0), Shares: int64Ptr(0), CollectCount: int64Ptr(0), PlayCount: int64Ptr(0)}, {Platform: PlatformDouyin, WorkKey: "positive", SourceType: SourceOwned, SourceID: ownedID, PublishedAt: &newer, Likes: int64Ptr(10), CommentsCount: int64Ptr(10), Shares: int64Ptr(10), CollectCount: int64Ptr(10), PlayCount: int64Ptr(10)}, {Platform: PlatformDouyin, WorkKey: "unknown", SourceType: SourceOwned, SourceID: ownedID}, {Platform: PlatformDouyin, WorkKey: "competitor", SourceType: SourceCompetitor, SourceID: competitor.ID, PublishedAt: &newer, Likes: int64Ptr(999)}, } works := make([]Work, len(inputs)) for i, input := range inputs { work, _, err := store.UpsertWork(ctx, input, now.Add(-26*time.Hour)) if err != nil { t.Fatal(err) } works[i] = work } for _, field := range []string{"published_at", "likes", "comments_count", "shares", "collect_count", "play_count"} { for _, order := range []string{"asc", "desc"} { t.Run(fmt.Sprintf("%s_%s", field, order), func(t *testing.T) { filter := WorkFilter{SourceType: SourceOwned, SortBy: field, SortOrder: order} first := works[0].ID second := works[1].ID if order == "desc" { first, second = second, first } for pageNumber, id := range []string{first, second, works[2].ID} { page, err := store.ListWorksPage(ctx, filter, pageNumber+1, 1) if err != nil || page.Total != 3 || len(page.Data) != 1 || page.Data[0].ID != id { t.Fatalf("page=%+v expected=%s err=%v", page, id, err) } } }) } } for _, filter := range []WorkFilter{ {SourceType: SourceOwned, SourceID: ownedID, MinCollectCount: int64Ptr(0), MinPlayCount: int64Ptr(0)}, {SourceType: SourceOwned, MinLikes: int64Ptr(0), MinComments: int64Ptr(0), MinShares: int64Ptr(0)}, {SourceType: SourceOwned, PublishedAtStatus: "verified"}, } { page, err := store.ListWorksPage(ctx, filter, 1, 10) if err != nil || page.Total != 2 { t.Fatalf("filter=%+v page=%+v err=%v", filter, page, err) } } page, err := store.ListWorksPage(ctx, WorkFilter{SourceType: SourceCompetitor, SourceID: competitor.ID}, 1, 10) if err != nil || page.Total != 1 || page.Data[0].ID != works[3].ID { t.Fatalf("competitor leaked owned works: %+v %v", page, err) } page, err = store.ListWorksPage(ctx, WorkFilter{SourceType: SourceOwned, SourceID: "missing"}, 1, 10) if err != nil || page.Total != 0 || page.Data == nil { t.Fatalf("empty account: %+v %v", page, err) } settings, err := store.GetSettings(ctx) if err != nil { t.Fatal(err) } for i, growth := range []int64{50, 5} { for _, point := range []struct { at time.Time likes int64 }{{now.Add(-25 * time.Hour), 100}, {now.Add(-time.Hour), 100 + growth}} { if _, err := store.RecordMetric(ctx, MetricInput{WorkID: works[i].ID, CollectedAt: point.at, Likes: int64Ptr(point.likes)}, settings, point.at); err != nil { t.Fatal(err) } } } for _, order := range []string{"asc", "desc"} { filter := WorkFilter{SourceType: SourceOwned, SortBy: "likes_growth", SortOrder: order, Growth: WorkGrowthFilter{Hours: 24}} expected := works[0].ID if order == "asc" { expected = works[1].ID } page, err = store.ListWorksPage(ctx, filter, 1, 1) if err != nil || page.Total != 3 || page.Data[0].ID != expected { t.Fatalf("growth ordering: %+v err=%v", page, err) } filter.Growth.MinLikes = int64Ptr(10) page, err = store.ListWorksPage(ctx, filter, 1, 1) if err != nil || page.Total != 1 || page.Data[0].ID != works[0].ID { t.Fatalf("growth threshold before page: %+v err=%v", page, err) } } }