merged from gramsrv upstream
This commit is contained in:
parent
79c64ee916
commit
21a0856587
651 changed files with 54774 additions and 4590 deletions
147
internal/store/postgres/channel_difference_cache_test.go
Normal file
147
internal/store/postgres/channel_difference_cache_test.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
func TestChannelDifferenceBaseCacheSingleflightAndCloneIsolation(t *testing.T) {
|
||||
cache := NewChannelDifferenceBaseCache(16, 1<<20, time.Minute)
|
||||
key := channelDifferenceBaseKey{channelID: 7, requestPts: 10, capturedPts: 11, capturedTopID: 3, limit: 100}
|
||||
var loads atomic.Int32
|
||||
load := func() (channelDifferenceBase, error) {
|
||||
loads.Add(1)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return channelDifferenceBase{
|
||||
lastPts: 11,
|
||||
candidatesKnown: true,
|
||||
mentionCandidateIDs: map[int]struct{}{3: {}},
|
||||
events: []domain.ChannelUpdateEvent{{
|
||||
ChannelID: 7,
|
||||
Pts: 11,
|
||||
PtsCount: 1,
|
||||
Type: domain.ChannelUpdateNewMessage,
|
||||
MessageIDs: []int{3},
|
||||
Message: domain.ChannelMessage{
|
||||
ChannelID: 7,
|
||||
ID: 3,
|
||||
Body: "immutable",
|
||||
Entities: []domain.MessageEntity{{Offset: 1}},
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
const callers = 64
|
||||
values := make([]channelDifferenceBase, callers)
|
||||
errs := make([]error, callers)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(callers)
|
||||
for i := range callers {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
values[i], errs[i] = cache.getOrLoad(context.Background(), key, load)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
for i, err := range errs {
|
||||
if err != nil {
|
||||
t.Fatalf("caller %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
if loads.Load() != 1 {
|
||||
t.Fatalf("loads = %d, want 1", loads.Load())
|
||||
}
|
||||
values[0].events[0].MessageIDs[0] = 99
|
||||
values[0].events[0].Message.Entities[0].Offset = 99
|
||||
delete(values[0].mentionCandidateIDs, 3)
|
||||
got, err := cache.getOrLoad(context.Background(), key, load)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.events[0].MessageIDs[0] != 3 || got.events[0].Message.Entities[0].Offset != 1 {
|
||||
t.Fatalf("cached value was aliased: %+v", got.events[0])
|
||||
}
|
||||
if _, ok := got.mentionCandidateIDs[3]; !ok {
|
||||
t.Fatalf("cached mention candidates were aliased: %+v", got.mentionCandidateIDs)
|
||||
}
|
||||
snapshot := cache.Snapshot()
|
||||
if snapshot.Entries != 1 || snapshot.Loads != 1 || snapshot.Hits == 0 || snapshot.Weight <= 0 {
|
||||
t.Fatalf("snapshot = %+v", snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelDifferenceBaseCacheSeparatesCutsAndInvalidatesChannel(t *testing.T) {
|
||||
cache := NewChannelDifferenceBaseCache(16, 1<<20, time.Minute)
|
||||
var loads atomic.Int32
|
||||
load := func() (channelDifferenceBase, error) {
|
||||
loads.Add(1)
|
||||
return channelDifferenceBase{lastPts: 2}, nil
|
||||
}
|
||||
keys := []channelDifferenceBaseKey{
|
||||
{channelID: 9, requestPts: 1, capturedPts: 2, capturedTopID: 1, limit: 100},
|
||||
{channelID: 9, requestPts: 1, capturedPts: 3, capturedTopID: 2, limit: 100},
|
||||
{channelID: 10, requestPts: 1, capturedPts: 2, capturedTopID: 1, limit: 100},
|
||||
}
|
||||
for _, key := range keys {
|
||||
if _, err := cache.getOrLoad(context.Background(), key, load); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if loads.Load() != 3 || cache.Snapshot().Entries != 3 {
|
||||
t.Fatalf("loads/entries = %d/%d, want 3/3", loads.Load(), cache.Snapshot().Entries)
|
||||
}
|
||||
cache.deleteChannel(9)
|
||||
if cache.Snapshot().Entries != 1 {
|
||||
t.Fatalf("entries after channel invalidation = %d, want 1", cache.Snapshot().Entries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelDifferenceBaseCacheDoesNotCacheErrors(t *testing.T) {
|
||||
cache := NewChannelDifferenceBaseCache(4, 1<<20, time.Minute)
|
||||
key := channelDifferenceBaseKey{channelID: 12, requestPts: 1, capturedPts: 2, limit: 100}
|
||||
want := errors.New("load failed")
|
||||
for range 2 {
|
||||
if _, err := cache.getOrLoad(context.Background(), key, func() (channelDifferenceBase, error) {
|
||||
return channelDifferenceBase{}, want
|
||||
}); !errors.Is(err, want) {
|
||||
t.Fatalf("err = %v, want %v", err, want)
|
||||
}
|
||||
}
|
||||
snapshot := cache.Snapshot()
|
||||
if snapshot.Entries != 0 || snapshot.Loads != 2 || snapshot.LoadErrors != 2 {
|
||||
t.Fatalf("snapshot = %+v", snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelDifferenceUnreadFlagsSkipDatabaseWithoutMentionCandidates(t *testing.T) {
|
||||
messages := []domain.ChannelMessage{{ChannelID: 12, ID: 7}}
|
||||
base := channelDifferenceBase{candidatesKnown: true, mentionCandidateIDs: map[int]struct{}{}}
|
||||
if err := populateChannelDifferenceUnreadFlags(context.Background(), nil, 99, messages, base); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if messages[0].Mentioned || messages[0].MediaUnread {
|
||||
t.Fatalf("empty candidate gate changed message flags: %+v", messages[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadModelListenerInvalidatesChannelDifferenceBase(t *testing.T) {
|
||||
cache := NewChannelDifferenceBaseCache(4, 1<<20, time.Minute)
|
||||
key := channelDifferenceBaseKey{channelID: 14, requestPts: 1, capturedPts: 2, limit: 100}
|
||||
if _, err := cache.getOrLoad(context.Background(), key, func() (channelDifferenceBase, error) {
|
||||
return channelDifferenceBase{lastPts: 2}, nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
listener := NewReadModelChangeListener("", ReadModelCacheSet{ChannelDifferences: cache}, nil)
|
||||
listener.handlePayload(`{"model":"channel_difference_base","peer_type":"channel","peer_id":14}`)
|
||||
if cache.Snapshot().Entries != 0 {
|
||||
t.Fatalf("entries after retention invalidation = %d, want 0", cache.Snapshot().Entries)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue