298 lines
11 KiB
Go
298 lines
11 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"github.com/iamxvbaba/td/bin"
|
|
"github.com/iamxvbaba/td/clock"
|
|
"github.com/iamxvbaba/td/proto"
|
|
"github.com/iamxvbaba/td/tg"
|
|
"go.uber.org/zap/zaptest"
|
|
"reflect"
|
|
"telesrv/internal/domain"
|
|
"testing"
|
|
)
|
|
|
|
func TestUpdatesDifferenceIncludesReadHistoryInbox(t *testing.T) {
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID}
|
|
got, ok := tgUpdatesDifference(0, domain.UpdateDifference{
|
|
State: domain.UpdateState{Pts: 6, Date: 1700000200, Seq: 5},
|
|
Events: []domain.UpdateEvent{{
|
|
Type: domain.UpdateEventReadHistoryInbox,
|
|
Pts: 6,
|
|
PtsCount: 1,
|
|
Date: 1700000200,
|
|
Peer: peer,
|
|
MaxID: 12,
|
|
StillUnreadCount: 0,
|
|
}},
|
|
}).(*tg.UpdatesDifference)
|
|
if !ok {
|
|
t.Fatalf("difference = %T, want *tg.UpdatesDifference", got)
|
|
}
|
|
if got.State.Pts != 6 || len(got.OtherUpdates) != 1 {
|
|
t.Fatalf("difference = %+v, want one read history update and pts=6", got)
|
|
}
|
|
update, ok := got.OtherUpdates[0].(*tg.UpdateReadHistoryInbox)
|
|
if !ok {
|
|
t.Fatalf("update = %T, want *tg.UpdateReadHistoryInbox", got.OtherUpdates[0])
|
|
}
|
|
if update.MaxID != 12 || update.Pts != 6 || update.PtsCount != 1 {
|
|
t.Fatalf("read update = %+v, want max_id=12 pts=6 pts_count=1", update)
|
|
}
|
|
}
|
|
|
|
func TestUpdatesDifferenceIncludesReadHistoryOutbox(t *testing.T) {
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: 1000000002}
|
|
got, ok := tgUpdatesDifference(0, domain.UpdateDifference{
|
|
State: domain.UpdateState{Pts: 7, Date: 1700000210, Seq: 0},
|
|
Events: []domain.UpdateEvent{{
|
|
Type: domain.UpdateEventReadHistoryOutbox,
|
|
Pts: 7,
|
|
PtsCount: 1,
|
|
Date: 1700000210,
|
|
Peer: peer,
|
|
MaxID: 9,
|
|
}},
|
|
}).(*tg.UpdatesDifference)
|
|
if !ok {
|
|
t.Fatalf("difference = %T, want *tg.UpdatesDifference", got)
|
|
}
|
|
if len(got.OtherUpdates) != 1 {
|
|
t.Fatalf("other updates = %+v, want one read outbox update", got.OtherUpdates)
|
|
}
|
|
update, ok := got.OtherUpdates[0].(*tg.UpdateReadHistoryOutbox)
|
|
if !ok || update.MaxID != 9 || update.Pts != 7 || update.PtsCount != 1 {
|
|
t.Fatalf("read outbox = %T %+v, want max_id=9 pts=7", got.OtherUpdates[0], got.OtherUpdates[0])
|
|
}
|
|
}
|
|
|
|
func TestMessagesGetOutboxReadDateReturnsDate(t *testing.T) {
|
|
const (
|
|
userID = int64(1000000001)
|
|
peerID = int64(1000000002)
|
|
)
|
|
messages := &captureMessages{outboxReadDate: 1700000300}
|
|
r := New(Config{}, Deps{Messages: messages}, zaptest.NewLogger(t), clock.System)
|
|
req := &tg.MessagesGetOutboxReadDateRequest{
|
|
Peer: &tg.InputPeerUser{UserID: peerID, AccessHash: 22},
|
|
MsgID: 3,
|
|
}
|
|
var in bin.Buffer
|
|
if err := req.Encode(&in); err != nil {
|
|
t.Fatalf("encode request: %v", err)
|
|
}
|
|
|
|
enc, err := r.Dispatch(WithUserID(context.Background(), userID), [8]byte{}, 77, &in)
|
|
if err != nil {
|
|
t.Fatalf("dispatch: %v", err)
|
|
}
|
|
got, ok := enc.(*tg.OutboxReadDate)
|
|
if !ok || got.Date != 1700000300 {
|
|
t.Fatalf("response = %T %#v, want outboxReadDate date", enc, enc)
|
|
}
|
|
if messages.outboxReadDateReq.OwnerUserID != userID || messages.outboxReadDateReq.Peer.ID != peerID || messages.outboxReadDateReq.ID != 3 {
|
|
t.Fatalf("read date request = %+v, want owner peer message id", messages.outboxReadDateReq)
|
|
}
|
|
}
|
|
|
|
func TestMessagesReadMessageContentsPushesUpdateToOtherSessions(t *testing.T) {
|
|
authKeyID := [8]byte{9, 9, 9}
|
|
messages := &captureMessages{
|
|
readContentsRes: domain.ReadMessageContentsResult{
|
|
OwnerUserID: 1000000001,
|
|
MessageIDs: []int{7, 8},
|
|
},
|
|
}
|
|
sessions := &captureSessions{}
|
|
r := New(Config{}, Deps{
|
|
Messages: messages,
|
|
Updates: &captureUpdates{state: domain.UpdateState{Pts: 42, Date: 1700000200}},
|
|
Sessions: sessions,
|
|
}, zaptest.NewLogger(t), clock.System)
|
|
ctx := WithSessionID(WithAuthKeyID(WithUserID(context.Background(), 1000000001), authKeyID), 55)
|
|
|
|
affected, err := r.onMessagesReadMessageContents(ctx, []int{7, 8})
|
|
if err != nil {
|
|
t.Fatalf("messages.readMessageContents: %v", err)
|
|
}
|
|
if affected.Pts != 42 || affected.PtsCount != 0 {
|
|
t.Fatalf("affected = %+v, want pts=42 pts_count=0", affected)
|
|
}
|
|
if messages.readContentsReq.OwnerUserID != 1000000001 || !reflect.DeepEqual(messages.readContentsReq.IDs, []int{7, 8}) {
|
|
t.Fatalf("read contents req = %+v", messages.readContentsReq)
|
|
}
|
|
snap := sessions.snapshot()
|
|
if snap.userID != 1000000001 || snap.sessionID != 55 || snap.messageType != proto.MessageFromServer {
|
|
t.Fatalf("push target = %+v", snap)
|
|
}
|
|
updates, ok := snap.message.(*tg.Updates)
|
|
if !ok {
|
|
t.Fatalf("pushed message = %T, want *tg.Updates", snap.message)
|
|
}
|
|
if len(updates.Updates) != 1 {
|
|
t.Fatalf("updates = %+v", updates.Updates)
|
|
}
|
|
read, ok := updates.Updates[0].(*tg.UpdateReadMessagesContents)
|
|
if !ok {
|
|
t.Fatalf("update = %T, want *tg.UpdateReadMessagesContents", updates.Updates[0])
|
|
}
|
|
if !reflect.DeepEqual(read.Messages, []int{7, 8}) || read.Pts != 42 || read.PtsCount != 0 {
|
|
t.Fatalf("read update = %+v", read)
|
|
}
|
|
}
|
|
|
|
func TestMessagesReadHistoryMarksDialogRead(t *testing.T) {
|
|
var authKeyID [8]byte
|
|
authKeyID[0] = 7
|
|
messages := &captureMessages{readResult: domain.ReadHistoryResult{
|
|
OwnerUserID: 1000000001,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID},
|
|
MaxID: 12,
|
|
Changed: true,
|
|
InboxEvent: domain.UpdateEvent{
|
|
Type: domain.UpdateEventReadHistoryInbox,
|
|
Pts: 5,
|
|
PtsCount: 1,
|
|
Date: 1700000100,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID},
|
|
MaxID: 12,
|
|
},
|
|
}}
|
|
updates := &captureUpdates{state: domain.UpdateState{Pts: 5, Date: 1700000100, Seq: 3}}
|
|
sessions := &captureSessions{}
|
|
r := New(Config{}, Deps{Messages: messages, Updates: updates, Sessions: sessions}, zaptest.NewLogger(t), clock.System)
|
|
req := &tg.MessagesReadHistoryRequest{
|
|
Peer: &tg.InputPeerUser{UserID: domain.OfficialSystemUserID, AccessHash: domain.OfficialSystemUser().AccessHash},
|
|
MaxID: 12,
|
|
}
|
|
var in bin.Buffer
|
|
if err := req.Encode(&in); err != nil {
|
|
t.Fatalf("encode request: %v", err)
|
|
}
|
|
|
|
enc, err := r.Dispatch(WithUserID(context.Background(), 1000000001), authKeyID, 0, &in)
|
|
if err != nil {
|
|
t.Fatalf("dispatch: %v", err)
|
|
}
|
|
got, ok := enc.(*tg.MessagesAffectedMessages)
|
|
if !ok {
|
|
t.Fatalf("response = %T, want *tg.MessagesAffectedMessages", enc)
|
|
}
|
|
if messages.readPeer.ID != domain.OfficialSystemUserID || messages.readMaxID != 12 {
|
|
t.Fatalf("read = peer %+v max %d, want official/12", messages.readPeer, messages.readMaxID)
|
|
}
|
|
if got.Pts != 5 || got.PtsCount != 1 {
|
|
t.Fatalf("affected = %+v, want recorded read-history pts", got)
|
|
}
|
|
gotSession := sessions.snapshot()
|
|
if gotSession.userID != 1000000001 || gotSession.messageType != proto.MessageFromServer {
|
|
t.Fatalf("push target = user %d type %v, want read update push to other sessions", gotSession.userID, gotSession.messageType)
|
|
}
|
|
}
|
|
|
|
func TestMessagesReadHistoryWithReliableDispatchPushesCurrentSessionReadUpdate(t *testing.T) {
|
|
var authKeyID [8]byte
|
|
authKeyID[0] = 8
|
|
messages := &captureMessages{readResult: domain.ReadHistoryResult{
|
|
OwnerUserID: 1000000001,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID},
|
|
MaxID: 12,
|
|
StillUnreadCount: 2,
|
|
Changed: true,
|
|
InboxEvent: domain.UpdateEvent{
|
|
Type: domain.UpdateEventReadHistoryInbox,
|
|
Pts: 5,
|
|
PtsCount: 1,
|
|
Date: 1700000100,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID},
|
|
MaxID: 12,
|
|
StillUnreadCount: 2,
|
|
},
|
|
}}
|
|
updates := &captureUpdates{
|
|
state: domain.UpdateState{Pts: 5, Date: 1700000100, Seq: 3},
|
|
reliableDispatch: true,
|
|
}
|
|
sessions := &captureSessions{}
|
|
r := New(Config{}, Deps{Messages: messages, Updates: updates, Sessions: sessions}, zaptest.NewLogger(t), clock.System)
|
|
req := &tg.MessagesReadHistoryRequest{
|
|
Peer: &tg.InputPeerUser{UserID: domain.OfficialSystemUserID, AccessHash: domain.OfficialSystemUser().AccessHash},
|
|
MaxID: 12,
|
|
}
|
|
var in bin.Buffer
|
|
if err := req.Encode(&in); err != nil {
|
|
t.Fatalf("encode request: %v", err)
|
|
}
|
|
|
|
enc, err := r.Dispatch(WithUserID(context.Background(), 1000000001), authKeyID, 77, &in)
|
|
if err != nil {
|
|
t.Fatalf("dispatch: %v", err)
|
|
}
|
|
got, ok := enc.(*tg.MessagesAffectedMessages)
|
|
if !ok {
|
|
t.Fatalf("response = %T, want *tg.MessagesAffectedMessages", enc)
|
|
}
|
|
if got.Pts != 5 || got.PtsCount != 1 {
|
|
t.Fatalf("affected = %+v, want recorded read-history pts", got)
|
|
}
|
|
if messages.readReq.OriginSessionID != 77 || messages.readReq.OriginAuthKeyID != authKeyID {
|
|
t.Fatalf("read origin = auth %v session %d, want request auth/session", messages.readReq.OriginAuthKeyID, messages.readReq.OriginSessionID)
|
|
}
|
|
snap := sessions.snapshot()
|
|
if snap.sessionID != 77 || snap.messageType != proto.MessageFromServer {
|
|
t.Fatalf("current-session push target = session %d type %v, want session 77 server message", snap.sessionID, snap.messageType)
|
|
}
|
|
updatesMsg, ok := snap.message.(*tg.Updates)
|
|
if !ok || len(updatesMsg.Updates) != 1 {
|
|
t.Fatalf("current-session push = %T %+v, want one updates container", snap.message, snap.message)
|
|
}
|
|
update, ok := updatesMsg.Updates[0].(*tg.UpdateReadHistoryInbox)
|
|
if !ok {
|
|
t.Fatalf("current-session update = %T, want *tg.UpdateReadHistoryInbox", updatesMsg.Updates[0])
|
|
}
|
|
if update.Pts != 5 || update.PtsCount != 1 || update.MaxID != 12 || update.StillUnreadCount != 2 {
|
|
t.Fatalf("current-session update = %+v, want pts=5 count=1 max=12 still=2", update)
|
|
}
|
|
}
|
|
|
|
func TestMessagesReadHistoryAlreadyReadReturnsCurrentStateWithoutEcho(t *testing.T) {
|
|
var authKeyID [8]byte
|
|
authKeyID[0] = 9
|
|
messages := &captureMessages{readResult: domain.ReadHistoryResult{
|
|
OwnerUserID: 1000000001,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.OfficialSystemUserID},
|
|
MaxID: 12,
|
|
StillUnreadCount: 0,
|
|
Changed: false,
|
|
}}
|
|
updates := &captureUpdates{
|
|
state: domain.UpdateState{Pts: 7, Date: 1700000101, Seq: 3},
|
|
reliableDispatch: true,
|
|
}
|
|
sessions := &captureSessions{}
|
|
r := New(Config{}, Deps{Messages: messages, Updates: updates, Sessions: sessions}, zaptest.NewLogger(t), clock.System)
|
|
req := &tg.MessagesReadHistoryRequest{
|
|
Peer: &tg.InputPeerUser{UserID: domain.OfficialSystemUserID, AccessHash: domain.OfficialSystemUser().AccessHash},
|
|
MaxID: 12,
|
|
}
|
|
var in bin.Buffer
|
|
if err := req.Encode(&in); err != nil {
|
|
t.Fatalf("encode request: %v", err)
|
|
}
|
|
|
|
enc, err := r.Dispatch(WithUserID(context.Background(), 1000000001), authKeyID, 88, &in)
|
|
if err != nil {
|
|
t.Fatalf("dispatch: %v", err)
|
|
}
|
|
got, ok := enc.(*tg.MessagesAffectedMessages)
|
|
if !ok {
|
|
t.Fatalf("response = %T, want *tg.MessagesAffectedMessages", enc)
|
|
}
|
|
if got.Pts != 7 || got.PtsCount != 0 {
|
|
t.Fatalf("affected = %+v, want current pts without advancing", got)
|
|
}
|
|
snap := sessions.snapshot()
|
|
if snap.message != nil {
|
|
t.Fatalf("current-session push = %T, want no direct echo for already-read request", snap.message)
|
|
}
|
|
}
|