165 lines
7.7 KiB
Go
165 lines
7.7 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"telesrv/internal/domain"
|
|
"telesrv/internal/store"
|
|
)
|
|
|
|
func peerIdentityVersionKey(peer domain.Peer) store.ReadModelKey {
|
|
return store.ReadModelKey{Model: peerIdentityReadModel, PeerType: peer.Type, PeerID: peer.ID}
|
|
}
|
|
|
|
func TestPeerUsernameIdentityCacheVersionsPositiveAndNegativeResults(t *testing.T) {
|
|
positive := domain.Peer{Type: domain.PeerTypeUser, ID: 11}
|
|
negative := domain.Peer{Type: domain.PeerTypeChannel, ID: 22}
|
|
versions := &fakeRPCReadModelVersions{hashes: map[store.ReadModelKey]int64{
|
|
peerIdentityVersionKey(positive): 101,
|
|
peerIdentityVersionKey(negative): 202,
|
|
}}
|
|
registry := newFakeUsernameRegistry()
|
|
registry.byPeer[positive] = []domain.Username{{Username: "first", Active: true, CollectibleID: 1}}
|
|
r := &Router{
|
|
deps: Deps{Usernames: registry, ReadModelVersions: versions},
|
|
peerIdentityCache: newPeerIdentityCache(8),
|
|
}
|
|
|
|
first := r.usernameRegistryMap(context.Background(), []domain.Peer{positive, negative})
|
|
if registry.batchCalls != 1 || len(first[positive]) != 1 {
|
|
t.Fatalf("first load calls=%d result=%+v", registry.batchCalls, first)
|
|
}
|
|
first[positive][0].Username = "caller-mutated"
|
|
second := r.usernameRegistryMap(context.Background(), []domain.Peer{positive, negative})
|
|
if registry.batchCalls != 1 {
|
|
t.Fatalf("positive/negative cache miss: batch calls=%d, want 1", registry.batchCalls)
|
|
}
|
|
if got := second[positive][0].Username; got != "first" {
|
|
t.Fatalf("cached username aliased caller mutation: got %q", got)
|
|
}
|
|
if _, ok := second[negative]; ok {
|
|
t.Fatalf("negative peer unexpectedly projected: %+v", second[negative])
|
|
}
|
|
|
|
registry.byPeer[positive] = []domain.Username{{Username: "second", Active: true, CollectibleID: 2}}
|
|
versions.hashes[peerIdentityVersionKey(positive)] = 303
|
|
third := r.usernameRegistryMap(context.Background(), []domain.Peer{positive, negative})
|
|
if registry.batchCalls != 1 || registry.peerCalls != 1 || len(third[positive]) != 1 || third[positive][0].Username != "second" {
|
|
t.Fatalf("version advance did not reload: batch=%d peer=%d result=%+v", registry.batchCalls, registry.peerCalls, third)
|
|
}
|
|
}
|
|
|
|
func TestPeerVerificationIdentityCacheVersionsPositiveAndNegativeResults(t *testing.T) {
|
|
positive := domain.Peer{Type: domain.PeerTypeChannel, ID: 31}
|
|
negative := domain.Peer{Type: domain.PeerTypeUser, ID: 32}
|
|
versions := &fakeRPCReadModelVersions{hashes: map[store.ReadModelKey]int64{
|
|
peerIdentityVersionKey(positive): 401,
|
|
peerIdentityVersionKey(negative): 402,
|
|
}}
|
|
verifications := newFakeBotVerifications()
|
|
verifications.marks[positive] = domain.CustomVerification{Peer: positive, IconDocumentID: 9001}
|
|
r := &Router{
|
|
deps: Deps{BotVerifications: verifications, ReadModelVersions: versions},
|
|
peerIdentityCache: newPeerIdentityCache(8),
|
|
}
|
|
|
|
first := r.botVerificationMap(context.Background(), []domain.Peer{positive, negative})
|
|
if verifications.batchCalls != 1 || first[positive].IconDocumentID != 9001 {
|
|
t.Fatalf("first load calls=%d result=%+v", verifications.batchCalls, first)
|
|
}
|
|
second := r.botVerificationMap(context.Background(), []domain.Peer{positive, negative})
|
|
if verifications.batchCalls != 1 || len(second) != 1 {
|
|
t.Fatalf("positive/negative cache miss: calls=%d result=%+v", verifications.batchCalls, second)
|
|
}
|
|
|
|
delete(verifications.marks, positive)
|
|
versions.hashes[peerIdentityVersionKey(positive)] = 403
|
|
third := r.botVerificationMap(context.Background(), []domain.Peer{positive, negative})
|
|
if verifications.batchCalls != 1 || verifications.peerCalls != 1 || len(third) != 0 {
|
|
t.Fatalf("version advance did not reload removal: batch=%d peer=%d result=%+v", verifications.batchCalls, verifications.peerCalls, third)
|
|
}
|
|
}
|
|
|
|
func TestPeerIdentityCachesDoNotTurnReadErrorsIntoNegativeEntries(t *testing.T) {
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: 51}
|
|
versions := &fakeRPCReadModelVersions{hashes: map[store.ReadModelKey]int64{
|
|
peerIdentityVersionKey(peer): 501,
|
|
}}
|
|
registry := newFakeUsernameRegistry()
|
|
registry.err = errors.New("username backend unavailable")
|
|
verifications := newFakeBotVerifications()
|
|
verifications.err = errors.New("verification backend unavailable")
|
|
r := &Router{
|
|
deps: Deps{
|
|
Usernames: registry,
|
|
BotVerifications: verifications,
|
|
ReadModelVersions: versions,
|
|
},
|
|
peerIdentityCache: newPeerIdentityCache(8),
|
|
}
|
|
|
|
if got := r.usernameRegistryMap(context.Background(), []domain.Peer{peer}); len(got) != 0 {
|
|
t.Fatalf("username error result = %+v, want empty overlay", got)
|
|
}
|
|
if got := r.botVerificationMap(context.Background(), []domain.Peer{peer}); len(got) != 0 {
|
|
t.Fatalf("verification error result = %+v, want empty overlay", got)
|
|
}
|
|
registry.err = nil
|
|
registry.byPeer[peer] = []domain.Username{{Username: "recovered", Active: true, CollectibleID: 7}}
|
|
verifications.err = nil
|
|
verifications.marks[peer] = domain.CustomVerification{Peer: peer, IconDocumentID: 9007}
|
|
|
|
if got := r.usernameRegistryMap(context.Background(), []domain.Peer{peer}); len(got[peer]) != 1 || got[peer][0].Username != "recovered" {
|
|
t.Fatalf("username backend recovery hidden by negative cache: %+v", got)
|
|
}
|
|
if got := r.botVerificationMap(context.Background(), []domain.Peer{peer}); got[peer].IconDocumentID != 9007 {
|
|
t.Fatalf("verification backend recovery hidden by negative cache: %+v", got)
|
|
}
|
|
if registry.peerCalls != 3 || verifications.peerCalls != 3 {
|
|
t.Fatalf("backend recovery did not retry: usernames=%d verifications=%d", registry.peerCalls, verifications.peerCalls)
|
|
}
|
|
}
|
|
|
|
func TestPeerIdentityCacheCombinesFacetsAndIgnoresBaseProjectionInvalidation(t *testing.T) {
|
|
userPeer := domain.Peer{Type: domain.PeerTypeUser, ID: 61}
|
|
channelPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: 62}
|
|
peers := []domain.Peer{userPeer, channelPeer}
|
|
versions := &fakeRPCReadModelVersions{hashes: map[store.ReadModelKey]int64{
|
|
peerIdentityVersionKey(userPeer): 601,
|
|
peerIdentityVersionKey(channelPeer): 602,
|
|
}}
|
|
registry := newFakeUsernameRegistry()
|
|
registry.byPeer[userPeer] = []domain.Username{{Username: "stable", Active: true}}
|
|
verifications := newFakeBotVerifications()
|
|
verifications.marks[channelPeer] = domain.CustomVerification{Peer: channelPeer, IconDocumentID: 9062}
|
|
r := &Router{
|
|
deps: Deps{
|
|
Usernames: registry,
|
|
BotVerifications: verifications,
|
|
ReadModelVersions: versions,
|
|
},
|
|
peerIdentityCache: newPeerIdentityCache(8),
|
|
}
|
|
|
|
usernames, marks := r.peerIdentityMaps(context.Background(), peers, true, true)
|
|
if registry.batchCalls != 1 || verifications.batchCalls != 1 || usernames[userPeer][0].Username != "stable" || marks[channelPeer].IconDocumentID != 9062 {
|
|
t.Fatalf("combined load registry=%d verification=%d usernames=%+v marks=%+v", registry.batchCalls, verifications.batchCalls, usernames, marks)
|
|
}
|
|
registry.byPeer[userPeer] = []domain.Username{{Username: "must-not-leak", Active: true}}
|
|
delete(verifications.marks, channelPeer)
|
|
r.InvalidateRPCProjectionReadModelForUser(userPeer.ID)
|
|
r.InvalidateRPCProjectionReadModelForChannel(channelPeer.ID)
|
|
usernames, marks = r.peerIdentityMaps(context.Background(), peers, true, true)
|
|
if registry.batchCalls != 1 || verifications.batchCalls != 1 || usernames[userPeer][0].Username != "stable" || marks[channelPeer].IconDocumentID != 9062 {
|
|
t.Fatalf("base invalidation evicted identity registry=%d verification=%d usernames=%+v marks=%+v", registry.batchCalls, verifications.batchCalls, usernames, marks)
|
|
}
|
|
|
|
versions.hashes[peerIdentityVersionKey(userPeer)] = 603
|
|
r.InvalidatePeerIdentityReadModel(userPeer)
|
|
usernames = r.usernameRegistryMap(context.Background(), peers)
|
|
if registry.peerCalls != 1 || usernames[userPeer][0].Username != "must-not-leak" {
|
|
t.Fatalf("exact identity invalidation did not reload user: peerCalls=%d usernames=%+v", registry.peerCalls, usernames)
|
|
}
|
|
}
|