114 lines
4.6 KiB
Go
114 lines
4.6 KiB
Go
package creator
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestWorkCoversUseUIDWorkIDFilesForOwnedAndCompetitor(t *testing.T) {
|
|
store, accounts, ctx := openCreatorIntegrationStore(t)
|
|
accountID := createIntegrationAccount(t, ctx, accounts, "cover-files")
|
|
owned, err := accounts.GetAccount(ctx, accountID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
competitor, err := store.CreateCompetitor(ctx, CompetitorInput{Platform: PlatformDouyin, PlatformAccountKey: "cover-target-uid", Nickname: "封面账号", HomepageURL: "https://www.douyin.com/user/cover-target"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, source := range []struct{ kind, id, uid string }{{SourceOwned, owned.ID, owned.PlatformAccountKey}, {SourceCompetitor, competitor.ID, competitor.PlatformAccountKey}} {
|
|
work, _, err := store.UpsertWork(ctx, WorkInput{SourceType: source.kind, SourceID: source.id, Platform: PlatformDouyin, WorkKey: "7312345678901234567-" + source.kind, Title: "封面作品", CoverURL: "https://p3.douyinpic.com/cover"}, time.Now().UTC())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
missing, err := store.ListWorksMissingCover(ctx, source.kind, source.id)
|
|
if err != nil || len(missing) != 1 {
|
|
t.Fatalf("missing: %v %v", missing, err)
|
|
}
|
|
if _, err := store.GetWorkCover(ctx, work.ID); !errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("missing cover: %v", err)
|
|
}
|
|
if err := store.SaveWorkCover(ctx, work.ID, "image/png", []byte("first-cover")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
path, err := store.GetWorkCover(ctx, work.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := filepath.Join(store.coverDirectory, source.uid, work.WorkKey+".png")
|
|
if path != want {
|
|
t.Fatalf("cover path=%q want=%q", path, want)
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil || string(data) != "first-cover" {
|
|
t.Fatalf("file: %q %v", data, err)
|
|
}
|
|
missing, err = store.ListWorksMissingCover(ctx, source.kind, source.id)
|
|
if err != nil || len(missing) != 0 {
|
|
t.Fatalf("cached work still missing: %v %v", missing, err)
|
|
}
|
|
if err := store.SaveWorkCover(ctx, work.ID, "image/webp", []byte("replacement")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(want); !errors.Is(err, os.ErrNotExist) {
|
|
t.Fatalf("old extension still exists: %v", err)
|
|
}
|
|
path, err = store.GetWorkCover(ctx, work.ID)
|
|
if err != nil || filepath.Ext(path) != ".webp" {
|
|
t.Fatalf("replacement path: %q %v", path, err)
|
|
}
|
|
data, err = os.ReadFile(path)
|
|
if err != nil || string(data) != "replacement" {
|
|
t.Fatalf("replacement: %q %v", data, err)
|
|
}
|
|
}
|
|
var obsoleteTableExists bool
|
|
if err := store.db.QueryRowContext(ctx, `SELECT to_regclass('creator_work_cover') IS NOT NULL`).Scan(&obsoleteTableExists); err != nil || obsoleteTableExists {
|
|
t.Fatalf("image-byte table remains: %v %v", obsoleteTableExists, err)
|
|
}
|
|
}
|
|
|
|
func TestWorkCoverFilesExposeFailuresAndRejectInvalidNames(t *testing.T) {
|
|
store, accounts, ctx := openCreatorIntegrationStore(t)
|
|
accountID := createIntegrationAccount(t, ctx, accounts, "cover-errors")
|
|
work, _, err := store.UpsertWork(ctx, WorkInput{SourceType: SourceOwned, SourceID: accountID, Platform: PlatformDouyin, WorkKey: "file-errors", CoverURL: "https://p3.douyinpic.com/cover"}, time.Now().UTC())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, item := range []struct {
|
|
contentType string
|
|
data []byte
|
|
}{{"text/html", []byte("wrong")}, {"image/png", nil}, {"image/png", make([]byte, maxWorkCoverBytes+1)}} {
|
|
if err := store.SaveWorkCover(ctx, work.ID, item.contentType, item.data); !errors.Is(err, ErrInvalid) {
|
|
t.Fatalf("invalid image accepted: %v", err)
|
|
}
|
|
}
|
|
if _, err := store.GetWorkCover(ctx, "missing-work"); !errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("unknown work: %v", err)
|
|
}
|
|
blocked := filepath.Join(t.TempDir(), "not-a-directory")
|
|
if err := os.WriteFile(blocked, []byte("blocked"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store.coverDirectory = blocked
|
|
if err := store.SaveWorkCover(ctx, work.ID, "image/png", []byte("cover")); err == nil {
|
|
t.Fatal("filesystem error was swallowed")
|
|
}
|
|
if _, err := store.GetWorkCover(ctx, work.ID); err == nil || errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("filesystem error treated as normal cache miss: %v", err)
|
|
}
|
|
bad, _, err := store.UpsertWork(ctx, WorkInput{SourceType: SourceOwned, SourceID: accountID, Platform: PlatformDouyin, WorkKey: "../outside"}, time.Now().UTC())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.SaveWorkCover(ctx, bad.ID, "image/png", []byte("cover")); !errors.Is(err, ErrInvalid) {
|
|
t.Fatalf("invalid work filename accepted: %v", err)
|
|
}
|
|
if _, err := store.ListWorksMissingCover(ctx, "wrong-source", accountID); !errors.Is(err, ErrInvalid) {
|
|
t.Fatalf("invalid source: %v", err)
|
|
}
|
|
}
|