164 lines
6.4 KiB
Go
164 lines
6.4 KiB
Go
package memory
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
func TestMessageStorePrivateRandomIDConflictAndReplayFacts(t *testing.T) {
|
|
ctx := context.Background()
|
|
messages := NewMessageStore()
|
|
base := domain.SendPrivateTextRequest{
|
|
SenderUserID: 1001, RecipientUserID: 1002, RandomID: 501,
|
|
Message: "immutable", Date: 1700000000,
|
|
}
|
|
first, err := messages.SendPrivateText(ctx, base)
|
|
if err != nil {
|
|
t.Fatalf("first send: %v", err)
|
|
}
|
|
replay := base
|
|
replay.Date++
|
|
replay.OriginSessionID = 77
|
|
replay.RecipientBlocked = true
|
|
duplicate, err := messages.SendPrivateText(ctx, replay)
|
|
if err != nil {
|
|
t.Fatalf("exact replay: %v", err)
|
|
}
|
|
if !duplicate.Duplicate || duplicate.SenderMessage.ID != first.SenderMessage.ID || duplicate.RecipientMessage.ID != first.RecipientMessage.ID {
|
|
t.Fatalf("exact replay = %+v, want original delivered boxes", duplicate)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
mutate func(*domain.SendPrivateTextRequest)
|
|
}{
|
|
{name: "peer", mutate: func(req *domain.SendPrivateTextRequest) { req.RecipientUserID = 1003 }},
|
|
{name: "body", mutate: func(req *domain.SendPrivateTextRequest) { req.Message = "changed" }},
|
|
{name: "media", mutate: func(req *domain.SendPrivateTextRequest) {
|
|
req.Media = &domain.MessageMedia{
|
|
Kind: domain.MessageMediaKindContact,
|
|
Contact: &domain.MessageContact{
|
|
PhoneNumber: "+10000000000",
|
|
FirstName: "Changed",
|
|
},
|
|
}
|
|
}},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
req := base
|
|
tc.mutate(&req)
|
|
if _, err := messages.SendPrivateText(ctx, req); !errors.Is(err, domain.ErrMessageRandomIDDuplicate) {
|
|
t.Fatalf("conflicting replay err = %v, want ErrMessageRandomIDDuplicate", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMessageStorePrivateRandomIDSelfAndBlockedReplay(t *testing.T) {
|
|
ctx := context.Background()
|
|
messages := NewMessageStore()
|
|
selfReq := domain.SendPrivateTextRequest{
|
|
SenderUserID: 2001, RecipientUserID: 2001, RandomID: 601,
|
|
Message: "saved note", Date: 1700000100,
|
|
}
|
|
self, err := messages.SendPrivateText(ctx, selfReq)
|
|
if err != nil {
|
|
t.Fatalf("self first: %v", err)
|
|
}
|
|
selfReq.Date++
|
|
selfReplay, err := messages.SendPrivateText(ctx, selfReq)
|
|
if err != nil {
|
|
t.Fatalf("self replay: %v", err)
|
|
}
|
|
if !selfReplay.Duplicate || selfReplay.SenderMessage.ID != self.SenderMessage.ID || selfReplay.RecipientMessage.ID != self.SenderMessage.ID {
|
|
t.Fatalf("self replay = %+v, want original single box", selfReplay)
|
|
}
|
|
|
|
blockedReq := domain.SendPrivateTextRequest{
|
|
SenderUserID: 2002, RecipientUserID: 2003, RandomID: 602,
|
|
Message: "blocked", Date: 1700000110, RecipientBlocked: true,
|
|
}
|
|
blocked, err := messages.SendPrivateText(ctx, blockedReq)
|
|
if err != nil {
|
|
t.Fatalf("blocked first: %v", err)
|
|
}
|
|
if blocked.RecipientMessage.ID != 0 {
|
|
t.Fatalf("blocked recipient = %+v, want empty", blocked.RecipientMessage)
|
|
}
|
|
blockedReq.Date++
|
|
blockedReq.RecipientBlocked = false
|
|
blockedReplay, err := messages.SendPrivateText(ctx, blockedReq)
|
|
if err != nil {
|
|
t.Fatalf("blocked replay: %v", err)
|
|
}
|
|
if !blockedReplay.Duplicate || blockedReplay.SenderMessage.ID != blocked.SenderMessage.ID || blockedReplay.RecipientMessage.ID != 0 {
|
|
t.Fatalf("blocked replay = %+v, want original sender-only result", blockedReplay)
|
|
}
|
|
}
|
|
|
|
func TestMessageStorePrivateRandomIDReplayUsesCurrentSnapshotAndDurableDeleteMemory(t *testing.T) {
|
|
ctx := context.Background()
|
|
messages := NewMessageStore()
|
|
req := domain.SendPrivateTextRequest{
|
|
SenderUserID: 3001, RecipientUserID: 3002, RandomID: 701,
|
|
Message: "original", Date: 1700000200,
|
|
}
|
|
first, err := messages.SendPrivateText(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("first send: %v", err)
|
|
}
|
|
edited, err := messages.EditMessage(ctx, domain.EditMessageRequest{
|
|
OwnerUserID: req.SenderUserID,
|
|
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: req.RecipientUserID},
|
|
ID: first.SenderMessage.ID,
|
|
Message: "edited projection",
|
|
EditDate: 1700000201,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("edit message: %v", err)
|
|
}
|
|
senderPtsBeforeReplay := messages.nextPts[req.SenderUserID]
|
|
recipientPtsBeforeReplay := messages.nextPts[req.RecipientUserID]
|
|
replay, err := messages.SendPrivateText(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("replay after edit: %v", err)
|
|
}
|
|
if replay.SenderMessage.ID != first.SenderMessage.ID || replay.SenderMessage.Pts != edited.Self().Message.Pts || replay.SenderMessage.Body != "edited projection" {
|
|
t.Fatalf("replay after edit = %+v, want current visible snapshot", replay.SenderMessage)
|
|
}
|
|
if replay.SenderEvent.Pts != first.SenderEvent.Pts || replay.ReplayDeleteEvent != nil {
|
|
t.Fatalf("replay after edit event = %+v delete=%+v, want original send pts and no delete", replay.SenderEvent, replay.ReplayDeleteEvent)
|
|
}
|
|
if messages.nextPts[req.SenderUserID] != senderPtsBeforeReplay || messages.nextPts[req.RecipientUserID] != recipientPtsBeforeReplay {
|
|
t.Fatalf("edit replay advanced pts sender/recipient = %d/%d, want %d/%d", messages.nextPts[req.SenderUserID], messages.nextPts[req.RecipientUserID], senderPtsBeforeReplay, recipientPtsBeforeReplay)
|
|
}
|
|
deleted, err := messages.DeleteMessages(ctx, domain.DeleteMessagesRequest{
|
|
OwnerUserID: req.SenderUserID,
|
|
IDs: []int{first.SenderMessage.ID},
|
|
Revoke: true,
|
|
Date: 1700000202,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("delete message: %v", err)
|
|
}
|
|
senderPtsBeforeReplay = messages.nextPts[req.SenderUserID]
|
|
recipientPtsBeforeReplay = messages.nextPts[req.RecipientUserID]
|
|
replay, err = messages.SendPrivateText(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("replay after delete: %v", err)
|
|
}
|
|
if replay.SenderMessage.ID != first.SenderMessage.ID || replay.SenderMessage.Pts != first.SenderMessage.Pts || replay.SenderMessage.Body != "original" {
|
|
t.Fatalf("replay after delete = %+v, want immutable first snapshot", replay.SenderMessage)
|
|
}
|
|
if replay.ReplayDeleteEvent == nil || replay.ReplayDeleteEvent.Pts != deleted.Self().Event.Pts ||
|
|
len(replay.ReplayDeleteEvent.MessageIDs) != 1 || replay.ReplayDeleteEvent.MessageIDs[0] != first.SenderMessage.ID {
|
|
t.Fatalf("replay delete event = %+v, want durable delete %+v", replay.ReplayDeleteEvent, deleted.Self().Event)
|
|
}
|
|
if messages.nextPts[req.SenderUserID] != senderPtsBeforeReplay || messages.nextPts[req.RecipientUserID] != recipientPtsBeforeReplay {
|
|
t.Fatalf("delete replay advanced pts sender/recipient = %d/%d, want %d/%d", messages.nextPts[req.SenderUserID], messages.nextPts[req.RecipientUserID], senderPtsBeforeReplay, recipientPtsBeforeReplay)
|
|
}
|
|
}
|