134 lines
5.6 KiB
Go
134 lines
5.6 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/iamxvbaba/td/clock"
|
|
"github.com/iamxvbaba/td/tg"
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
appaccount "telesrv/internal/app/account"
|
|
appupdates "telesrv/internal/app/updates"
|
|
"telesrv/internal/domain"
|
|
"telesrv/internal/store/memory"
|
|
)
|
|
|
|
func TestAccountChangePhoneRPCReturnsSelfPushesOthersAndReplaysDifference(t *testing.T) {
|
|
ctx := context.Background()
|
|
users := memory.NewUserStore()
|
|
auths := memory.NewAuthorizationStore()
|
|
codes := memory.NewCodeStore()
|
|
events := memory.NewUpdateEventStore()
|
|
user, err := users.Create(ctx, domain.User{AccessHash: 401, Phone: "15550013001", FirstName: "Alice", Username: "Alice"})
|
|
if err != nil {
|
|
t.Fatalf("create user: %v", err)
|
|
}
|
|
authKeyID := [8]byte{4, 3, 2, 1}
|
|
if err := auths.Bind(ctx, domain.Authorization{AuthKeyID: authKeyID, UserID: user.ID, CreatedAt: time.Now().Add(-48 * time.Hour)}); err != nil {
|
|
t.Fatalf("bind auth: %v", err)
|
|
}
|
|
accountSvc := appaccount.NewService(
|
|
memory.NewPasswordStore(),
|
|
appaccount.WithUsers(users),
|
|
appaccount.WithPhoneChange(memory.NewPhoneChangeStore(users, events), auths, codes, nil, "12345", time.Minute, 5),
|
|
)
|
|
registry := newFakeUsernameRegistry()
|
|
registry.byPeer[domain.Peer{Type: domain.PeerTypeUser, ID: user.ID}] = []domain.Username{
|
|
{Username: "Alice", Editable: true, Active: true, SortOrder: 0},
|
|
{Username: "aliceCollect0728b", Active: true, SortOrder: 1, CollectibleID: 2},
|
|
}
|
|
sessions := &captureSessions{}
|
|
r := New(Config{}, Deps{Account: accountSvc, Sessions: sessions, Usernames: registry}, zaptest.NewLogger(t), clock.System)
|
|
reqCtx := WithSessionID(WithAuthKeyID(WithUserID(ctx, user.ID), authKeyID), 77)
|
|
|
|
sentClass, err := r.onAccountSendChangePhoneCode(reqCtx, &tg.AccountSendChangePhoneCodeRequest{PhoneNumber: "+1 555 001 3002"})
|
|
if err != nil {
|
|
t.Fatalf("send change phone code: %v", err)
|
|
}
|
|
sent, ok := sentClass.(*tg.AuthSentCode)
|
|
if !ok {
|
|
t.Fatalf("sent code = %T", sentClass)
|
|
}
|
|
if _, ok := sent.Type.(*tg.AuthSentCodeTypeSMS); !ok || sent.PhoneCodeHash == "" {
|
|
t.Fatalf("sent code type/hash = %T/%q", sent.Type, sent.PhoneCodeHash)
|
|
}
|
|
|
|
userClass, err := r.onAccountChangePhone(reqCtx, &tg.AccountChangePhoneRequest{
|
|
PhoneNumber: "15550013002",
|
|
PhoneCodeHash: sent.PhoneCodeHash,
|
|
PhoneCode: "12345",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("change phone: %v", err)
|
|
}
|
|
self, ok := userClass.(*tg.User)
|
|
if !ok || self.ID != user.ID || self.Phone != "15550013002" {
|
|
t.Fatalf("returned self = %T %+v", userClass, userClass)
|
|
}
|
|
assertVectorOnlyUsernames(t, "account.changePhone", self, []string{"Alice", "aliceCollect0728b"})
|
|
|
|
otherPush, ok := sessions.lastUserPush().(*tg.Updates)
|
|
if !ok || len(otherPush.Updates) != 2 {
|
|
t.Fatalf("other-session push = %T %+v", sessions.lastUserPush(), sessions.lastUserPush())
|
|
}
|
|
phoneUpdate, ok := otherPush.Updates[0].(*tg.UpdateUserPhone)
|
|
if !ok || phoneUpdate.UserID != user.ID || phoneUpdate.Phone != "15550013002" {
|
|
t.Fatalf("phone update = %T %+v", otherPush.Updates[0], otherPush.Updates[0])
|
|
}
|
|
if _, ok := otherPush.Updates[1].(*tg.UpdateDeleteMessages); !ok {
|
|
t.Fatalf("pts bookkeeping = %T", otherPush.Updates[1])
|
|
}
|
|
currentPush, ok := sessions.snapshot().message.(*tg.Updates)
|
|
if !ok || len(currentPush.Updates) != 1 {
|
|
t.Fatalf("current-session bookkeeping = %T %+v", sessions.snapshot().message, sessions.snapshot().message)
|
|
}
|
|
if _, ok := currentPush.Updates[0].(*tg.UpdateDeleteMessages); !ok {
|
|
t.Fatalf("current bookkeeping update = %T", currentPush.Updates[0])
|
|
}
|
|
|
|
updateSvc := appupdates.NewService(memory.NewUpdateStateStore(), events)
|
|
diff, err := updateSvc.GetDifference(ctx, [8]byte{9}, user.ID, domain.UpdateState{Pts: 0})
|
|
if err != nil {
|
|
t.Fatalf("get difference: %v", err)
|
|
}
|
|
tgDiff, ok := tgUpdatesDifference(user.ID, diff).(*tg.UpdatesDifference)
|
|
if !ok || len(tgDiff.OtherUpdates) != 1 {
|
|
t.Fatalf("difference = %T %+v", tgUpdatesDifference(user.ID, diff), tgUpdatesDifference(user.ID, diff))
|
|
}
|
|
replayed, ok := tgDiff.OtherUpdates[0].(*tg.UpdateUserPhone)
|
|
if !ok || replayed.UserID != user.ID || replayed.Phone != "15550013002" {
|
|
t.Fatalf("replayed update = %T %+v", tgDiff.OtherUpdates[0], tgDiff.OtherUpdates[0])
|
|
}
|
|
}
|
|
|
|
func TestAccountChangePhoneRPCMapsCodeAndOccupiedErrors(t *testing.T) {
|
|
ctx := context.Background()
|
|
users := memory.NewUserStore()
|
|
auths := memory.NewAuthorizationStore()
|
|
codes := memory.NewCodeStore()
|
|
events := memory.NewUpdateEventStore()
|
|
user, _ := users.Create(ctx, domain.User{AccessHash: 411, Phone: "15550013101", FirstName: "Alice"})
|
|
occupied, _ := users.Create(ctx, domain.User{AccessHash: 412, Phone: "15550013102", FirstName: "Bob"})
|
|
authKeyID := [8]byte{5, 4, 3, 2}
|
|
if err := auths.Bind(ctx, domain.Authorization{AuthKeyID: authKeyID, UserID: user.ID}); err != nil {
|
|
t.Fatalf("bind auth: %v", err)
|
|
}
|
|
accountSvc := appaccount.NewService(memory.NewPasswordStore(),
|
|
appaccount.WithUsers(users),
|
|
appaccount.WithPhoneChange(memory.NewPhoneChangeStore(users, events), auths, codes, nil, "12345", time.Minute, 5))
|
|
r := New(Config{}, Deps{Account: accountSvc}, zaptest.NewLogger(t), clock.System)
|
|
reqCtx := WithSessionID(WithAuthKeyID(WithUserID(ctx, user.ID), authKeyID), 88)
|
|
|
|
if _, err := r.onAccountSendChangePhoneCode(reqCtx, &tg.AccountSendChangePhoneCodeRequest{PhoneNumber: occupied.Phone}); err == nil {
|
|
t.Fatal("occupied phone unexpectedly accepted")
|
|
} else {
|
|
assertPhoneRPCErr(t, err, "PHONE_NUMBER_OCCUPIED")
|
|
}
|
|
if _, err := r.onAccountChangePhone(reqCtx, &tg.AccountChangePhoneRequest{PhoneNumber: "15550013103"}); err == nil {
|
|
t.Fatal("empty code unexpectedly accepted")
|
|
} else {
|
|
assertPhoneRPCErr(t, err, "PHONE_CODE_EMPTY")
|
|
}
|
|
}
|