go-libp2p-peerstore/pstoreds/ds_gc_test.go

145 lines
4.0 KiB
Go

package pstoreds
import (
"testing"
"time"
"github.com/ipfs/go-datastore/query"
"github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-libp2p-peerstore/test"
)
var lookaheadQuery = query.Query{Prefix: gcLookaheadBase.String(), KeysOnly: true}
type testProbe struct {
t *testing.T
ab peerstore.AddrBook
}
func (tp *testProbe) countLookaheadEntries() (i int) {
results, err := tp.ab.(*dsAddrBook).ds.Query(lookaheadQuery)
if err != nil {
tp.t.Fatal(err)
}
defer results.Close()
for range results.Next() {
i++
}
return i
}
func (tp *testProbe) clearCache() {
for _, k := range tp.ab.(*dsAddrBook).cache.Keys() {
tp.ab.(*dsAddrBook).cache.Remove(k)
}
}
func TestGCLookahead(t *testing.T) {
opts := DefaultOpts()
// effectively disable automatic GC for this test.
opts.GCInitialDelay = 90 * time.Hour
opts.GCLookaheadInterval = 10 * time.Second
opts.GCPurgeInterval = 1 * time.Minute
factory := addressBookFactory(t, badgerStore, opts)
ab, closeFn := factory()
defer closeFn()
tp := &testProbe{t, ab}
ids := test.GeneratePeerIDs(10)
addrs := test.GenerateAddrs(100)
// lookahead is 10 seconds, so these entries will be outside the lookahead window.
ab.AddAddrs(ids[0], addrs[:10], time.Hour)
ab.AddAddrs(ids[1], addrs[10:20], time.Hour)
ab.AddAddrs(ids[2], addrs[20:30], time.Hour)
ab.(*dsAddrBook).populateLookahead()
if i := tp.countLookaheadEntries(); i != 0 {
t.Errorf("expected no GC lookahead entries, got: %v", i)
}
// change addresses of a peer to have TTL 1 second, placing them in the lookahead window.
ab.UpdateAddrs(ids[1], time.Hour, time.Second)
// Purge the cache, to exercise a different path in the lookahead cycle.
tp.clearCache()
ab.(*dsAddrBook).populateLookahead()
if i := tp.countLookaheadEntries(); i != 1 {
t.Errorf("expected 1 GC lookahead entry, got: %v", i)
}
// change addresses of another to have TTL 5 second, placing them in the lookahead window.
ab.UpdateAddrs(ids[2], time.Hour, 5*time.Second)
ab.(*dsAddrBook).populateLookahead()
if i := tp.countLookaheadEntries(); i != 2 {
t.Errorf("expected 2 GC lookahead entries, got: %v", i)
}
}
func TestGCPurging(t *testing.T) {
opts := DefaultOpts()
// effectively disable automatic GC for this test.
opts.GCInitialDelay = 90 * time.Hour
opts.GCLookaheadInterval = 20 * time.Second
opts.GCPurgeInterval = 1 * time.Minute
factory := addressBookFactory(t, badgerStore, opts)
ab, closeFn := factory()
defer closeFn()
tp := &testProbe{t, ab}
ids := test.GeneratePeerIDs(10)
addrs := test.GenerateAddrs(100)
// stagger addresses within the lookahead window, but stagger them.
ab.AddAddrs(ids[0], addrs[:10], 1*time.Second)
ab.AddAddrs(ids[1], addrs[30:40], 1*time.Second)
ab.AddAddrs(ids[2], addrs[60:70], 1*time.Second)
ab.AddAddrs(ids[0], addrs[10:20], 4*time.Second)
ab.AddAddrs(ids[1], addrs[40:50], 4*time.Second)
ab.AddAddrs(ids[0], addrs[20:30], 10*time.Second)
ab.AddAddrs(ids[1], addrs[50:60], 10*time.Second)
// this is inside the window, but it will survive the purges we do in the test.
ab.AddAddrs(ids[3], addrs[70:80], 15*time.Second)
ab.(*dsAddrBook).populateLookahead()
if i := tp.countLookaheadEntries(); i != 4 {
t.Errorf("expected 4 GC lookahead entries, got: %v", i)
}
<-time.After(2 * time.Second)
ab.(*dsAddrBook).purgeCycle()
if i := tp.countLookaheadEntries(); i != 3 {
t.Errorf("expected 3 GC lookahead entries, got: %v", i)
}
// Purge the cache, to exercise a different path in the purge cycle.
tp.clearCache()
<-time.After(5 * time.Second)
ab.(*dsAddrBook).purgeCycle()
if i := tp.countLookaheadEntries(); i != 3 {
t.Errorf("expected 3 GC lookahead entries, got: %v", i)
}
<-time.After(5 * time.Second)
ab.(*dsAddrBook).purgeCycle()
if i := tp.countLookaheadEntries(); i != 1 {
t.Errorf("expected 1 GC lookahead entries, got: %v", i)
}
if i := len(ab.PeersWithAddrs()); i != 1 {
t.Errorf("expected 1 entries in database, got: %v", i)
}
if p := ab.PeersWithAddrs()[0]; p != ids[3] {
t.Errorf("expected remaining peer to be #3, got: %v, expected: %v", p, ids[3])
}
}