feat: implement traversal engine (HAN-380) (#6)
CI / test (push) Failing after 1m26s

Co-authored-by: Hansen IT Solutions <gary@hansenits.com>
Co-committed-by: Hansen IT Solutions <gary@hansenits.com>
This commit was merged in pull request #6.
This commit is contained in:
2026-06-06 03:41:14 +00:00
committed by multica-agent
parent 194bc97526
commit 39529dacbb
11 changed files with 2098 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
package traverse
import (
"fmt"
"net"
"strings"
"sync"
"testing"
"github.com/miekg/dns"
)
func TestNewInfoCache(t *testing.T) {
c := NewInfoCache(nil)
if c.parent != nil {
t.Error("root cache should have nil parent")
}
if c.NSCount() != 0 {
t.Errorf("NSCount = %d, want 0", c.NSCount())
}
if c.GlueCount() != 0 {
t.Errorf("GlueCount = %d, want 0", c.GlueCount())
}
}
func TestInfoCacheStoreAndLookupNS(t *testing.T) {
c := NewInfoCache(nil)
c.StoreNS("com.", []string{"a.gtld-servers.net.", "b.gtld-servers.net."})
if c.NSCount() != 1 {
t.Errorf("NSCount = %d, want 1", c.NSCount())
}
names := c.LookupNS("com.")
if len(names) != 2 {
t.Fatalf("expected 2 nameservers, got %d", len(names))
}
if names[0] != "a.gtld-servers.net." {
t.Errorf("nameserver[0] = %q, want %q", names[0], "a.gtld-servers.net.")
}
}
func TestInfoCacheNSDedup(t *testing.T) {
c := NewInfoCache(nil)
c.StoreNS("com.", []string{"a.gtld-servers.net.", "a.gtld-servers.net."})
names := c.LookupNS("com.")
if len(names) != 1 {
t.Errorf("expected 1 deduped NS, got %d", len(names))
}
}
func TestInfoCacheNSCaseInsensitive(t *testing.T) {
c := NewInfoCache(nil)
c.StoreNS("COM.", []string{"A.GTLD-SERVERS.NET."})
names := c.LookupNS("com.")
if len(names) != 1 {
t.Fatalf("expected 1 NS, got %d", len(names))
}
if names[0] != "a.gtld-servers.net." {
t.Errorf("NS = %q, want %q", names[0], "a.gtld-servers.net.")
}
}
func TestInfoCacheNSLookupMiss(t *testing.T) {
c := NewInfoCache(nil)
names := c.LookupNS("org.")
if names != nil {
t.Errorf("expected nil for miss, got %v", names)
}
}
func TestInfoCacheNSStoreEmpty(t *testing.T) {
c := NewInfoCache(nil)
c.StoreNS("com.", nil)
if c.NSCount() != 0 {
t.Errorf("expected 0 after empty store, got %d", c.NSCount())
}
}
func TestInfoCacheChainedNS(t *testing.T) {
parent := NewInfoCache(nil)
parent.StoreNS("com.", []string{"a.gtld-servers.net."})
child := parent.Child()
if child.parent != parent {
t.Error("child parent should be the parent cache")
}
names := child.LookupNS("com.")
if len(names) != 1 {
t.Fatalf("expected 1 NS from parent, got %d", len(names))
}
if child.NSCount() != 0 {
t.Errorf("child NSCount = %d, want 0", child.NSCount())
}
}
func TestInfoCacheChildOverridesParent(t *testing.T) {
parent := NewInfoCache(nil)
parent.StoreNS("com.", []string{"a.gtld-servers.net."})
child := parent.Child()
child.StoreNS("com.", []string{"b.gtld-servers.net."})
names := child.LookupNS("com.")
if len(names) != 1 {
t.Fatalf("expected 1 NS, got %d", len(names))
}
if names[0] != "b.gtld-servers.net." {
t.Errorf("expected child's NS to override, got %q", names[0])
}
}
func TestInfoCacheStoreAndLookupGlue(t *testing.T) {
c := NewInfoCache(nil)
addrs := []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("5.6.7.8")}
c.StoreGlue("ns1.example.com.", addrs)
result := c.LookupGlue("ns1.example.com.")
if len(result) != 2 {
t.Fatalf("expected 2 glue addresses, got %d", len(result))
}
}
func TestInfoCacheGlueDedup(t *testing.T) {
c := NewInfoCache(nil)
ip := net.ParseIP("1.2.3.4")
c.StoreGlue("ns1.example.com.", []net.IP{ip, ip})
result := c.LookupGlue("ns1.example.com.")
if len(result) != 1 {
t.Errorf("expected 1 deduped glue, got %d", len(result))
}
}
func TestInfoCacheChainedGlue(t *testing.T) {
parent := NewInfoCache(nil)
parent.StoreGlue("ns1.example.com.", []net.IP{net.ParseIP("1.2.3.4")})
child := parent.Child()
result := child.LookupGlue("ns1.example.com.")
if len(result) != 1 {
t.Fatalf("expected 1 glue from parent, got %d", len(result))
}
if child.GlueCount() != 0 {
t.Errorf("child GlueCount = %d, want 0", child.GlueCount())
}
}
func TestInfoCacheGlueLookupMiss(t *testing.T) {
c := NewInfoCache(nil)
result := c.LookupGlue("nonexistent.example.com.")
if result != nil {
t.Errorf("expected nil for miss, got %v", result)
}
}
func TestInfoCacheConcurrentAccess(t *testing.T) {
c := NewInfoCache(nil)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
name := strings.ToLower(dns.Fqdn(fmt.Sprintf("ns%d.example.com.", i)))
c.StoreNS("example.com.", []string{name})
c.StoreGlue(name, []net.IP{net.ParseIP(fmt.Sprintf("1.2.3.%d", i%256))})
_ = c.LookupNS("example.com.")
_ = c.LookupGlue(name)
}(i)
}
wg.Wait()
}
func TestInfoCacheNilParent(t *testing.T) {
c := NewInfoCache(nil)
if c.LookupNS("com.") != nil {
t.Error("root cache should return nil for miss")
}
if c.LookupGlue("ns.example.com.") != nil {
t.Error("root cache should return nil for glue miss")
}
}
func TestNormalize(t *testing.T) {
tests := []struct {
input string
want string
}{
{"example.com", "example.com."},
{"Example.COM.", "example.com."},
{"EXAMPLE.COM", "example.com."},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
got := normalize(tt.input)
if got != tt.want {
t.Errorf("normalize(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}