fix(rpc): sync verification icon envelope coverage
Follow up gramsrv#27 with the remaining peer-bearing messages.Messages boundaries and route-level wire regression coverage from the telesrv canonical implementation. Origin-PR: gramsrv#27 Origin-Head:f0bd6c9699Origin-Merge:7713847b2aCanonical: f1ba406015a2d5e37802b963757a5cac8ee3eb0e Co-authored-by: epilepticseizureee <business.egor.sg@gmail.com>
This commit is contained in:
parent
7713847b2a
commit
3fa0c6f1e4
12 changed files with 156 additions and 16 deletions
|
|
@ -65,6 +65,53 @@ func assertFlagBitDelta(t *testing.T, label string, before, after bin.Fields, wa
|
|||
}
|
||||
}
|
||||
|
||||
func assertMessagesEnvelopeBotVerificationIcon(t *testing.T, out tg.MessagesMessagesClass, peer domain.Peer, want int64) {
|
||||
t.Helper()
|
||||
var users []tg.UserClass
|
||||
var chats []tg.ChatClass
|
||||
switch value := out.(type) {
|
||||
case *tg.MessagesMessages:
|
||||
users, chats = value.Users, value.Chats
|
||||
case *tg.MessagesMessagesSlice:
|
||||
users, chats = value.Users, value.Chats
|
||||
case *tg.MessagesChannelMessages:
|
||||
users, chats = value.Users, value.Chats
|
||||
default:
|
||||
t.Fatalf("messages envelope = %T, want peer-bearing messages.Messages", out)
|
||||
}
|
||||
switch peer.Type {
|
||||
case domain.PeerTypeUser:
|
||||
for _, item := range users {
|
||||
user, ok := item.(*tg.User)
|
||||
if !ok || user.ID != peer.ID {
|
||||
continue
|
||||
}
|
||||
wire := &tg.User{}
|
||||
tlRoundTrip(t, user, wire)
|
||||
if icon, ok := wire.GetBotVerificationIcon(); !ok || icon != want {
|
||||
t.Fatalf("user %d bot_verification_icon = %d, ok=%v, want %d", peer.ID, icon, ok, want)
|
||||
}
|
||||
return
|
||||
}
|
||||
case domain.PeerTypeChannel:
|
||||
for _, item := range chats {
|
||||
channel, ok := item.(*tg.Channel)
|
||||
if !ok || channel.ID != peer.ID {
|
||||
continue
|
||||
}
|
||||
wire := &tg.Channel{}
|
||||
tlRoundTrip(t, channel, wire)
|
||||
if icon, ok := wire.GetBotVerificationIcon(); !ok || icon != want {
|
||||
t.Fatalf("channel %d bot_verification_icon = %d, ok=%v, want %d", peer.ID, icon, ok, want)
|
||||
}
|
||||
return
|
||||
}
|
||||
default:
|
||||
t.Fatalf("unsupported verification peer %+v", peer)
|
||||
}
|
||||
t.Fatalf("messages envelope %T does not carry peer %+v", out, peer)
|
||||
}
|
||||
|
||||
// TestBotVerificationConstructorIDs pins the two constructor ids the feature
|
||||
// serialises. A drift here silently reshapes every payload below.
|
||||
func TestBotVerificationConstructorIDs(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,9 @@ func (r *Router) onChannelsSearchPosts(ctx context.Context, req *tg.ChannelsSear
|
|||
return nil, channelInvalidErr(err)
|
||||
}
|
||||
history = r.enrichChannelHistory(ctx, userID, history)
|
||||
return tgChannelSearchPostsMessages(userID, history), nil
|
||||
result := tgChannelSearchPostsMessages(userID, history)
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func validateChannelSearchPostsRequest(req *tg.ChannelsSearchPostsRequest) error {
|
||||
|
|
|
|||
|
|
@ -835,9 +835,11 @@ func TestChannelsSearchPostsReturnsPublicPostsWithSeekPaging(t *testing.T) {
|
|||
viewer, _ := userStore.Create(ctx, domain.User{AccessHash: 91002, Phone: "15550091002", FirstName: "Viewer"})
|
||||
channelStore := memory.NewChannelStore()
|
||||
channelService := appchannels.NewService(channelStore)
|
||||
verify := newFakeBotVerifications()
|
||||
r := New(Config{}, Deps{
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: channelService,
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: channelService,
|
||||
BotVerifications: verify,
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
public, err := channelService.CreateChannel(ctx, owner.ID, domain.CreateChannelRequest{
|
||||
Title: "Public Search",
|
||||
|
|
@ -847,6 +849,14 @@ func TestChannelsSearchPostsReturnsPublicPostsWithSeekPaging(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("create public channel: %v", err)
|
||||
}
|
||||
const searchPostsIcon = int64(8800021)
|
||||
searchPostsPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: public.Channel.ID}
|
||||
verify.marks[searchPostsPeer] = domain.CustomVerification{
|
||||
VerifierBotID: 777000123,
|
||||
Peer: searchPostsPeer,
|
||||
IconDocumentID: searchPostsIcon,
|
||||
Description: "Verified search result",
|
||||
}
|
||||
if _, err := channelService.UpdateUsername(ctx, owner.ID, domain.UpdateChannelUsernameRequest{
|
||||
UserID: owner.ID,
|
||||
ChannelID: public.Channel.ID,
|
||||
|
|
@ -920,6 +930,7 @@ func TestChannelsSearchPostsReturnsPublicPostsWithSeekPaging(t *testing.T) {
|
|||
if peer, ok := first.PeerID.(*tg.PeerChannel); !ok || peer.ChannelID != public.Channel.ID {
|
||||
t.Fatalf("first result peer = %#v, want public channel %d", first.PeerID, public.Channel.ID)
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, got, searchPostsPeer, searchPostsIcon)
|
||||
|
||||
page2 := &tg.ChannelsSearchPostsRequest{
|
||||
OffsetRate: slice.NextRate,
|
||||
|
|
|
|||
|
|
@ -961,6 +961,16 @@ func TestTDesktopPassiveChannelStubs(t *testing.T) {
|
|||
}); err == nil || !strings.Contains(err.Error(), "MESSAGE_ID_INVALID") {
|
||||
t.Fatalf("messages.deletePollAnswer err = %v, want MESSAGE_ID_INVALID without poll store", err)
|
||||
}
|
||||
verify := newFakeBotVerifications()
|
||||
r.deps.BotVerifications = verify
|
||||
const unreadPollIcon = int64(8800024)
|
||||
unreadPollPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: channel.ID}
|
||||
verify.marks[unreadPollPeer] = domain.CustomVerification{
|
||||
VerifierBotID: 777000123,
|
||||
Peer: unreadPollPeer,
|
||||
IconDocumentID: unreadPollIcon,
|
||||
Description: "Verified poll peer",
|
||||
}
|
||||
unreadPollVotes, err := r.onMessagesGetUnreadPollVotes(ownerCtx, &tg.MessagesGetUnreadPollVotesRequest{
|
||||
Peer: inputPeerChannel(channel),
|
||||
Limit: 10,
|
||||
|
|
@ -968,6 +978,7 @@ func TestTDesktopPassiveChannelStubs(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("messages.getUnreadPollVotes: %v", err)
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, unreadPollVotes, unreadPollPeer, unreadPollIcon)
|
||||
if len(unreadPollVotes.(*tg.MessagesMessages).Messages) != 0 {
|
||||
t.Fatalf("messages.getUnreadPollVotes = %+v, want empty messages", unreadPollVotes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,35 @@ import (
|
|||
"go.uber.org/zap/zaptest"
|
||||
|
||||
accountapp "telesrv/internal/app/account"
|
||||
appusers "telesrv/internal/app/users"
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
func TestQuickReplyRPCSaveListAndDeleteMessage(t *testing.T) {
|
||||
const userID int64 = 1000000001
|
||||
const userID int64 = domain.UserIDSequenceBase
|
||||
ctx := WithSessionID(WithAuthKeyID(WithUserID(context.Background(), userID), [8]byte{1}), 77)
|
||||
r, updates := newChatAutomationTestRouter(t)
|
||||
verify := newFakeBotVerifications()
|
||||
r.deps.BotVerifications = verify
|
||||
userStore := memory.NewUserStore()
|
||||
self, err := userStore.Create(context.Background(), domain.User{
|
||||
AccessHash: 7000001,
|
||||
Phone: "15550007001",
|
||||
FirstName: "Quick",
|
||||
})
|
||||
if err != nil || self.ID != userID {
|
||||
t.Fatalf("create quick-reply user = %+v err %v, want id %d", self, err, userID)
|
||||
}
|
||||
r.deps.Users = appusers.NewService(userStore)
|
||||
const quickReplyIcon = int64(8800023)
|
||||
quickReplyPeer := domain.Peer{Type: domain.PeerTypeUser, ID: userID}
|
||||
verify.marks[quickReplyPeer] = domain.CustomVerification{
|
||||
VerifierBotID: 777000123,
|
||||
Peer: quickReplyPeer,
|
||||
IconDocumentID: quickReplyIcon,
|
||||
Description: "Verified quick-reply peer",
|
||||
}
|
||||
|
||||
got, err := r.onMessagesSendMessage(ctx, &tg.MessagesSendMessageRequest{
|
||||
Peer: &tg.InputPeerSelf{},
|
||||
|
|
@ -68,6 +89,17 @@ func TestQuickReplyRPCSaveListAndDeleteMessage(t *testing.T) {
|
|||
t.Fatalf("quick replies = %#v", list)
|
||||
}
|
||||
|
||||
quickReplyMessages, err := r.onMessagesGetQuickReplyMessages(ctx, &tg.MessagesGetQuickReplyMessagesRequest{
|
||||
ShortcutID: shortcutID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("onMessagesGetQuickReplyMessages: %v", err)
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, quickReplyMessages, quickReplyPeer, quickReplyIcon)
|
||||
if verify.batchCalls != 0 || verify.peerCalls != 1 {
|
||||
t.Fatalf("quick-reply verification reads = batch %d peer %d, want 0/1 for one peer", verify.batchCalls, verify.peerCalls)
|
||||
}
|
||||
|
||||
deleted, err := r.onMessagesDeleteQuickReplyMessages(ctx, &tg.MessagesDeleteQuickReplyMessagesRequest{
|
||||
ShortcutID: shortcutID,
|
||||
ID: []int{messageID},
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@ func (r *Router) onMessagesGetSavedHistory(ctx context.Context, req *tg.Messages
|
|||
if req.Hash != 0 {
|
||||
return &tg.MessagesMessagesNotModified{Count: 0}, nil
|
||||
}
|
||||
return &tg.MessagesMessages{
|
||||
result := &tg.MessagesMessages{
|
||||
Messages: []tg.MessageClass{},
|
||||
Chats: r.savedHistoryChats(ctx, userID, hasParent, parentPeer, req.Peer),
|
||||
Users: []tg.UserClass{},
|
||||
}, nil
|
||||
}
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
// parent_peer = monoforum:返回该订阅者(req.Peer)在频道私信内的历史。
|
||||
return r.monoforumSavedHistory(ctx, userID, mono, savedPeer, req.Limit, req.OffsetID)
|
||||
|
|
@ -83,6 +85,7 @@ func (r *Router) onMessagesGetSavedHistory(ctx context.Context, req *tg.Messages
|
|||
m.Chats = mergeTGChats(m.Chats, chats)
|
||||
}
|
||||
}
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -298,11 +298,13 @@ func (r *Router) onMessagesGetReplies(ctx context.Context, req *tg.MessagesGetRe
|
|||
}
|
||||
return r.tgChannelHistoryMessages(ctx, userID, r.enrichChannelHistory(ctx, userID, replies)), nil
|
||||
}
|
||||
return &tg.MessagesMessages{
|
||||
result := &tg.MessagesMessages{
|
||||
Messages: []tg.MessageClass{},
|
||||
Chats: r.chatsForInputPeer(ctx, userID, req.Peer),
|
||||
Users: []tg.UserClass{},
|
||||
}, nil
|
||||
}
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Router) onMessagesGetDiscussionMessage(ctx context.Context, req *tg.MessagesGetDiscussionMessageRequest) (*tg.MessagesDiscussionMessage, error) {
|
||||
|
|
@ -596,7 +598,9 @@ func (r *Router) onMessagesSearchGlobal(ctx context.Context, req *tg.MessagesSea
|
|||
return nil, err
|
||||
}
|
||||
if emptyCommunitySearch {
|
||||
return appendCommunitySearchChat(&tg.MessagesMessages{}, communityView), nil
|
||||
result := appendCommunitySearchChat(&tg.MessagesMessages{}, communityView)
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
var private domain.MessageList
|
||||
if !req.BroadcastsOnly && !req.GroupsOnly && r.deps.Messages != nil {
|
||||
|
|
@ -623,7 +627,9 @@ func (r *Router) onMessagesSearchGlobal(ctx context.Context, req *tg.MessagesSea
|
|||
}
|
||||
}
|
||||
if req.UsersOnly || r.deps.Channels == nil {
|
||||
return appendCommunitySearchChat(tgMessagesMessages(userID, r.enrichMessageList(ctx, userID, limitMessageList(private, limit))), communityView), nil
|
||||
result := appendCommunitySearchChat(tgMessagesMessages(userID, r.enrichMessageList(ctx, userID, limitMessageList(private, limit))), communityView)
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
channelHistory, err := r.deps.Channels.SearchJoinedMessages(ctx, userID, domain.ChannelGlobalSearchRequest{
|
||||
Query: query,
|
||||
|
|
|
|||
|
|
@ -119,12 +119,14 @@ func (r *Router) monoforumSavedHistory(ctx context.Context, userID int64, mono d
|
|||
messages = append(messages, item)
|
||||
}
|
||||
}
|
||||
return &tg.MessagesMessagesSlice{
|
||||
result := &tg.MessagesMessagesSlice{
|
||||
Count: hist.Count,
|
||||
Messages: messages,
|
||||
Chats: r.monoforumChats(ctx, userID, mono),
|
||||
Users: r.monoforumSubscriberUsers(ctx, userID, nil, hist.Messages),
|
||||
}, nil
|
||||
}
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// monoforumChats 投影客户端 materialize monoforum 私信所需的频道:monoforum 自身直接投影,
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@ func TestMonoforumSavedDialogsAndHistory(t *testing.T) {
|
|||
|
||||
channelStore := memory.NewChannelStore()
|
||||
channelSvc := appchannels.NewService(channelStore)
|
||||
verify := newFakeBotVerifications()
|
||||
r := New(Config{}, Deps{
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: channelSvc,
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: channelSvc,
|
||||
BotVerifications: verify,
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
|
||||
created, err := channelSvc.CreateChannel(ctx, owner.ID, domain.CreateChannelRequest{Title: "DM Broadcast", Broadcast: true, Date: 1000})
|
||||
|
|
@ -65,6 +67,14 @@ func TestMonoforumSavedDialogsAndHistory(t *testing.T) {
|
|||
}
|
||||
monoInput := &tg.InputPeerChannel{ChannelID: monoID, AccessHash: mono.AccessHash}
|
||||
parentInput := &tg.InputPeerChannel{ChannelID: created.Channel.ID, AccessHash: created.Channel.AccessHash}
|
||||
const monoforumIcon = int64(8800025)
|
||||
monoforumPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: monoID}
|
||||
verify.marks[monoforumPeer] = domain.CustomVerification{
|
||||
VerifierBotID: 777000123,
|
||||
Peer: monoforumPeer,
|
||||
IconDocumentID: monoforumIcon,
|
||||
Description: "Verified monoforum peer",
|
||||
}
|
||||
|
||||
// TDesktop 点 Direct Messages 入口会先按 monoforum peer 拉普通 channel history。
|
||||
// 主历史只应返回 monoforum 自身的 service messages,不能混入 saved_peer 子会话消息。
|
||||
|
|
@ -83,6 +93,7 @@ func TestMonoforumSavedDialogsAndHistory(t *testing.T) {
|
|||
if len(mainHistory.Messages) != 1 {
|
||||
t.Fatalf("main monoforum history = %d msgs, want only the creation service", len(mainHistory.Messages))
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, mainHistory, monoforumPeer, monoforumIcon)
|
||||
service, ok := mainHistory.Messages[0].(*tg.MessageService)
|
||||
if !ok {
|
||||
t.Fatalf("main monoforum message = %T, want MessageService", mainHistory.Messages[0])
|
||||
|
|
@ -167,6 +178,7 @@ func TestMonoforumSavedDialogsAndHistory(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("getSavedHistory(monoforum): %v", err)
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, hres, monoforumPeer, monoforumIcon)
|
||||
var gotMsgs []tg.MessageClass
|
||||
switch m := hres.(type) {
|
||||
case *tg.MessagesMessages:
|
||||
|
|
|
|||
|
|
@ -265,12 +265,14 @@ func (r *Router) onMessagesGetUnreadPollVotes(ctx context.Context, req *tg.Messa
|
|||
if topMsgID, ok := req.GetTopMsgID(); ok && (topMsgID < 0 || topMsgID > domain.MaxMessageBoxID) {
|
||||
return nil, messageIDInvalidErr()
|
||||
}
|
||||
return &tg.MessagesMessages{
|
||||
result := &tg.MessagesMessages{
|
||||
Messages: []tg.MessageClass{},
|
||||
Topics: []tg.ForumTopicClass{},
|
||||
Chats: r.chatsForInputPeer(ctx, userID, req.Peer),
|
||||
Users: []tg.UserClass{},
|
||||
}, nil
|
||||
}
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Router) onMessagesReadPollVotes(ctx context.Context, req *tg.MessagesReadPollVotesRequest) (*tg.MessagesAffectedHistory, error) {
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ func (r *Router) onMessagesGetQuickReplyMessages(ctx context.Context, req *tg.Me
|
|||
}
|
||||
out := tgMessagesQuickReplyMessages(list)
|
||||
out.Users = r.quickReplyUsers(ctx, userID)
|
||||
r.applyPeerReadModelsToMessages(ctx, userID, out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -447,6 +447,16 @@ func TestMessagesGetSavedDialogsByID(t *testing.T) {
|
|||
func TestMessagesGetSavedHistoryFiltersBySavedPeer(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r, _, alice, bob, noteID, fwdID := savedDialogsFixture(t)
|
||||
verify := newFakeBotVerifications()
|
||||
r.deps.BotVerifications = verify
|
||||
const savedHistoryIcon = int64(8800022)
|
||||
bobPeer := domain.Peer{Type: domain.PeerTypeUser, ID: bob.ID}
|
||||
verify.marks[bobPeer] = domain.CustomVerification{
|
||||
VerifierBotID: 777000123,
|
||||
Peer: bobPeer,
|
||||
IconDocumentID: savedHistoryIcon,
|
||||
Description: "Verified saved peer",
|
||||
}
|
||||
|
||||
bobHistory, err := r.onMessagesGetSavedHistory(WithUserID(ctx, alice.ID), &tg.MessagesGetSavedHistoryRequest{
|
||||
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
|
|
@ -455,6 +465,7 @@ func TestMessagesGetSavedHistoryFiltersBySavedPeer(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("getSavedHistory bob: %v", err)
|
||||
}
|
||||
assertMessagesEnvelopeBotVerificationIcon(t, bobHistory, bobPeer, savedHistoryIcon)
|
||||
bobMsgs := savedHistoryMessages(t, bobHistory)
|
||||
if len(bobMsgs) != 1 || bobMsgs[0].ID != fwdID {
|
||||
t.Fatalf("bob saved history = %+v, want forwarded message only", bobMsgs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue