Files
creator-hub/internal/creator/competitor_share_jobs_test.go
T
rogee 03f6145a61 fix(creator): 修复导入页列表 SQL —— join 缺别名导致 /accounts/import 一进来就 500
- ListCompetitorShareJobsWithAuthor 的 LEFT JOIN creator_competitor 缺 AS competitor
  别名,ON 条件引用 competitor.id 直接报 missing FROM-clause entry(42P01)
- competitorShareJobFilter 过滤条件误用原表名 creator_competitor_share_job,
  与查询别名 share_job 不符,带 platform/status 参数时会再报缺列
- 新增集成测试 TestListCompetitorShareJobsWithAuthorSQL 覆盖 join 作者回填
  与 platform/status 过滤(此前该 SQL 无任何测试,bug 逃逸)
2026-09-28 09:19:02 +08:00

109 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package creator
import (
"errors"
"testing"
"time"
)
func TestNormalizeCompetitorShareJobInput(t *testing.T) {
job, err := normalizeCompetitorShareJobInput(CompetitorShareJobInput{
Platform: " douyin ",
ShareURL: " https://v.douyin.com/share-a/ ",
})
if err != nil {
t.Fatal(err)
}
if job.Platform != PlatformDouyin || job.ShareURL != "https://v.douyin.com/share-a/" || job.Tags == nil {
t.Fatalf("normalized job = %+v", job)
}
for _, input := range []CompetitorShareJobInput{
{Platform: PlatformDouyin, ShareURL: "http://v.douyin.com/share-a/"},
{Platform: "unsupported", ShareURL: "https://v.douyin.com/share-a/"},
{Platform: PlatformDouyin, ShareURL: "https://v.douyin.com/share-a/#fragment"},
} {
if _, err := normalizeCompetitorShareJobInput(input); !errors.Is(err, ErrInvalid) {
t.Fatalf("input %+v returned err=%v", input, err)
}
}
}
// 集成测试:ListCompetitorShareJobsWithAuthor 的 SQL(join 别名 + 过滤条件别名)必须真实可执行。
// 回归背景:LEFT JOIN creator_competitor ON competitor.id=... 缺 AS competitor 别名,
// 过滤条件误用原表名而非 share_job 别名,导入页一进来就 500 "creator operation failed"。
func TestListCompetitorShareJobsWithAuthorSQL(t *testing.T) {
store, _, ctx := openCreatorIntegrationStore(t)
if err := store.Ping(ctx); err != nil {
t.Fatal(err)
}
if err := store.EnsureSchema(ctx); err != nil {
t.Fatal(err)
}
job, err := store.CreateCompetitorShareJob(ctx, CompetitorShareJobInput{
Platform: PlatformDouyin, ShareURL: "https://v.douyin.com/import-author-sql/",
})
if err != nil {
t.Fatal(err)
}
competitor, err := store.UpsertCompetitor(ctx, CompetitorInput{
Platform: PlatformDouyin, PlatformAccountKey: "sec_uid_import-author-sql",
Nickname: "解析作者", AvatarURL: "https://example.com/a.jpg",
HomepageURL: "https://www.douyin.com/user/import-author-sql",
})
if err != nil {
t.Fatal(err)
}
_, token, ok, err := store.ClaimCompetitorShareJob(ctx, job.ID, time.Now().UTC())
if err != nil || !ok {
t.Fatalf("claim job: ok=%v err=%v", ok, err)
}
if err := store.MarkCompetitorShareJob(ctx, job.ID, token, CompetitorShareJobSucceeded, competitor.ID, ""); err != nil {
t.Fatal(err)
}
if _, err := store.CreateCompetitorShareJob(ctx, CompetitorShareJobInput{
Platform: PlatformDouyin, ShareURL: "https://v.douyin.com/import-author-sql-other/",
}); err != nil {
t.Fatal(err)
}
// 无过滤:两条任务都能列出,成功任务带作者信息。
items, err := store.ListCompetitorShareJobsWithAuthor(ctx, "", "")
if err != nil {
t.Fatalf("list with author: %v", err)
}
if len(items) != 2 {
t.Fatalf("items = %d, want 2", len(items))
}
var matched bool
for _, item := range items {
if item.ID != job.ID {
continue
}
matched = true
if item.AuthorName != "解析作者" || item.AuthorAvatarURL != "https://example.com/a.jpg" || item.CompetitorID != competitor.ID {
t.Fatalf("author view = %+v", item)
}
}
if !matched {
t.Fatalf("job %s missing in list", job.ID)
}
// platform+status 过滤:条件引用 join 别名,不能报缺列。
filtered, err := store.ListCompetitorShareJobsWithAuthor(ctx, PlatformDouyin, CompetitorShareJobSucceeded)
if err != nil {
t.Fatalf("list filtered: %v", err)
}
if len(filtered) != 1 || filtered[0].ID != job.ID {
t.Fatalf("filtered = %+v", filtered)
}
none, err := store.ListCompetitorShareJobsWithAuthor(ctx, PlatformDouyin, CompetitorShareJobFailed)
if err != nil {
t.Fatalf("list filtered empty: %v", err)
}
if len(none) != 0 {
t.Fatalf("expected empty, got %+v", none)
}
}