package spindle
import (
"context"
"fmt"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/bluesky-social/indigo/atproto/syntax"
)
func strangers(n int) []syntax.DID {
var out []syntax.DID
for i := range n {
out = append(out, syntax.DID(fmt.Sprintf("did:plc:stranger%d", i)))
}
return out
}
func TestNotifyEventUnknownReposDontTakeKnownReposSlots(t *testing.T) {
e := newPushEnv(t)
release := e.w.holdManifest()
defer release(false)
held := strangers(8)
var answered atomic.Int32
var wg sync.WaitGroup
for _, did := range held {
wg.Go(func() {
e.n.s.NotifyEvent(context.Background(), e.w.knotRef(), did, faultPush("refs/heads/main", zeroSha, strings.Repeat("a", 40)))
answered.Add(1)
})
}
eventually(t, 10*time.Second, "the strangers to be held on the knot or turned away", func() bool {
return int(e.w.heldReads.Load()+answered.Load()) == len(held)
})
uri, err := e.notify(e.n.s, e.firstPush(t))
if err != nil || uri == "" {
t.Fatalf("the served repo's push answered %q, %v while strangers were held, want a pipeline", uri, err)
}
release(false)
wg.Wait()
}
func TestNotifyEventRemembersReposItDoesNotServe(t *testing.T) {
e := newPushEnv(t)
stranger := syntax.DID("did:plc:stranger")
push := faultPush("refs/heads/main", zeroSha, strings.Repeat("a", 40))
if uri, err := e.n.s.NotifyEvent(context.Background(), e.w.knotRef(), stranger, push); err != nil || uri != "" {
t.Fatalf("first notify answered %q, %v, want an empty answer", uri, err)
}
before := e.w.traffic()
if uri, err := e.n.s.NotifyEvent(context.Background(), e.w.knotRef(), stranger, push); err != nil || uri != "" {
t.Fatalf("second notify answered %q, %v, want an empty answer", uri, err)
}
if got := e.w.traffic() - before; got != 0 {
t.Fatalf("second notify of an unknown repo made %d knot requests, want 0", got)
}
}
func TestNotifyAdmissionStillRemembersAfterAFloodOfDistinctDids(t *testing.T) {
var a notifyAdmission
for i := range unknownRepoMemoryMax + 10 {
a.miss(syntax.DID(fmt.Sprintf("did:plc:flood%d", i)))
}
last := syntax.DID("did:plc:flood" + fmt.Sprint(unknownRepoMemoryMax+9))
if !a.missedRecently(last) {
t.Fatal("a miss after the memory filled was forgotten, so real misses cost a read again")
}
if a.missedRecently("did:plc:flood0") {
t.Fatal("the oldest miss outlived the cap")
}
}