owpengram-server/internal/rpc/messages_sticker_sets_rpc_test.go

306 lines
12 KiB
Go

package rpc
import (
"context"
"testing"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
appaccount "telesrv/internal/app/account"
"telesrv/internal/domain"
"telesrv/internal/store/memory"
)
func userStickerSetRouter(t *testing.T) (*Router, *memory.PasswordStore, *captureSessions) {
t.Helper()
files := &fakeFiles{
docs: map[int64]domain.Document{
101: {ID: 101, AccessHash: 11, Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
102: {ID: 102, AccessHash: 12, Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
},
sets: map[domain.StickerSetKind][]domain.StickerSet{
domain.StickerSetKindStickers: {
{ID: 10, AccessHash: 100, ShortName: "funny", Title: "Funny", Kind: domain.StickerSetKindStickers, Count: 1, Hash: 7, Installed: true, InstalledDate: 1, DocumentIDs: []int64{101}},
{ID: 20, AccessHash: 200, ShortName: "work", Title: "Work", Kind: domain.StickerSetKindStickers, Count: 1, Hash: 8, Installed: true, InstalledDate: 1, DocumentIDs: []int64{102}},
},
domain.StickerSetKindEmoji: {
{ID: 30, AccessHash: 300, ShortName: "emoji_fun", Title: "Emoji Fun", Kind: domain.StickerSetKindEmoji, Emojis: true, Count: 1, Hash: 9, Installed: true, InstalledDate: 1, DocumentIDs: []int64{101}},
},
},
}
passwordStore := memory.NewPasswordStore()
sessions := &captureSessions{}
router := New(Config{}, Deps{
Account: appaccount.NewService(passwordStore, appaccount.WithUserStickerSets(passwordStore)),
Files: files,
Sessions: sessions,
}, zaptest.NewLogger(t), clock.System)
return router, passwordStore, sessions
}
func TestMessagesInstallStickerSetPersistsAndPushesUpdate(t *testing.T) {
r, store, sessions := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
out, err := r.onMessagesInstallStickerSet(ctx, &tg.MessagesInstallStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: "funny"},
})
if err != nil {
t.Fatalf("install sticker set: %v", err)
}
if _, ok := out.(*tg.MessagesStickerSetInstallResultSuccess); !ok {
t.Fatalf("install result = %T, want *tg.MessagesStickerSetInstallResultSuccess", out)
}
items, total, err := store.ListUserStickerSets(ctx, 1000000001, domain.StickerSetKindStickers, nil, 0, 10)
if err != nil {
t.Fatalf("list installed sets: %v", err)
}
if total != 1 || len(items) != 1 || items[0].StickerSetID != 10 || items[0].Archived {
t.Fatalf("installed sets = total %d items %+v, want one active set 10", total, items)
}
assertStickerSetsUpdate(t, sessions.lastUserPush(), domain.StickerSetKindStickers, nil)
}
func TestMessagesInstallStickerSetUpdatesAllStickersProjection(t *testing.T) {
r, _, _ := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
before, err := r.onMessagesGetAllStickers(ctx, 0)
if err != nil {
t.Fatalf("get all stickers before install: %v", err)
}
if full, ok := before.(*tg.MessagesAllStickers); ok && len(full.Sets) != 0 {
t.Fatalf("all stickers before install = %+v, want empty non-default catalog", full.Sets)
}
if _, err := r.onMessagesInstallStickerSet(ctx, &tg.MessagesInstallStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: "funny"},
}); err != nil {
t.Fatalf("install sticker set: %v", err)
}
after, err := r.onMessagesGetAllStickers(ctx, 0)
if err != nil {
t.Fatalf("get all stickers after install: %v", err)
}
full, ok := after.(*tg.MessagesAllStickers)
if !ok {
t.Fatalf("get all stickers after install = %T, want *tg.MessagesAllStickers", after)
}
if len(full.Sets) != 1 || full.Sets[0].ID != 10 || full.Sets[0].InstalledDate == 0 {
t.Fatalf("all stickers after install = %+v, want installed set 10", full.Sets)
}
if ok, err := r.onMessagesUninstallStickerSet(ctx, &tg.InputStickerSetID{ID: 10, AccessHash: 100}); err != nil || !ok {
t.Fatalf("uninstall sticker set = %v %v", ok, err)
}
afterUninstall, err := r.onMessagesGetAllStickers(ctx, 0)
if err != nil {
t.Fatalf("get all stickers after uninstall: %v", err)
}
if full, ok := afterUninstall.(*tg.MessagesAllStickers); ok && len(full.Sets) != 0 {
t.Fatalf("all stickers after uninstall = %+v, want empty", full.Sets)
}
}
func TestMessagesEmptyViewerStickerSetsInvalidateOldClientHash(t *testing.T) {
r, _, _ := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
stickers, err := r.onMessagesGetAllStickers(ctx, 3041827464193675523)
if err != nil {
t.Fatalf("get all stickers with old hash: %v", err)
}
full, ok := stickers.(*tg.MessagesAllStickers)
if !ok {
t.Fatalf("get all stickers with old hash = %T, want full empty list", stickers)
}
if full.Hash != 0 || len(full.Sets) != 0 {
t.Fatalf("empty sticker list = hash %d sets %+v, want hash 0 with no sets", full.Hash, full.Sets)
}
emoji, err := r.onMessagesGetEmojiStickers(ctx, 7254637046733671932)
if err != nil {
t.Fatalf("get emoji stickers with old hash: %v", err)
}
emojiFull, ok := emoji.(*tg.MessagesAllStickers)
if !ok {
t.Fatalf("get emoji stickers with old hash = %T, want full empty list", emoji)
}
if emojiFull.Hash != 0 || len(emojiFull.Sets) != 0 {
t.Fatalf("empty emoji list = hash %d sets %+v, want hash 0 with no sets", emojiFull.Hash, emojiFull.Sets)
}
}
func TestMessagesGetStickerSetUsesViewerInstallState(t *testing.T) {
r, _, _ := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
before, err := r.onMessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: "funny"},
})
if err != nil {
t.Fatalf("get sticker set before install: %v", err)
}
full, ok := before.(*tg.MessagesStickerSet)
if !ok {
t.Fatalf("get sticker set before install = %T, want *tg.MessagesStickerSet", before)
}
if full.Set.InstalledDate != 0 {
t.Fatalf("preview installed_date before install = %d, want 0", full.Set.InstalledDate)
}
if _, err := r.onMessagesInstallStickerSet(ctx, &tg.MessagesInstallStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: "funny"},
}); err != nil {
t.Fatalf("install sticker set: %v", err)
}
after, err := r.onMessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: "funny"},
})
if err != nil {
t.Fatalf("get sticker set after install: %v", err)
}
full, ok = after.(*tg.MessagesStickerSet)
if !ok {
t.Fatalf("get sticker set after install = %T, want *tg.MessagesStickerSet", after)
}
if full.Set.InstalledDate == 0 {
t.Fatalf("preview installed_date after install = 0, want viewer install date")
}
}
func TestMessagesInstallStickerSetRejectsBadAccessHash(t *testing.T) {
r, store, sessions := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
out, err := r.onMessagesInstallStickerSet(ctx, &tg.MessagesInstallStickerSetRequest{
Stickerset: &tg.InputStickerSetID{ID: 10, AccessHash: 999},
})
if out != nil || !tgerr.Is(err, "STICKERSET_INVALID") {
t.Fatalf("install with bad access hash = %T %v, want STICKERSET_INVALID", out, err)
}
items, total, err := store.ListUserStickerSets(ctx, 1000000001, domain.StickerSetKindStickers, nil, 0, 10)
if err != nil {
t.Fatalf("list installed sets: %v", err)
}
if total != 0 || len(items) != 0 {
t.Fatalf("installed after rejected install = total %d items %+v, want empty", total, items)
}
if push := sessions.lastUserPush(); push != nil {
t.Fatalf("push after rejected install = %T, want nil", push)
}
}
func TestMessagesReorderAndToggleStickerSets(t *testing.T) {
r, store, sessions := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
for _, shortName := range []string{"funny", "work"} {
if _, err := r.onMessagesInstallStickerSet(ctx, &tg.MessagesInstallStickerSetRequest{Stickerset: &tg.InputStickerSetShortName{ShortName: shortName}}); err != nil {
t.Fatalf("install %s: %v", shortName, err)
}
}
if ok, err := r.onMessagesReorderStickerSets(ctx, &tg.MessagesReorderStickerSetsRequest{Order: []int64{20, 10, 20, 0}}); err != nil || !ok {
t.Fatalf("reorder = %v %v", ok, err)
}
if got := installedStickerSetIDs(t, store, ctx, 1000000001, domain.StickerSetKindStickers, nil); len(got) != 2 || got[0] != 20 || got[1] != 10 {
t.Fatalf("installed order = %v, want [20 10]", got)
}
assertStickerSetsUpdate(t, sessions.lastUserPush(), domain.StickerSetKindStickers, []int64{20, 10})
if ok, err := r.onMessagesToggleStickerSets(ctx, &tg.MessagesToggleStickerSetsRequest{
Stickersets: []tg.InputStickerSetClass{&tg.InputStickerSetID{ID: 20, AccessHash: 200}},
Uninstall: true,
}); err != nil || !ok {
t.Fatalf("toggle uninstall = %v %v", ok, err)
}
if got := installedStickerSetIDs(t, store, ctx, 1000000001, domain.StickerSetKindStickers, nil); len(got) != 1 || got[0] != 10 {
t.Fatalf("installed after toggle uninstall = %v, want [10]", got)
}
assertStickerSetsUpdate(t, sessions.lastUserPush(), domain.StickerSetKindStickers, nil)
}
func TestMessagesToggleEmojiStickerSetsUsesEmojiUpdateFlag(t *testing.T) {
r, store, sessions := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
if ok, err := r.onMessagesToggleStickerSets(ctx, &tg.MessagesToggleStickerSetsRequest{
Stickersets: []tg.InputStickerSetClass{&tg.InputStickerSetShortName{ShortName: "emoji_fun"}},
}); err != nil || !ok {
t.Fatalf("toggle emoji install = %v %v", ok, err)
}
if got := installedStickerSetIDs(t, store, ctx, 1000000001, domain.StickerSetKindEmoji, nil); len(got) != 1 || got[0] != 30 {
t.Fatalf("emoji installed sets = %v, want [30]", got)
}
assertStickerSetsUpdate(t, sessions.lastUserPush(), domain.StickerSetKindEmoji, nil)
}
func TestMessagesGetMyStickersEmptyUntilCreatorStore(t *testing.T) {
r, _, _ := userStickerSetRouter(t)
ctx := WithUserID(context.Background(), 1000000001)
out, err := r.onMessagesGetMyStickers(ctx, &tg.MessagesGetMyStickersRequest{Limit: 50})
if err != nil {
t.Fatalf("get my stickers: %v", err)
}
if out.Count != 0 || len(out.Sets) != 0 {
t.Fatalf("get my stickers = count %d sets %d, want empty creator-owned page", out.Count, len(out.Sets))
}
out, err = r.onMessagesGetMyStickers(ctx, &tg.MessagesGetMyStickersRequest{Limit: domain.MaxInstalledStickerSets + 1})
if out != nil || !tgerr.Is(err, "LIMIT_INVALID") {
t.Fatalf("get my stickers over limit = %T %v, want LIMIT_INVALID", out, err)
}
}
func installedStickerSetIDs(t *testing.T, store *memory.PasswordStore, ctx context.Context, userID int64, kind domain.StickerSetKind, archived *bool) []int64 {
t.Helper()
items, _, err := store.ListUserStickerSets(ctx, userID, kind, archived, 0, 10)
if err != nil {
t.Fatalf("list installed sticker sets: %v", err)
}
out := make([]int64, 0, len(items))
for _, item := range items {
out = append(out, item.StickerSetID)
}
return out
}
func assertStickerSetsUpdate(t *testing.T, push any, kind domain.StickerSetKind, order []int64) {
t.Helper()
updates, ok := push.(*tg.Updates)
if !ok {
t.Fatalf("push = %T, want *tg.Updates", push)
}
if len(updates.Updates) != 1 {
t.Fatalf("push updates = %d, want 1", len(updates.Updates))
}
if order != nil {
update, ok := updates.Updates[0].(*tg.UpdateStickerSetsOrder)
if !ok {
t.Fatalf("push update = %T, want *tg.UpdateStickerSetsOrder", updates.Updates[0])
}
if len(update.Order) != len(order) {
t.Fatalf("order update = %v, want %v", update.Order, order)
}
for i := range order {
if update.Order[i] != order[i] {
t.Fatalf("order update = %v, want %v", update.Order, order)
}
}
if update.Masks != (kind == domain.StickerSetKindMasks) || update.Emojis != (kind == domain.StickerSetKindEmoji) {
t.Fatalf("order flags masks=%v emojis=%v for kind %s", update.Masks, update.Emojis, kind)
}
return
}
update, ok := updates.Updates[0].(*tg.UpdateStickerSets)
if !ok {
t.Fatalf("push update = %T, want *tg.UpdateStickerSets", updates.Updates[0])
}
if update.Masks != (kind == domain.StickerSetKindMasks) || update.Emojis != (kind == domain.StickerSetKindEmoji) {
t.Fatalf("update flags masks=%v emojis=%v for kind %s", update.Masks, update.Emojis, kind)
}
}