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.
190 lines
7.8 KiB
Go
190 lines
7.8 KiB
Go
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()
|
||
}
|