CI / test (pull_request) Failing after 2m40s
Add core traversal engine with iterative resolution from root servers: - referral.go: Referral struct with name, type, bailiwick, addresses, state - cache.go: Chained InfoCache with parent inheritance for NS and glue records - stack.go: LIFO stack with configurable max depth enforcement - response.go: Response classifier (referral, answer, CNAME follow, NODATA, NXDOMAIN, SERVFAIL) with child referral generation and probability splitting - traverser.go: Traverser orchestrates full traversal from root to leaf, following all referral branches, handling CNAME chains, and respecting max depth limits Add IterativeQuery/IterativeQueryWithExchange to dns package (RD=false queries). 57 new tests covering all acceptance criteria: traversal from root to leaf, comprehensive branch following, max depth enforcement, probability distribution, chained cache behavior, CNAME following, NXDOMAIN/SERVFAIL handling, context cancellation, and concurrent access. Co-authored-by: multica-agent <github@multica.ai>
144 lines
3.0 KiB
Go
144 lines
3.0 KiB
Go
package traverse
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hits/ExploreDNS/internal/dns"
|
|
)
|
|
|
|
func TestNewStack(t *testing.T) {
|
|
s := NewStack(10)
|
|
if s.MaxDepth() != 10 {
|
|
t.Errorf("MaxDepth = %d, want 10", s.MaxDepth())
|
|
}
|
|
if !s.IsEmpty() {
|
|
t.Error("new stack should be empty")
|
|
}
|
|
if s.Len() != 0 {
|
|
t.Errorf("Len = %d, want 0", s.Len())
|
|
}
|
|
}
|
|
|
|
func TestNewStackDefaultDepth(t *testing.T) {
|
|
s := NewStack(0)
|
|
if s.MaxDepth() != DefaultMaxDepth {
|
|
t.Errorf("MaxDepth = %d, want %d", s.MaxDepth(), DefaultMaxDepth)
|
|
}
|
|
|
|
s = NewStack(-5)
|
|
if s.MaxDepth() != DefaultMaxDepth {
|
|
t.Errorf("MaxDepth = %d, want %d", s.MaxDepth(), DefaultMaxDepth)
|
|
}
|
|
}
|
|
|
|
func TestStackPushPop(t *testing.T) {
|
|
s := NewStack(5)
|
|
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
|
|
|
|
ok := s.Push(ref)
|
|
if !ok {
|
|
t.Error("Push should succeed")
|
|
}
|
|
if s.Len() != 1 {
|
|
t.Errorf("Len = %d, want 1", s.Len())
|
|
}
|
|
|
|
popped := s.Pop()
|
|
if popped != ref {
|
|
t.Error("popped referral should match pushed")
|
|
}
|
|
if s.Len() != 0 {
|
|
t.Errorf("Len = %d, want 0", s.Len())
|
|
}
|
|
}
|
|
|
|
func TestStackLIFO(t *testing.T) {
|
|
s := NewStack(5)
|
|
r1 := NewReferral("a.com", dns.TypeA, ".", 0, 1.0, nil)
|
|
r2 := NewReferral("b.com", dns.TypeA, ".", 1, 1.0, nil)
|
|
r3 := NewReferral("c.com", dns.TypeA, ".", 2, 1.0, nil)
|
|
|
|
s.Push(r1)
|
|
s.Push(r2)
|
|
s.Push(r3)
|
|
|
|
if popped := s.Pop(); popped != r3 {
|
|
t.Error("should pop r3 first (LIFO)")
|
|
}
|
|
if popped := s.Pop(); popped != r2 {
|
|
t.Error("should pop r2 second")
|
|
}
|
|
if popped := s.Pop(); popped != r1 {
|
|
t.Error("should pop r1 third")
|
|
}
|
|
}
|
|
|
|
func TestStackPushNil(t *testing.T) {
|
|
s := NewStack(5)
|
|
ok := s.Push(nil)
|
|
if ok {
|
|
t.Error("Push(nil) should return false")
|
|
}
|
|
if s.Len() != 0 {
|
|
t.Errorf("Len = %d, want 0", s.Len())
|
|
}
|
|
}
|
|
|
|
func TestStackMaxDepth(t *testing.T) {
|
|
s := NewStack(3)
|
|
|
|
r0 := NewReferral("a.com", dns.TypeA, ".", 0, 1.0, nil)
|
|
r1 := NewReferral("b.com", dns.TypeA, ".", 1, 1.0, nil)
|
|
r2 := NewReferral("c.com", dns.TypeA, ".", 2, 1.0, nil)
|
|
r3 := NewReferral("d.com", dns.TypeA, ".", 3, 1.0, nil)
|
|
|
|
if !s.Push(r0) {
|
|
t.Error("depth 0 should be accepted")
|
|
}
|
|
if !s.Push(r1) {
|
|
t.Error("depth 1 should be accepted")
|
|
}
|
|
if !s.Push(r2) {
|
|
t.Error("depth 2 should be accepted")
|
|
}
|
|
if s.Push(r3) {
|
|
t.Error("depth 3 should be rejected (maxDepth=3)")
|
|
}
|
|
}
|
|
|
|
func TestStackPopEmpty(t *testing.T) {
|
|
s := NewStack(5)
|
|
if popped := s.Pop(); popped != nil {
|
|
t.Error("Pop on empty stack should return nil")
|
|
}
|
|
}
|
|
|
|
func TestStackPeek(t *testing.T) {
|
|
s := NewStack(5)
|
|
if peek := s.Peek(); peek != nil {
|
|
t.Error("Peek on empty stack should return nil")
|
|
}
|
|
|
|
ref := NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil)
|
|
s.Push(ref)
|
|
|
|
if peek := s.Peek(); peek != ref {
|
|
t.Error("Peek should return top item")
|
|
}
|
|
if s.Len() != 1 {
|
|
t.Errorf("Peek should not remove item, Len = %d, want 1", s.Len())
|
|
}
|
|
}
|
|
|
|
func TestStackIsEmpty(t *testing.T) {
|
|
s := NewStack(5)
|
|
if !s.IsEmpty() {
|
|
t.Error("new stack should be empty")
|
|
}
|
|
|
|
s.Push(NewReferral("example.com", dns.TypeA, ".", 0, 1.0, nil))
|
|
if s.IsEmpty() {
|
|
t.Error("stack with item should not be empty")
|
|
}
|
|
}
|