157 lines
3.3 KiB
Go
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)
|
|
}
|
|
}
|