owpengram-server/internal/rpc/messages_chat_theme_rpc_test.go

303 lines
11 KiB
Go

package rpc
import (
"context"
"strings"
"testing"
"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"
appmessages "telesrv/internal/app/messages"
appusers "telesrv/internal/app/users"
"telesrv/internal/domain"
"telesrv/internal/seed/appearance"
"telesrv/internal/store/memory"
)
func TestMessagesSetChatThemePrivatePersistsServiceMessageAndUserFull(t *testing.T) {
ctx := context.Background()
userStore := memory.NewUserStore()
alice, _ := userStore.Create(ctx, domain.User{AccessHash: 1001, Phone: "15550003101", FirstName: "Alice"})
bob, _ := userStore.Create(ctx, domain.User{AccessHash: 1002, Phone: "15550003102", FirstName: "Bob"})
dialogStore := memory.NewDialogStore()
messageStore := memory.NewMessageStore(dialogStore)
router := New(Config{}, Deps{
Users: appusers.NewService(userStore),
Dialogs: appdialogs.NewService(dialogStore),
Messages: appmessages.NewService(messageStore, dialogStore),
}, zaptest.NewLogger(t), clock.System)
theme := "\U0001f338"
if cts := appearance.Default().ChatThemes; len(cts) > 0 {
theme = cts[0].Emoticon
}
set, err := router.onMessagesSetChatTheme(WithUserID(ctx, alice.ID), &tg.MessagesSetChatThemeRequest{
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
Theme: &tg.InputChatTheme{Emoticon: theme},
})
if err != nil {
t.Fatalf("set chat theme: %v", err)
}
setAction := chatThemeActionFromUpdates(t, set)
if got := setAction.Theme.(*tg.ChatTheme).Emoticon; got != theme {
t.Fatalf("set action emoticon = %q, want %q", got, theme)
}
assertDialogTheme(t, dialogStore, alice.ID, bob.ID, theme)
assertDialogTheme(t, dialogStore, bob.ID, alice.ID, theme)
full, err := router.onUsersGetFullUser(WithUserID(ctx, alice.ID), &tg.InputUser{UserID: bob.ID, AccessHash: bob.AccessHash})
if err != nil {
t.Fatalf("get full user after set: %v", err)
}
if gotTheme, ok := full.FullUser.GetTheme(); !ok || gotTheme.(*tg.ChatTheme).Emoticon != theme {
t.Fatalf("full user theme = %#v ok=%v, want %q", gotTheme, ok, theme)
}
clear, err := router.onMessagesSetChatTheme(WithUserID(ctx, alice.ID), &tg.MessagesSetChatThemeRequest{
Peer: &tg.InputPeerUser{UserID: bob.ID, AccessHash: bob.AccessHash},
Theme: &tg.InputChatTheme{Emoticon: ""},
})
if err != nil {
t.Fatalf("clear chat theme: %v", err)
}
clearAction := chatThemeActionFromUpdates(t, clear)
if got := clearAction.Theme.(*tg.ChatTheme).Emoticon; got != "" {
t.Fatalf("clear action emoticon = %q, want empty", got)
}
assertDialogTheme(t, dialogStore, alice.ID, bob.ID, "")
assertDialogTheme(t, dialogStore, bob.ID, alice.ID, "")
full, err = router.onUsersGetFullUser(WithUserID(ctx, alice.ID), &tg.InputUser{UserID: bob.ID, AccessHash: bob.AccessHash})
if err != nil {
t.Fatalf("get full user after clear: %v", err)
}
if gotTheme, ok := full.FullUser.GetTheme(); ok {
t.Fatalf("full user theme after clear = %#v, want absent", gotTheme)
}
}
func TestMessagesSetChatThemeRejectsUnsupportedThemes(t *testing.T) {
router := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System)
ctx := WithUserID(context.Background(), 1000000001)
for _, req := range []*tg.MessagesSetChatThemeRequest{
{Peer: &tg.InputPeerUser{UserID: 1000000002}, Theme: &tg.InputChatTheme{Emoticon: "\U0001f47b"}},
{Peer: &tg.InputPeerUser{UserID: 1000000002}, Theme: &tg.InputChatThemeUniqueGift{Slug: "gift"}},
} {
_, err := router.onMessagesSetChatTheme(ctx, req)
if err == nil || !strings.Contains(err.Error(), "THEME_INVALID") {
t.Fatalf("set unsupported theme err = %v, want THEME_INVALID", err)
}
}
}
func TestMessagesSetChatWallPaperAcksPrivatePeerAndSupportsChannel(t *testing.T) {
router := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System)
ctx := WithUserID(context.Background(), 1000000001)
okReq := &tg.MessagesSetChatWallPaperRequest{
Peer: &tg.InputPeerUser{UserID: 1000000002},
}
okReq.SetWallpaper(&tg.InputWallPaperNoFile{ID: 930000000000000000})
if got, err := router.onMessagesSetChatWallPaper(ctx, okReq); err != nil {
t.Fatalf("set chat wallpaper: %v", err)
} else if updates, ok := got.(*tg.Updates); !ok || len(updates.Updates) != 0 || updates.Date == 0 {
t.Fatalf("set chat wallpaper updates = %#v, want dated empty updates", got)
}
for _, req := range []*tg.MessagesSetChatWallPaperRequest{
nil,
{Peer: &tg.InputPeerEmpty{}},
{Peer: &tg.InputPeerChannel{ChannelID: 10}},
} {
_, err := router.onMessagesSetChatWallPaper(ctx, req)
if err == nil {
t.Fatalf("set chat wallpaper with %#v succeeded, want error", req)
}
}
userStore := memory.NewUserStore()
alice, _ := userStore.Create(context.Background(), domain.User{AccessHash: 2001, Phone: "15550003201", FirstName: "Alice"})
bob, _ := userStore.Create(context.Background(), domain.User{AccessHash: 2002, Phone: "15550003202", FirstName: "Bob"})
channelStore := memory.NewChannelStore()
channels := appchannels.NewService(channelStore)
created, err := channels.CreateChannel(context.Background(), alice.ID, domain.CreateChannelRequest{
Title: "Wallpaper Channel",
Broadcast: true,
MemberUserIDs: []int64{bob.ID},
Date: 1700000100,
})
if err != nil {
t.Fatalf("create channel: %v", err)
}
router = New(Config{}, Deps{
Users: appusers.NewService(userStore),
Channels: channels,
}, zaptest.NewLogger(t), clock.System)
settings := tg.WallPaperSettings{}
settings.SetBackgroundColor(0)
settings.SetSecondBackgroundColor(0x95c46a)
settings.SetRotation(45)
channelReq := &tg.MessagesSetChatWallPaperRequest{
Peer: &tg.InputPeerChannel{ChannelID: created.Channel.ID, AccessHash: created.Channel.AccessHash},
}
channelReq.SetWallpaper(&tg.InputWallPaperNoFile{ID: 930000000000000001})
channelReq.SetSettings(settings)
got, err := router.onMessagesSetChatWallPaper(WithUserID(context.Background(), alice.ID), channelReq)
if err != nil {
t.Fatalf("set channel wallpaper: %v", err)
}
updates, ok := got.(*tg.Updates)
if !ok {
t.Fatalf("set channel wallpaper updates = %T, want *tg.Updates", got)
}
action := channelWallpaperActionFromUpdates(t, updates)
actionWallpaper, ok := action.Wallpaper.(*tg.WallPaperNoFile)
if !ok || actionWallpaper.ID != 930000000000000001 {
t.Fatalf("service wallpaper = %T %#v, want wallPaperNoFile id", action.Wallpaper, action.Wallpaper)
}
peerWallpaper := channelPeerWallpaperFromUpdates(t, updates)
if gotID := peerWallpaper.ID; gotID != 930000000000000001 {
t.Fatalf("updatePeerWallpaper id = %d, want selected wallpaper id", gotID)
}
if color, ok := peerWallpaper.Settings.GetBackgroundColor(); !ok || color != 0 {
t.Fatalf("background color = %d ok=%v, want explicit black", color, ok)
}
view, err := channels.GetChannel(context.Background(), alice.ID, created.Channel.ID)
if err != nil {
t.Fatalf("get channel after wallpaper: %v", err)
}
if view.Channel.Wallpaper == nil || !view.Channel.Wallpaper.NoFile || !view.Channel.Wallpaper.Settings.HasBackgroundColor {
t.Fatalf("stored channel wallpaper = %#v, want no-file with explicit settings", view.Channel.Wallpaper)
}
full := tgChannelFull(view)
fullWallpaper, ok := full.GetWallpaper()
if !ok {
t.Fatalf("channelFull wallpaper missing")
}
fullNoFile, ok := fullWallpaper.(*tg.WallPaperNoFile)
if !ok || fullNoFile.ID != 930000000000000001 {
t.Fatalf("channelFull wallpaper = %T %#v, want selected no-file", fullWallpaper, fullWallpaper)
}
clearReq := &tg.MessagesSetChatWallPaperRequest{Peer: channelReq.Peer}
clearGot, err := router.onMessagesSetChatWallPaper(WithUserID(context.Background(), alice.ID), clearReq)
if err != nil {
t.Fatalf("clear channel wallpaper: %v", err)
}
clearUpdates, ok := clearGot.(*tg.Updates)
if !ok {
t.Fatalf("clear channel wallpaper updates = %T, want *tg.Updates", clearGot)
}
if channelPeerWallpaperPresent(clearUpdates) {
t.Fatalf("clear updatePeerWallpaper carried wallpaper, want absent wallpaper")
}
view, err = channels.GetChannel(context.Background(), alice.ID, created.Channel.ID)
if err != nil {
t.Fatalf("get channel after clear wallpaper: %v", err)
}
if view.Channel.Wallpaper != nil {
t.Fatalf("stored channel wallpaper after clear = %#v, want nil", view.Channel.Wallpaper)
}
if _, ok := tgChannelFull(view).GetWallpaper(); ok {
t.Fatalf("channelFull wallpaper after clear present, want absent")
}
_, err = router.onMessagesSetChatWallPaper(WithUserID(context.Background(), bob.ID), channelReq)
if err == nil || !strings.Contains(err.Error(), "CHAT_ADMIN_REQUIRED") {
t.Fatalf("non-admin set channel wallpaper err = %v, want CHAT_ADMIN_REQUIRED", err)
}
}
func channelWallpaperActionFromUpdates(t *testing.T, updates *tg.Updates) *tg.MessageActionSetChatWallPaper {
t.Helper()
for _, update := range updates.Updates {
newMessage, ok := update.(*tg.UpdateNewChannelMessage)
if !ok {
continue
}
service, ok := newMessage.Message.(*tg.MessageService)
if !ok {
continue
}
action, ok := service.Action.(*tg.MessageActionSetChatWallPaper)
if !ok {
t.Fatalf("channel service action = %T, want MessageActionSetChatWallPaper", service.Action)
}
return action
}
t.Fatalf("updates = %#v, want UpdateNewChannelMessage wallpaper service action", updates.Updates)
return nil
}
func channelPeerWallpaperFromUpdates(t *testing.T, updates *tg.Updates) *tg.WallPaperNoFile {
t.Helper()
for _, update := range updates.Updates {
peerWallpaper, ok := update.(*tg.UpdatePeerWallpaper)
if !ok {
continue
}
wallpaper, ok := peerWallpaper.GetWallpaper()
if !ok {
t.Fatalf("updatePeerWallpaper missing wallpaper")
}
noFile, ok := wallpaper.(*tg.WallPaperNoFile)
if !ok {
t.Fatalf("updatePeerWallpaper wallpaper = %T, want WallPaperNoFile", wallpaper)
}
return noFile
}
t.Fatalf("updates = %#v, want UpdatePeerWallpaper", updates.Updates)
return nil
}
func channelPeerWallpaperPresent(updates *tg.Updates) bool {
for _, update := range updates.Updates {
peerWallpaper, ok := update.(*tg.UpdatePeerWallpaper)
if !ok {
continue
}
_, ok = peerWallpaper.GetWallpaper()
return ok
}
return false
}
func chatThemeActionFromUpdates(t *testing.T, updates tg.UpdatesClass) *tg.MessageActionSetChatTheme {
t.Helper()
got, ok := updates.(*tg.Updates)
if !ok {
t.Fatalf("updates = %T, want *tg.Updates", updates)
}
for _, update := range got.Updates {
newMessage, ok := update.(*tg.UpdateNewMessage)
if !ok {
continue
}
service, ok := newMessage.Message.(*tg.MessageService)
if !ok {
continue
}
action, ok := service.Action.(*tg.MessageActionSetChatTheme)
if !ok {
t.Fatalf("service action = %T, want MessageActionSetChatTheme", service.Action)
}
return action
}
t.Fatalf("updates = %#v, want UpdateNewMessage service action", got.Updates)
return nil
}
func assertDialogTheme(t *testing.T, dialogs *memory.DialogStore, ownerID, peerID int64, want string) {
t.Helper()
list, err := dialogs.ListByPeers(context.Background(), ownerID, []domain.Peer{{Type: domain.PeerTypeUser, ID: peerID}})
if err != nil {
t.Fatalf("list dialogs for %d/%d: %v", ownerID, peerID, err)
}
if len(list.Dialogs) != 1 {
t.Fatalf("dialogs for %d/%d = %d, want 1", ownerID, peerID, len(list.Dialogs))
}
if got := list.Dialogs[0].ThemeEmoticon; got != want {
t.Fatalf("dialog theme for %d/%d = %q, want %q", ownerID, peerID, got, want)
}
}