Files
CHORUS/pkg/dht/dht_test.go
2025-09-20 23:21:35 +10:00

157 lines
3.3 KiB
Go

package dht
import (
"context"
"strings"
"testing"
"time"
libp2p "github.com/libp2p/go-libp2p"
dhtmode "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/test"
)
type harness struct {
ctx context.Context
host libp2pHost
dht *LibP2PDHT
}
type libp2pHost interface {
Close() error
}
func newHarness(t *testing.T, opts ...Option) *harness {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
host, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"))
if err != nil {
cancel()
t.Fatalf("failed to create libp2p host: %v", err)
}
options := append([]Option{WithAutoBootstrap(false)}, opts...)
d, err := NewLibP2PDHT(ctx, host, options...)
if err != nil {
host.Close()
cancel()
t.Fatalf("failed to create DHT: %v", err)
}
t.Cleanup(func() {
d.Close()
host.Close()
cancel()
})
return &harness{ctx: ctx, host: host, dht: d}
}
func TestDefaultConfig(t *testing.T) {
cfg := DefaultConfig()
if cfg.ProtocolPrefix != "/CHORUS" {
t.Fatalf("expected protocol prefix '/CHORUS', got %s", cfg.ProtocolPrefix)
}
if cfg.BootstrapTimeout != 30*time.Second {
t.Fatalf("expected bootstrap timeout 30s, got %v", cfg.BootstrapTimeout)
}
if cfg.Mode != dhtmode.ModeAuto {
t.Fatalf("expected mode auto, got %v", cfg.Mode)
}
if !cfg.AutoBootstrap {
t.Fatal("expected auto bootstrap to be enabled")
}
}
func TestWithOptionsOverridesDefaults(t *testing.T) {
h := newHarness(t,
WithProtocolPrefix("/custom"),
WithDiscoveryInterval(2*time.Minute),
WithBootstrapTimeout(45*time.Second),
WithMode(dhtmode.ModeClient),
WithAutoBootstrap(true),
)
cfg := h.dht.config
if cfg.ProtocolPrefix != "/custom" {
t.Fatalf("expected protocol prefix '/custom', got %s", cfg.ProtocolPrefix)
}
if cfg.DiscoveryInterval != 2*time.Minute {
t.Fatalf("expected discovery interval 2m, got %v", cfg.DiscoveryInterval)
}
if cfg.BootstrapTimeout != 45*time.Second {
t.Fatalf("expected bootstrap timeout 45s, got %v", cfg.BootstrapTimeout)
}
if cfg.Mode != dhtmode.ModeClient {
t.Fatalf("expected mode client, got %v", cfg.Mode)
}
if !cfg.AutoBootstrap {
t.Fatal("expected auto bootstrap to remain enabled")
}
}
func TestProvideRequiresBootstrap(t *testing.T) {
h := newHarness(t)
err := h.dht.Provide(h.ctx, "key")
if err == nil {
t.Fatal("expected Provide to fail when not bootstrapped")
}
if !strings.Contains(err.Error(), "not bootstrapped") {
t.Fatalf("expected error to indicate bootstrap requirement, got %v", err)
}
}
func TestRegisterPeer(t *testing.T) {
h := newHarness(t)
peerID := test.RandPeerIDFatal(t)
h.dht.RegisterPeer(peerID, "apollo", "platform", []string{"go"})
peers := h.dht.GetKnownPeers()
info, ok := peers[peerID]
if !ok {
t.Fatalf("expected peer to be tracked")
}
if info.Agent != "apollo" {
t.Fatalf("expected agent apollo, got %s", info.Agent)
}
if info.Role != "platform" {
t.Fatalf("expected role platform, got %s", info.Role)
}
if len(info.Capabilities) != 1 || info.Capabilities[0] != "go" {
t.Fatalf("expected capability go, got %v", info.Capabilities)
}
}
func TestGetStatsProvidesUptime(t *testing.T) {
h := newHarness(t)
stats := h.dht.GetStats()
if stats.TotalPeers != 0 {
t.Fatalf("expected zero peers, got %d", stats.TotalPeers)
}
if stats.Uptime < 0 {
t.Fatalf("expected non-negative uptime, got %v", stats.Uptime)
}
}