chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
147
internal/rpc/channels_delete_monoforum_test.go
Normal file
147
internal/rpc/channels_delete_monoforum_test.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
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"
|
||||
|
||||
appchannels "telesrv/internal/app/channels"
|
||||
appdialogs "telesrv/internal/app/dialogs"
|
||||
appusers "telesrv/internal/app/users"
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
// TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC 锁定 Risk A 的 RPC 层契约:删除开启了
|
||||
// Direct Messages 的母广播频道时,响应与推送都必须为母频道 **和** 其关联 monoforum 各下发一条
|
||||
// ChannelForbidden 墓碑,且删后 getDialogs 两者都不再返回。否则在线客户端会留着 mono 会话
|
||||
// (isMonoforum=true 但 link 不可解析)继续渲染崩溃。
|
||||
func TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
userStore := memory.NewUserStore()
|
||||
owner, err := userStore.Create(ctx, domain.User{AccessHash: 41, Phone: "15550004041", FirstName: "Owner"})
|
||||
if err != nil {
|
||||
t.Fatalf("create owner: %v", err)
|
||||
}
|
||||
|
||||
channelStore := memory.NewChannelStore()
|
||||
bc, err := channelStore.CreateChannel(ctx, domain.CreateChannelRequest{
|
||||
CreatorUserID: owner.ID, Title: "DM Broadcast", Broadcast: true, Date: 1_700_000_900,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create broadcast: %v", err)
|
||||
}
|
||||
parentID := bc.Channel.ID
|
||||
enabled, err := channelStore.SetPaidMessagesPrice(ctx, owner.ID, parentID, 0, true)
|
||||
if err != nil {
|
||||
t.Fatalf("enable DM: %v", err)
|
||||
}
|
||||
monoID := enabled.Channel.LinkedMonoforumID
|
||||
if monoID == 0 {
|
||||
t.Fatalf("no monoforum created")
|
||||
}
|
||||
|
||||
sessions := &captureSessions{}
|
||||
r := New(Config{}, Deps{
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: appchannels.NewService(channelStore),
|
||||
Dialogs: appdialogs.NewService(memory.NewDialogStore(), channelStore),
|
||||
Sessions: sessions,
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
|
||||
getDialogChannelIDs := func() map[int64]struct{} {
|
||||
t.Helper()
|
||||
req := &tg.MessagesGetDialogsRequest{OffsetPeer: &tg.InputPeerEmpty{}, Limit: 50}
|
||||
var b bin.Buffer
|
||||
if err := req.Encode(&b); err != nil {
|
||||
t.Fatalf("encode get dialogs: %v", err)
|
||||
}
|
||||
enc, err := r.Dispatch(WithUserID(ctx, owner.ID), [8]byte{}, 0, &b)
|
||||
if err != nil {
|
||||
t.Fatalf("dispatch get dialogs: %v", err)
|
||||
}
|
||||
box, ok := enc.(*tg.MessagesDialogsBox)
|
||||
if !ok {
|
||||
t.Fatalf("dialogs response = %T, want box", enc)
|
||||
}
|
||||
ids := map[int64]struct{}{}
|
||||
switch d := box.Dialogs.(type) {
|
||||
case *tg.MessagesDialogs:
|
||||
for _, ch := range d.Chats {
|
||||
if c, ok := ch.(*tg.Channel); ok {
|
||||
ids[c.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
case *tg.MessagesDialogsSlice:
|
||||
for _, ch := range d.Chats {
|
||||
if c, ok := ch.(*tg.Channel); ok {
|
||||
ids[c.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
default:
|
||||
t.Fatalf("dialogs = %T, want messages.dialogs(Slice)", box.Dialogs)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
before := getDialogChannelIDs()
|
||||
if _, ok := before[parentID]; !ok {
|
||||
t.Fatalf("before delete: parent %d missing from dialogs %v", parentID, before)
|
||||
}
|
||||
if _, ok := before[monoID]; !ok {
|
||||
t.Fatalf("before delete: monoforum %d missing from dialogs %v", monoID, before)
|
||||
}
|
||||
|
||||
deleted, err := r.onChannelsDeleteChannel(WithUserID(ctx, owner.ID), &tg.InputChannel{
|
||||
ChannelID: parentID,
|
||||
AccessHash: bc.Channel.AccessHash,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("delete channel: %v", err)
|
||||
}
|
||||
|
||||
forbidden := func(updates *tg.Updates) map[int64]struct{} {
|
||||
ids := map[int64]struct{}{}
|
||||
for _, ch := range updates.Chats {
|
||||
if f, ok := ch.(*tg.ChannelForbidden); ok {
|
||||
ids[f.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
respUpdates, ok := deleted.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("delete response = %T, want *tg.Updates", deleted)
|
||||
}
|
||||
respForbidden := forbidden(respUpdates)
|
||||
if _, ok := respForbidden[parentID]; !ok {
|
||||
t.Fatalf("delete response missing ChannelForbidden for parent %d: %+v", parentID, respUpdates.Chats)
|
||||
}
|
||||
if _, ok := respForbidden[monoID]; !ok {
|
||||
t.Fatalf("delete response missing ChannelForbidden for monoforum %d: %+v", monoID, respUpdates.Chats)
|
||||
}
|
||||
|
||||
// 推送给接收方(含 owner 本人)的更新同样要带 mono 墓碑。
|
||||
pushed := sessions.snapshot()
|
||||
pushedUpdates, ok := pushed.message.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("pushed message = %T, want *tg.Updates", pushed.message)
|
||||
}
|
||||
pushedForbidden := forbidden(pushedUpdates)
|
||||
if _, ok := pushedForbidden[monoID]; !ok {
|
||||
t.Fatalf("pushed update missing ChannelForbidden for monoforum %d: %+v", monoID, pushedUpdates.Chats)
|
||||
}
|
||||
|
||||
after := getDialogChannelIDs()
|
||||
if _, ok := after[parentID]; ok {
|
||||
t.Fatalf("after delete: parent %d still in dialogs %v", parentID, after)
|
||||
}
|
||||
if _, ok := after[monoID]; ok {
|
||||
t.Fatalf("after delete: monoforum %d still in dialogs %v", monoID, after)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue