chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
416
internal/rpc/messages_pin_rpc_test.go
Normal file
416
internal/rpc/messages_pin_rpc_test.go
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/gotd/td/bin"
|
||||
"github.com/gotd/td/clock"
|
||||
"github.com/gotd/td/tg"
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
||||
appcontacts "telesrv/internal/app/contacts"
|
||||
appdialogs "telesrv/internal/app/dialogs"
|
||||
appmessages "telesrv/internal/app/messages"
|
||||
appusers "telesrv/internal/app/users"
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
func newPinTestRouter(t *testing.T) (*Router, *memory.MessageStore, *memory.UserStore) {
|
||||
t.Helper()
|
||||
userStore := memory.NewUserStore()
|
||||
dialogs := memory.NewDialogStore()
|
||||
messageStore := memory.NewMessageStore(dialogs)
|
||||
contactStore := memory.NewContactStore()
|
||||
r := New(Config{}, Deps{
|
||||
Users: appusers.NewService(userStore),
|
||||
Contacts: appcontacts.NewService(contactStore, userStore),
|
||||
Messages: appmessages.NewService(messageStore, dialogs),
|
||||
Dialogs: appdialogs.NewService(dialogs),
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
return r, messageStore, userStore
|
||||
}
|
||||
|
||||
func findPinnedMessagesUpdate(t *testing.T, updates tg.UpdatesClass) *tg.UpdatePinnedMessages {
|
||||
t.Helper()
|
||||
box, ok := updates.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("updates = %T, want *tg.Updates", updates)
|
||||
}
|
||||
for _, update := range box.Updates {
|
||||
if pinned, ok := update.(*tg.UpdatePinnedMessages); ok {
|
||||
return pinned
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findServiceMessageUpdate(t *testing.T, updates tg.UpdatesClass) *tg.MessageService {
|
||||
t.Helper()
|
||||
box, ok := updates.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("updates = %T, want *tg.Updates", updates)
|
||||
}
|
||||
for _, update := range box.Updates {
|
||||
if newMsg, ok := update.(*tg.UpdateNewMessage); ok {
|
||||
if svc, ok := newMsg.Message.(*tg.MessageService); ok {
|
||||
return svc
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func privatePinnedIDs(t *testing.T, store *memory.MessageStore, ownerID, peerID int64) []int {
|
||||
t.Helper()
|
||||
list, err := store.ListByUser(context.Background(), ownerID, domain.MessageFilter{
|
||||
HasPeer: true,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: peerID},
|
||||
PinnedOnly: true,
|
||||
Limit: 50,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("list pinned: %v", err)
|
||||
}
|
||||
ids := make([]int, 0, len(list.Messages))
|
||||
for _, msg := range list.Messages {
|
||||
ids = append(ids, msg.ID)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// TestMessagesUpdatePinnedMessagePrivateSharedPin 验证私聊共享置顶全链路:
|
||||
// 双侧 box 翻转、updatePinnedMessages 账号 pts 事件、messageActionPinMessage
|
||||
// 服务消息(reply_to 指向被置顶消息)、filterPinned 搜索与 userFull 发现。
|
||||
func TestMessagesUpdatePinnedMessagePrivateSharedPin(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r, messageStore, userStore := newPinTestRouter(t)
|
||||
alice, _ := userStore.Create(ctx, domain.User{AccessHash: 71, Phone: "15550009201", FirstName: "Alice"})
|
||||
bob, _ := userStore.Create(ctx, domain.User{AccessHash: 72, Phone: "15550009202", FirstName: "Bob"})
|
||||
|
||||
sent, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "pin target",
|
||||
RandomID: 92001,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send: %v", err)
|
||||
}
|
||||
aliceMsg := sent.(*tg.Updates).Updates[1].(*tg.UpdateNewMessage).Message.(*tg.Message)
|
||||
|
||||
bobList, err := messageStore.ListByUser(ctx, bob.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: alice.ID}, Limit: 10,
|
||||
})
|
||||
if err != nil || len(bobList.Messages) != 1 {
|
||||
t.Fatalf("bob list = %+v err %v, want delivered message", bobList.Messages, err)
|
||||
}
|
||||
bobBoxID := bobList.Messages[0].ID
|
||||
|
||||
// 共享置顶(未设 pm_oneside = 官方"同时为对方置顶"勾选形态)。
|
||||
pinRes, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: aliceMsg.ID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("pin: %v", err)
|
||||
}
|
||||
pinnedUpdate := findPinnedMessagesUpdate(t, pinRes)
|
||||
if pinnedUpdate == nil || !pinnedUpdate.Pinned || pinnedUpdate.Pts == 0 || pinnedUpdate.PtsCount != 1 {
|
||||
t.Fatalf("pin update = %+v, want pinned with account pts", pinnedUpdate)
|
||||
}
|
||||
if len(pinnedUpdate.Messages) != 1 || pinnedUpdate.Messages[0] != aliceMsg.ID {
|
||||
t.Fatalf("pin update messages = %v, want [%d] (alice 视角 box id)", pinnedUpdate.Messages, aliceMsg.ID)
|
||||
}
|
||||
if peer, ok := pinnedUpdate.Peer.(*tg.PeerUser); !ok || peer.UserID != bob.ID {
|
||||
t.Fatalf("pin update peer = %+v, want bob", pinnedUpdate.Peer)
|
||||
}
|
||||
svc := findServiceMessageUpdate(t, pinRes)
|
||||
if svc == nil {
|
||||
t.Fatalf("pin response lacks messageService, want messageActionPinMessage")
|
||||
}
|
||||
if _, ok := svc.Action.(*tg.MessageActionPinMessage); !ok {
|
||||
t.Fatalf("service action = %T, want messageActionPinMessage", svc.Action)
|
||||
}
|
||||
reply, ok := svc.GetReplyTo()
|
||||
if !ok {
|
||||
t.Fatalf("pin service message lacks reply_to (客户端凭此渲染置顶预览)")
|
||||
}
|
||||
if header, ok := reply.(*tg.MessageReplyHeader); !ok || header.ReplyToMsgID != aliceMsg.ID {
|
||||
t.Fatalf("service reply_to = %+v, want alice box id %d", reply, aliceMsg.ID)
|
||||
}
|
||||
|
||||
// 双侧置顶状态 + 对端服务消息(含对端视角 reply_to 翻译)。
|
||||
if ids := privatePinnedIDs(t, messageStore, alice.ID, bob.ID); len(ids) != 1 || ids[0] != aliceMsg.ID {
|
||||
t.Fatalf("alice pinned = %v, want [%d]", ids, aliceMsg.ID)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 1 || ids[0] != bobBoxID {
|
||||
t.Fatalf("bob pinned = %v, want [%d] (bob 视角 box id)", ids, bobBoxID)
|
||||
}
|
||||
bobAfter, _ := messageStore.ListByUser(ctx, bob.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: alice.ID}, Limit: 10,
|
||||
})
|
||||
foundService := false
|
||||
for _, msg := range bobAfter.Messages {
|
||||
if msg.Media != nil && msg.Media.Kind == domain.MessageMediaKindService &&
|
||||
msg.Media.ServiceAction != nil && msg.Media.ServiceAction.Kind == domain.MessageServiceActionPinMessage {
|
||||
foundService = true
|
||||
if msg.ReplyTo == nil || msg.ReplyTo.MessageID != bobBoxID {
|
||||
t.Fatalf("bob service reply = %+v, want bob box id %d", msg.ReplyTo, bobBoxID)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !foundService {
|
||||
t.Fatalf("bob history lacks pin service message: %+v", bobAfter.Messages)
|
||||
}
|
||||
|
||||
// 幂等:重复 pin 返回空 updates,不再生成服务消息。
|
||||
repeat, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: aliceMsg.ID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("repeat pin: %v", err)
|
||||
}
|
||||
if update := findPinnedMessagesUpdate(t, repeat); update != nil {
|
||||
t.Fatalf("repeat pin update = %+v, want no-op", update)
|
||||
}
|
||||
|
||||
// 搜索发现链路:filterPinned(bob 视角)带总数与 message.pinned 标志。
|
||||
searchReq := &tg.MessagesSearchRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: alice.ID, AccessHash: alice.AccessHash},
|
||||
Filter: &tg.InputMessagesFilterPinned{},
|
||||
Limit: 10,
|
||||
}
|
||||
var in bin.Buffer
|
||||
if err := searchReq.Encode(&in); err != nil {
|
||||
t.Fatalf("encode pinned search: %v", err)
|
||||
}
|
||||
enc, err := r.Dispatch(WithUserID(ctx, bob.ID), [8]byte{}, 0, &in)
|
||||
if err != nil {
|
||||
t.Fatalf("dispatch pinned search: %v", err)
|
||||
}
|
||||
pinnedMessages, _, _ := searchMessagesPayload(t, enc)
|
||||
if len(pinnedMessages) != 1 {
|
||||
t.Fatalf("pinned search len = %d, want 1", len(pinnedMessages))
|
||||
}
|
||||
if msg := pinnedMessages[0].(*tg.Message); msg.ID != bobBoxID || !msg.Pinned {
|
||||
t.Fatalf("pinned search msg = id %d pinned %v, want bob box id %d pinned", msg.ID, msg.Pinned, bobBoxID)
|
||||
}
|
||||
|
||||
// userFull 发现链路:pinned_msg_id + can_pin_message。
|
||||
full, err := r.onUsersGetFullUser(WithUserID(ctx, alice.ID), &tg.InputUser{UserID: bob.ID, AccessHash: bob.AccessHash})
|
||||
if err != nil {
|
||||
t.Fatalf("get full user: %v", err)
|
||||
}
|
||||
if pinnedID, ok := full.FullUser.GetPinnedMsgID(); !ok || pinnedID != aliceMsg.ID {
|
||||
t.Fatalf("userFull pinned_msg_id = %d (%v), want %d", pinnedID, ok, aliceMsg.ID)
|
||||
}
|
||||
if !full.FullUser.CanPinMessage {
|
||||
t.Fatalf("userFull can_pin_message = false, want true")
|
||||
}
|
||||
|
||||
// unpin:双侧清除,事件 pinned=false。
|
||||
unpinReq := &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: aliceMsg.ID,
|
||||
}
|
||||
unpinReq.SetUnpin(true)
|
||||
unpinRes, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), unpinReq)
|
||||
if err != nil {
|
||||
t.Fatalf("unpin: %v", err)
|
||||
}
|
||||
unpinUpdate := findPinnedMessagesUpdate(t, unpinRes)
|
||||
if unpinUpdate == nil || unpinUpdate.Pinned {
|
||||
t.Fatalf("unpin update = %+v, want pinned=false", unpinUpdate)
|
||||
}
|
||||
if findServiceMessageUpdate(t, unpinRes) != nil {
|
||||
t.Fatalf("unpin generated service message, official unpin emits none")
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, alice.ID, bob.ID); len(ids) != 0 {
|
||||
t.Fatalf("alice pinned after unpin = %v, want empty", ids)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 0 {
|
||||
t.Fatalf("bob pinned after unpin = %v, want empty (共享置顶 unpin 双侧传播)", ids)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMessagesUpdatePinnedMessagePrivateOnesideAndUnpinAll 验证 pm_oneside
|
||||
// 单侧置顶(不传播、无服务消息)与 unpinAllMessages 清扫。
|
||||
func TestMessagesUpdatePinnedMessagePrivateOnesideAndUnpinAll(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r, messageStore, userStore := newPinTestRouter(t)
|
||||
alice, _ := userStore.Create(ctx, domain.User{AccessHash: 73, Phone: "15550009203", FirstName: "Alice"})
|
||||
bob, _ := userStore.Create(ctx, domain.User{AccessHash: 74, Phone: "15550009204", FirstName: "Bob"})
|
||||
|
||||
sent, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "oneside target",
|
||||
RandomID: 92011,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send: %v", err)
|
||||
}
|
||||
aliceMsg := sent.(*tg.Updates).Updates[1].(*tg.UpdateNewMessage).Message.(*tg.Message)
|
||||
bobBefore, _ := messageStore.ListByUser(ctx, bob.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: alice.ID}, Limit: 10,
|
||||
})
|
||||
|
||||
// pm_oneside = 官方私聊置顶框默认形态(未勾选"同时为对方置顶")。
|
||||
onesideReq := &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: aliceMsg.ID,
|
||||
}
|
||||
onesideReq.SetPmOneside(true)
|
||||
onesideRes, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), onesideReq)
|
||||
if err != nil {
|
||||
t.Fatalf("oneside pin: %v", err)
|
||||
}
|
||||
if update := findPinnedMessagesUpdate(t, onesideRes); update == nil || !update.Pinned {
|
||||
t.Fatalf("oneside pin update = %+v, want pinned", update)
|
||||
}
|
||||
if findServiceMessageUpdate(t, onesideRes) != nil {
|
||||
t.Fatalf("oneside pin generated service message, want none")
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, alice.ID, bob.ID); len(ids) != 1 {
|
||||
t.Fatalf("alice oneside pinned = %v, want 1", ids)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 0 {
|
||||
t.Fatalf("bob pinned after oneside = %v, want empty (单侧不传播)", ids)
|
||||
}
|
||||
bobAfter, _ := messageStore.ListByUser(ctx, bob.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: alice.ID}, Limit: 10,
|
||||
})
|
||||
if len(bobAfter.Messages) != len(bobBefore.Messages) {
|
||||
t.Fatalf("bob history grew %d -> %d after oneside pin, want unchanged", len(bobBefore.Messages), len(bobAfter.Messages))
|
||||
}
|
||||
|
||||
// 单侧→共享升级:同一消息再发不带 pm_oneside 的 pin,必须向对端
|
||||
// 传播并生成服务消息(own 侧已置顶不构成整体 no-op)。
|
||||
upgradeRes, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: aliceMsg.ID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("upgrade pin: %v", err)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 1 {
|
||||
t.Fatalf("bob pinned after upgrade = %v, want shared pin propagated", ids)
|
||||
}
|
||||
if findServiceMessageUpdate(t, upgradeRes) == nil {
|
||||
t.Fatalf("upgrade pin lacks service message, want messageActionPinMessage")
|
||||
}
|
||||
|
||||
// 再追加一条共享置顶,然后 unpinAll 一次清掉两条。
|
||||
sent2, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "shared target",
|
||||
RandomID: 92012,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send shared: %v", err)
|
||||
}
|
||||
sharedMsg := sent2.(*tg.Updates).Updates[1].(*tg.UpdateNewMessage).Message.(*tg.Message)
|
||||
if _, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: sharedMsg.ID,
|
||||
}); err != nil {
|
||||
t.Fatalf("shared pin: %v", err)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, alice.ID, bob.ID); len(ids) != 2 {
|
||||
t.Fatalf("alice pinned = %v, want 2 before unpinAll", ids)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 2 {
|
||||
t.Fatalf("bob pinned = %v, want 2 shared before unpinAll", ids)
|
||||
}
|
||||
|
||||
affected, err := r.onMessagesUnpinAllMessages(WithUserID(ctx, alice.ID), &tg.MessagesUnpinAllMessagesRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unpinAll: %v", err)
|
||||
}
|
||||
if affected.Pts == 0 || affected.Offset != 0 {
|
||||
t.Fatalf("unpinAll affected = %+v, want account pts and offset 0", affected)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, alice.ID, bob.ID); len(ids) != 0 {
|
||||
t.Fatalf("alice pinned after unpinAll = %v, want empty", ids)
|
||||
}
|
||||
if ids := privatePinnedIDs(t, messageStore, bob.ID, alice.ID); len(ids) != 0 {
|
||||
t.Fatalf("bob pinned after unpinAll = %v, want empty (共享置顶同步清除)", ids)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMessagesUpdatePinnedMessageSavedMessagesAndServiceGuard 验证 Saved
|
||||
// Messages 置顶(无服务消息)与服务消息禁止置顶。
|
||||
func TestMessagesUpdatePinnedMessageSavedMessagesAndServiceGuard(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r, messageStore, userStore := newPinTestRouter(t)
|
||||
alice, _ := userStore.Create(ctx, domain.User{AccessHash: 75, Phone: "15550009205", FirstName: "Alice"})
|
||||
|
||||
sent, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerSelf{},
|
||||
Message: "saved note",
|
||||
RandomID: 92021,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send saved: %v", err)
|
||||
}
|
||||
savedMsg := sent.(*tg.Updates).Updates[1].(*tg.UpdateNewMessage).Message.(*tg.Message)
|
||||
|
||||
pinRes, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerSelf{},
|
||||
ID: savedMsg.ID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("pin saved: %v", err)
|
||||
}
|
||||
if update := findPinnedMessagesUpdate(t, pinRes); update == nil || !update.Pinned {
|
||||
t.Fatalf("saved pin update = %+v, want pinned", update)
|
||||
}
|
||||
if findServiceMessageUpdate(t, pinRes) != nil {
|
||||
t.Fatalf("saved messages pin generated service message, want none (无人可通知)")
|
||||
}
|
||||
list, _ := messageStore.ListByUser(ctx, alice.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: alice.ID}, Limit: 10,
|
||||
})
|
||||
if len(list.Messages) != 1 || !list.Messages[0].Pinned {
|
||||
t.Fatalf("saved history = %+v, want single pinned message without service message", list.Messages)
|
||||
}
|
||||
|
||||
// 服务消息不可置顶:先用共享置顶在双人聊天里生成一条服务消息再试。
|
||||
bob, _ := userStore.Create(ctx, domain.User{AccessHash: 76, Phone: "15550009206", FirstName: "Bob"})
|
||||
sent2, err := r.onMessagesSendMessage(WithUserID(ctx, alice.ID), &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Message: "to pin",
|
||||
RandomID: 92022,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send: %v", err)
|
||||
}
|
||||
target := sent2.(*tg.Updates).Updates[1].(*tg.UpdateNewMessage).Message.(*tg.Message)
|
||||
if _, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: target.ID,
|
||||
}); err != nil {
|
||||
t.Fatalf("pin for service msg: %v", err)
|
||||
}
|
||||
aliceList, _ := messageStore.ListByUser(ctx, alice.ID, domain.MessageFilter{
|
||||
HasPeer: true, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: bob.ID}, Limit: 10,
|
||||
})
|
||||
serviceID := 0
|
||||
for _, msg := range aliceList.Messages {
|
||||
if msg.Media != nil && msg.Media.Kind == domain.MessageMediaKindService {
|
||||
serviceID = msg.ID
|
||||
}
|
||||
}
|
||||
if serviceID == 0 {
|
||||
t.Fatalf("no service message found in alice history: %+v", aliceList.Messages)
|
||||
}
|
||||
if _, err := r.onMessagesUpdatePinnedMessage(WithUserID(ctx, alice.ID), &tg.MessagesUpdatePinnedMessageRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
ID: serviceID,
|
||||
}); err == nil {
|
||||
t.Fatalf("pin service message succeeded, want MESSAGE_ID_INVALID")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue