owpengram-server/internal/rpc/username_notify_test.go
Egor Egorov fff8de783a
feat: add NFT usernames and bot verification (#22)
Implements collectible usernames, official verification workflows, and third-party bot verification after maintainer protocol and migration review.

The composite activity/moderation rating remains an admin-only read model; Telegram Stars Rating wire fields stay unset pending a dedicated official-semantics implementation.

Reviewed-Head: 2796345775ea0f908fb7734601e5e1dee4b653b9
Original-Head: fa082b892fd5180c9c9bc53c81c21cf5d250a75b

Co-authored-by: Egor Egorov <business.egor.sg@gmail.com>
2026-07-28 01:18:00 +08:00

94 lines
3.3 KiB
Go

package rpc
import (
"context"
"testing"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
usernamesapp "telesrv/internal/app/usernames"
"telesrv/internal/domain"
)
var _ usernamesapp.PeerUsernameNotifier = (*Router)(nil)
func TestNotifyPeerUsernamesChangedUserPushesPreloadedVector(t *testing.T) {
const (
targetID = int64(2002)
viewerID = int64(1001)
)
users := &verifiedNotifyUsers{
user: domain.User{ID: targetID, FirstName: "Owner", Username: "owner_slot"},
found: true,
audience: []int64{targetID, viewerID},
}
registry := newFakeUsernameRegistry()
registry.byPeer[domain.Peer{Type: domain.PeerTypeUser, ID: targetID}] = []domain.Username{
{Username: "owner_slot", Editable: true, Active: true},
{Username: "nft", Active: true, CollectibleID: 7},
}
sessions := &captureSessions{onlineUserIDs: []int64{targetID, viewerID}}
r := New(Config{}, Deps{Users: users, Usernames: registry, Sessions: sessions}, zap.NewNop(), clock.System)
if err := r.NotifyPeerUsernamesChanged(context.Background(), domain.Peer{
Type: domain.PeerTypeUser, ID: targetID,
}); err != nil {
t.Fatalf("notify user usernames: %v", err)
}
if registry.peerCalls != 1 || registry.batchCalls != 0 {
t.Fatalf("registry reads = peer %d / batch %d, want one peer-wide read", registry.peerCalls, registry.batchCalls)
}
updates := sessions.lastUserPush().(*tg.Updates)
user := updates.Users[0].(*tg.User)
if scalar, ok := user.GetUsername(); ok || scalar != "" {
t.Fatalf("pushed scalar username = %q (set %v), want absent", scalar, ok)
}
vector, ok := user.GetUsernames()
if !ok || len(vector) != 2 || vector[1].Username != "nft" {
t.Fatalf("pushed username vector = %+v (set %v)", vector, ok)
}
}
func TestNotifyPeerUsernamesChangedChannelPushesPreloadedVector(t *testing.T) {
const (
channelID = int64(4004)
ownerID = int64(3003)
memberID = int64(3004)
)
channels := &verifiedNotifyChannels{channel: domain.Channel{
ID: channelID, AccessHash: 44, CreatorUserID: ownerID,
Title: "Collectible", Username: "channel_slot", Broadcast: true,
}}
registry := newFakeUsernameRegistry()
registry.byPeer[domain.Peer{Type: domain.PeerTypeChannel, ID: channelID}] = []domain.Username{
{Username: "channel_slot", Editable: true, Active: true},
{Username: "collectible", Active: true, CollectibleID: 9},
}
sessions := &captureSessions{
onlineUserIDs: []int64{ownerID, memberID},
channelMembers: map[int64][]int64{channelID: {ownerID, memberID}},
}
r := New(Config{}, Deps{
Channels: channels, Usernames: registry, Sessions: sessions,
}, zap.NewNop(), clock.System)
if err := r.NotifyPeerUsernamesChanged(context.Background(), domain.Peer{
Type: domain.PeerTypeChannel, ID: channelID,
}); err != nil {
t.Fatalf("notify channel usernames: %v", err)
}
if registry.peerCalls != 1 || registry.batchCalls != 0 {
t.Fatalf("registry reads = peer %d / batch %d, want one peer-wide read", registry.peerCalls, registry.batchCalls)
}
updates := sessions.lastUserPush().(*tg.Updates)
channel := updates.Chats[0].(*tg.Channel)
if scalar, ok := channel.GetUsername(); ok || scalar != "" {
t.Fatalf("pushed scalar username = %q (set %v), want absent", scalar, ok)
}
vector, ok := channel.GetUsernames()
if !ok || len(vector) != 2 || vector[1].Username != "collectible" {
t.Fatalf("pushed username vector = %+v (set %v)", vector, ok)
}
}