Files
creator-hub/internal/creator/private_messages_test.go
T
rogee e50bed9ad8
douyin-release-gate / verify (push) Failing after 18m54s
feat: add account events and private message management
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.
2026-10-07 10:23:05 +08:00

190 lines
7.8 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 (
"context"
"errors"
"fmt"
"strings"
"testing"
"time"
)
func TestPrivateMessageInputValidation(t *testing.T) {
valid := PrivateMessageSendInput{RequestID: "one", AccountID: "account", PeerUID: "123", Text: "你好"}
if err := valid.Validate(); err != nil {
t.Fatal(err)
}
for _, edit := range []func(*PrivateMessageSendInput){
func(i *PrivateMessageSendInput) { i.RequestID = "" }, func(i *PrivateMessageSendInput) { i.AccountID = "" },
func(i *PrivateMessageSendInput) { i.PeerUID = "abc" }, func(i *PrivateMessageSendInput) { i.PeerUID = "0" },
func(i *PrivateMessageSendInput) { i.Text = " " }, func(i *PrivateMessageSendInput) { i.Text = strings.Repeat("你", 1001) },
} {
i := valid
edit(&i)
if !errors.Is(i.Validate(), ErrInvalid) {
t.Fatalf("accepted %+v", i)
}
}
valid.Text = strings.Repeat("你", 1000)
if err := valid.Validate(); err != nil {
t.Fatal(err)
}
}
func TestDecodePrivateInbox(t *testing.T) {
raw := []byte(`{"status":"succeeded","account_uid":"123","messages":[{"peer_uid":"456","peer_name":"好友","server_id":"1001","sender_uid":"456","message_type":"7","content":"{\"aweType\":700,\"type\":0,\"text\":\"你好\"}","created_at":"1700000000123"},{"peer_uid":"456","server_id":"1002","sender_uid":"123","message_type":"7","content":"{\"aweType\":701,\"type\":1,\"resource_url\":\"https://example.invalid\"}","created_at":null}]}`)
items, err := DecodePrivateInbox(raw, "123")
if err != nil {
t.Fatal(err)
}
if len(items) != 2 || items[0].Direction != "inbound" || items[0].Text != "你好" || items[0].MessageAt == nil || items[0].MessageAt.UnixMilli() != 1700000000123 || items[1].Direction != "outbound" || items[1].MessageType != "image" || items[1].MessageAt != nil {
t.Fatalf("items=%+v", items)
}
for _, raw := range []string{`{}`, `{"status":"failed","code":"IM_SDK_NOT_READY"}`, `{"status":"succeeded","account_uid":"999","messages":[]}`, `{"status":"succeeded","account_uid":"123"}`, `{"status":"succeeded","account_uid":"123","messages":[{"peer_uid":"456","server_id":"0","sender_uid":"456","message_type":"7","content":"{}"}]}`, `{"status":"succeeded","account_uid":"123","messages":[{"peer_uid":"456","server_id":"1","sender_uid":"777","message_type":"7","content":"{}"}]}`} {
if _, err := DecodePrivateInbox([]byte(raw), "123"); err == nil {
t.Fatalf("accepted %s", raw)
}
}
}
func TestPrivateListenerStateDoesNotDependOnNoticeProgress(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
id := createIntegrationAccount(t, ctx, accounts, "independent-listener")
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)
}
if _, err := store.db.ExecContext(ctx, `ALTER TABLE creator_account_listener DROP COLUMN IF EXISTS notice_checkpoints`); err != nil {
t.Fatal(err)
}
states, err := store.ListPrivateListeners(ctx)
if err != nil || len(states) != 1 || states[0].AccountID != id || !states[0].Enabled || states[0].Generation != state.Generation {
t.Fatalf("states=%+v %v", states, err)
}
}
func TestPreviouslyMisclassifiedNetworkFailureIsUnconfirmed(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
id := createIntegrationAccount(t, ctx, accounts, "network-reclassification")
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)
}
if _, err := store.SetListenerEnabled(ctx, id, true); err != nil {
t.Fatal(err)
}
reservation, err := store.BeginPrivateMessage(ctx, PrivateMessageSendInput{RequestID: "old-network", AccountID: id, PeerUID: "456", Text: "你好"})
if err != nil {
t.Fatal(err)
}
if _, err := store.FinishPrivateMessage(ctx, reservation.Message.ID, "failed", "", "发送失败:MESSAGE_REJECTED;status_code=1008", nil); err != nil {
t.Fatal(err)
}
if err := store.RecoverInterruptedPrivateMessages(ctx); err != nil {
t.Fatal(err)
}
page, err := store.ListPrivateMessages(ctx, id, "456", 1, 25)
if err != nil || page.Data[0].State != "unknown" {
t.Fatalf("network=%+v %v", page, err)
}
}
func TestPrivateMessagesLifecycle(t *testing.T) {
store, accounts, ctx := openCreatorIntegrationStore(t)
uid := fmt.Sprint(time.Now().UnixNano())
id := createIntegrationAccount(t, ctx, accounts, uid)
input := PrivateMessageSendInput{RequestID: "request-1", AccountID: id, PeerUID: "456", Text: "你好"}
if _, err := store.BeginPrivateMessage(ctx, input); !errors.Is(err, ErrConflict) {
t.Fatalf("unlistened send=%v", err)
}
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)
}
listener, err := store.SetListenerEnabled(ctx, id, true)
if err != nil {
t.Fatal(err)
}
first, err := store.BeginPrivateMessage(ctx, input)
if err != nil || !first.New || first.Message.State != "sending" {
t.Fatalf("begin=%+v %v", first, err)
}
duplicate, err := store.BeginPrivateMessage(ctx, input)
if err != nil || duplicate.New || duplicate.Message.ID != first.Message.ID {
t.Fatalf("duplicate=%+v %v", duplicate, err)
}
changed := input
changed.Text = "不同内容"
if _, err := store.BeginPrivateMessage(ctx, changed); !errors.Is(err, ErrConflict) {
t.Fatalf("changed request=%v", err)
}
self := input
self.RequestID = "self"
self.PeerUID = profile.PlatformAccountKey
if _, err := store.BeginPrivateMessage(ctx, self); !errors.Is(err, ErrInvalid) {
t.Fatalf("self=%v", err)
}
at := time.Now().UTC()
batch := []PrivateInboxMessage{{PeerUID: "456", PeerName: "好友", ServerID: "100", Direction: "outbound", MessageType: "text", Text: "你好", MessageAt: &at}, {PeerUID: "456", PeerName: "好友", ServerID: "101", Direction: "inbound", MessageType: "text", Text: "你好呀", MessageAt: &at}}
if err := store.SavePrivateInbox(ctx, id, listener.Generation, batch); err != nil {
t.Fatal(err)
}
if err := store.SavePrivateInbox(ctx, id, listener.Generation, batch); err != nil {
t.Fatal(err)
}
finished, err := store.FinishPrivateMessage(ctx, first.Message.ID, "succeeded", "100", "", &at)
if err != nil || finished.State != "succeeded" {
t.Fatalf("finish=%+v %v", finished, err)
}
page, err := store.ListPrivateMessages(ctx, id, "456", 1, 25)
if err != nil || page.Total != 2 || len(page.Data) != 2 {
t.Fatalf("messages=%+v %v", page, err)
}
conv, err := store.ListPrivateConversations(ctx, id, 1, 25)
if err != nil || conv.Total != 1 || conv.Data[0].MessageCount != 2 {
t.Fatalf("conversations=%+v %v", conv, err)
}
if err := store.UpdatePrivateSyncStatus(ctx, id, listener.Generation, "network failed"); err != nil {
t.Fatal(err)
}
statuses, err := store.ListPrivateSyncStatus(ctx)
if err != nil || len(statuses) != 1 || statuses[0].Error != "network failed" {
t.Fatalf("status=%+v %v", statuses, err)
}
if _, err := store.SetListenerEnabled(ctx, id, false); err != nil {
t.Fatal(err)
}
if err := store.SavePrivateInbox(ctx, id, listener.Generation, batch); !errors.Is(err, ErrConflict) {
t.Fatalf("late sync=%v", err)
}
page, err = store.ListPrivateMessages(ctx, id, "456", 1, 25)
if err != nil || page.Total != 0 || page.Data == nil {
t.Fatalf("disabled=%+v %v", page, err)
}
conv, err = store.ListPrivateConversations(ctx, "", 1, 25)
if err != nil || conv.Total != 0 || conv.Data == nil {
t.Fatalf("disabled conversations=%+v %v", conv, err)
}
if _, err := store.SetListenerEnabled(ctx, id, true); err != nil {
t.Fatal(err)
}
page, err = store.ListPrivateMessages(ctx, id, "456", 1, 25)
if err != nil || page.Total != 2 {
t.Fatalf("reenabled=%+v %v", page, err)
}
_ = context.Background()
}