douyin-release-gate / verify (push) Failing after 18m54s
Add Douyin notification polling, event details, and manual multi-account private messaging. Refine environment memory settings, account operations, login collection recovery, and message UI; update tests and documentation.
142 lines
5.4 KiB
Go
142 lines
5.4 KiB
Go
package creator
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestEventDetailsValidateWithoutDroppingFailures(t *testing.T) {
|
|
d := ListenerDelivery{DeliveryID: "1", Kind: "notice", Notice: &ListenerNotice{EventKey: "2", EventType: "like", WorkAuthorUID: "123", WorkCoverError: "download failed"}}
|
|
if err := d.Validate(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d.Notice.WorkAuthorUID = "../123"
|
|
if !errors.Is(d.Validate(), ErrInvalid) {
|
|
t.Fatal("bad author identity accepted")
|
|
}
|
|
d.Notice.WorkAuthorUID = "123"
|
|
d.Notice.InteractorName = strings.Repeat("x", 32769)
|
|
if !errors.Is(d.Validate(), ErrInvalid) {
|
|
t.Fatal("oversized profile accepted")
|
|
}
|
|
}
|
|
|
|
func TestEventCoverUsesPlatformIdentityWithoutPlaceholderWork(t *testing.T) {
|
|
s := &Store{coverDirectory: t.TempDir()}
|
|
if _, err := s.GetPlatformWorkCover("123", "456"); !errors.Is(err, ErrNotFound) {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SavePlatformWorkCover("123", "456", "image/webp", []byte("image")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
path, err := s.GetPlatformWorkCover("123", "456")
|
|
if err != nil || path != filepath.Join(s.coverDirectory, "123", "456.webp") {
|
|
t.Fatalf("%s %v", path, err)
|
|
}
|
|
if err := s.SavePlatformWorkCover("../bad", "456", "image/png", []byte("image")); !errors.Is(err, ErrInvalid) {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SavePlatformWorkCover("123", "456", "text/html", []byte("bad")); !errors.Is(err, ErrInvalid) {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(path, []byte{}, 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.GetPlatformWorkCover("123", "456"); !errors.Is(err, ErrInvalid) {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestEventDetailsBackfillPreservesMessageAndTimes(t *testing.T) {
|
|
store, accounts, ctx := openCreatorIntegrationStore(t)
|
|
store.coverDirectory = t.TempDir()
|
|
id := createIntegrationAccount(t, ctx, accounts, fmt.Sprint(time.Now().UnixNano()))
|
|
profile, err := store.GetAccountProfile(ctx, id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = store.RecordVerifiedLoginResult(ctx, id, profile.PlatformAccountKey); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
state, err := store.SetListenerEnabled(ctx, id, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
now := time.Now().UTC().Truncate(time.Microsecond)
|
|
d := ListenerDelivery{DeliveryID: "original", Kind: "notice", Baseline: true, Notice: &ListenerNotice{EventKey: "101", EventType: "comment", InteractorUID: "456", WorkID: "987", PlatformEventAt: &now, MessageText: "原评论"}}
|
|
if err = store.RecordListenerDeliveries(ctx, id, state.Generation, []ListenerDelivery{d}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d.DeliveryID = "details"
|
|
d.Notice.InteractorName = "用户昵称"
|
|
d.Notice.InteractorSecUID = "MS4wLjABAAAAprofile"
|
|
d.Notice.WorkAuthorUID = "123"
|
|
d.Notice.WorkCoverURL = "https://p3.douyinpic.com/cover.jpg"
|
|
d.Notice.WorkURL = "https://www.douyin.com/video/987"
|
|
d.Notice.MessageText = "不应覆盖的重读内容"
|
|
later := now.Add(time.Hour)
|
|
d.Notice.PlatformEventAt = &later
|
|
if err = store.SavePlatformWorkCover("123", "987", "image/jpeg", []byte("image")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = store.RecordListenerDeliveries(ctx, id, state.Generation, []ListenerDelivery{d}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
page, err := store.ListAggregatedEventsPage(ctx, EventAggregationFilter{AccountID: id}, 1, 25)
|
|
if err != nil || page.Total != 1 {
|
|
t.Fatalf("%+v %v", page, err)
|
|
}
|
|
event := page.Data[0]
|
|
if event.InteractorName != "用户昵称" || event.InteractorSecUID != "MS4wLjABAAAAprofile" || !event.HasWorkCover {
|
|
t.Fatalf("details not filled: %+v", event)
|
|
}
|
|
if event.MessageText != "原评论" || !event.PlatformEventAt.Equal(now) || !event.Baseline {
|
|
t.Fatalf("original changed: %+v", event)
|
|
}
|
|
if _, err = store.GetEventWorkCover(ctx, event.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d.Notice.InteractorName = ""
|
|
d.Notice.InteractorSecUID = ""
|
|
d.Notice.WorkCoverURL = ""
|
|
d.Notice.WorkURL = ""
|
|
d.Notice.WorkAuthorUID = ""
|
|
if err = store.RecordListenerDeliveries(ctx, id, state.Generation, []ListenerDelivery{d}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
page, err = store.ListAggregatedEventsPage(ctx, EventAggregationFilter{AccountID: id}, 1, 25)
|
|
if err != nil || page.Data[0].InteractorName != "用户昵称" || page.Data[0].WorkURL == "" {
|
|
t.Fatalf("partial response erased details: %+v %v", page, err)
|
|
}
|
|
d.Notice.InteractorUID = "789"
|
|
d.Notice.InteractorName = "不同用户"
|
|
d.Notice.InteractorSecUID = "other"
|
|
d.Notice.WorkID = "111"
|
|
d.Notice.WorkAuthorUID = "222"
|
|
d.Notice.WorkURL = "https://www.douyin.com/video/111"
|
|
if err = store.RecordListenerDeliveries(ctx, id, state.Generation, []ListenerDelivery{d}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
page, err = store.ListAggregatedEventsPage(ctx, EventAggregationFilter{AccountID: id}, 1, 25)
|
|
if err != nil || page.Data[0].InteractorName != "用户昵称" || page.Data[0].InteractorSecUID != "MS4wLjABAAAAprofile" || page.Data[0].WorkAuthorUID != "123" || page.Data[0].WorkURL != "https://www.douyin.com/video/987" {
|
|
t.Fatalf("merged notification misattributed details: %+v %v", page, err)
|
|
}
|
|
if _, err = store.GetEventWorkCover(ctx, "bad"); !errors.Is(err, ErrInvalid) {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = store.GetEventWorkCover(ctx, "999999999"); !errors.Is(err, ErrNotFound) {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = store.SetListenerEnabled(ctx, id, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = store.GetEventWorkCover(ctx, event.ID); !errors.Is(err, ErrNotFound) {
|
|
t.Fatalf("disabled account cover remained exposed: %v", err)
|
|
}
|
|
}
|