90 lines
2.8 KiB
Go
90 lines
2.8 KiB
Go
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
func TestChannelTopMessageCacheBatchesClonesAndInvalidates(t *testing.T) {
|
|
cache := NewChannelTopMessageCache(8)
|
|
if cache == nil {
|
|
t.Fatal("NewChannelTopMessageCache returned nil")
|
|
}
|
|
keys := []channelMessageLookupKey{{channelID: 7, id: 11}, {channelID: 7, id: 12}, {channelID: 8, id: 21}}
|
|
loads := 0
|
|
load := func(_ context.Context, missing []channelMessageLookupKey) (map[channelMessageLookupKey]domain.ChannelMessage, error) {
|
|
loads++
|
|
out := make(map[channelMessageLookupKey]domain.ChannelMessage, len(missing))
|
|
for _, key := range missing {
|
|
out[key] = domain.ChannelMessage{
|
|
ChannelID: key.channelID,
|
|
ID: key.id,
|
|
Entities: []domain.MessageEntity{{Offset: 1, Length: 2}},
|
|
Action: &domain.ChannelMessageAction{UserIDs: []int64{3}},
|
|
RichMessage: &domain.MessageRichMessage{
|
|
Blocks: []byte{4, 5},
|
|
},
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
first, err := cache.getOrLoadBatch(context.Background(), keys, load)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loads != 1 {
|
|
t.Fatalf("cold batch loads = %d, want 1", loads)
|
|
}
|
|
first[keys[0]].Entities[0].Offset = 99
|
|
first[keys[0]].Action.UserIDs[0] = 99
|
|
first[keys[0]].RichMessage.Blocks[0] = 99
|
|
|
|
second, err := cache.getOrLoadBatch(context.Background(), keys, load)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loads != 1 {
|
|
t.Fatalf("warm batch loads = %d, want 1", loads)
|
|
}
|
|
if got := second[keys[0]]; got.Entities[0].Offset != 1 || got.Action.UserIDs[0] != 3 || got.RichMessage.Blocks[0] != 4 {
|
|
t.Fatalf("cached message alias-mutated: %+v", got)
|
|
}
|
|
|
|
listener := NewReadModelChangeListener("", ReadModelCacheSet{ChannelTopMessages: cache}, nil)
|
|
cache.reactionPresence.Store(keys[0], channelTopReactionPresence{Normal: true})
|
|
listener.handlePayload(`{"model":"channel_base","owner_user_id":0,"peer_type":"channel","peer_id":7}`)
|
|
if _, ok := cache.reactionPresence.Peek(keys[0]); ok {
|
|
t.Fatal("channel_base did not invalidate top reaction presence")
|
|
}
|
|
if _, err := cache.getOrLoadBatch(context.Background(), keys, load); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loads != 2 {
|
|
t.Fatalf("channel invalidation loads = %d, want 2", loads)
|
|
}
|
|
}
|
|
|
|
func TestChannelTopMessageCacheNegativeResultIsCached(t *testing.T) {
|
|
cache := NewChannelTopMessageCache(4)
|
|
key := channelMessageLookupKey{channelID: 9, id: 1}
|
|
loads := 0
|
|
load := func(context.Context, []channelMessageLookupKey) (map[channelMessageLookupKey]domain.ChannelMessage, error) {
|
|
loads++
|
|
return map[channelMessageLookupKey]domain.ChannelMessage{}, nil
|
|
}
|
|
for i := 0; i < 2; i++ {
|
|
got, err := cache.getOrLoadBatch(context.Background(), []channelMessageLookupKey{key}, load)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got[key].ID != 0 {
|
|
t.Fatalf("negative result = %+v", got[key])
|
|
}
|
|
}
|
|
if loads != 1 {
|
|
t.Fatalf("negative cache loads = %d, want 1", loads)
|
|
}
|
|
}
|