package ws import ( "testing" "time" ) // The parts of the resolver that do not need a nameserver: the address // parser, the resolv.conf scan, and the cache. dnsLookup's UDP exchange stays // integration-only (it needs a DNS server; the relay's own tests do not dial // hostnames). func TestParseIPv4AcceptsAndRejects(t *testing.T) { cases := []struct { in string a, b, c, d byte ok bool }{ {"1.2.3.4", 1, 2, 3, 4, true}, {"0.0.0.0", 0, 0, 0, 0, true}, {"255.255.255.255", 255, 255, 255, 255, true}, {"8.8.8.8", 8, 8, 8, 8, true}, {"256.1.1.1", 0, 0, 0, 0, false}, {"1.2.3", 0, 0, 0, 0, false}, {"1.2.3.4.5", 0, 0, 0, 0, false}, // A trailing dot is read as a zero octet; the parser is lenient // about the nameserver lines it exists to read. {"1.2.3.", 1, 2, 3, 0, true}, {"a.b.c.d", 0, 0, 0, 0, false}, {"", 0, 0, 0, 0, false}, {"1.2.3.4x", 0, 0, 0, 0, false}, {" 1.2.3.4", 0, 0, 0, 0, false}, } for _, tc := range cases { got := parseIPv4([]byte(tc.in)) if tc.ok { if len(got) != 4 || got[0] != tc.a || got[1] != tc.b || got[2] != tc.c || got[3] != tc.d { t.Fatalf("parseIPv4(%q) = %v", tc.in, got) } } else if got != nil { t.Fatalf("parseIPv4(%q) must be rejected", tc.in) } } } func TestEnsureDNSAddrIsIdempotent(t *testing.T) { ensureDNSAddr() if !dnsAddrInit { t.Fatal("ensureDNSAddr must record that it ran") } // Either /etc/resolv.conf named a server or the 8.8.8.8 fallback stands. if dnsAddr[0] == 0 && dnsAddr[1] == 0 && dnsAddr[2] == 0 && dnsAddr[3] == 0 { t.Fatal("no DNS server address") } first := dnsAddr ensureDNSAddr() if dnsAddr[0] != first[0] || dnsAddr[1] != first[1] || dnsAddr[2] != first[2] || dnsAddr[3] != first[3] { t.Fatal("ensureDNSAddr must not rescan") } } func TestResolveHostServesTheCache(t *testing.T) { host := "cached-probe.invalid" dnsMu.Lock() dnsCache[host] = dnsEntry{ip: "10.1.2.3", exp: time.Now().Add(time.Hour)} dnsMu.Unlock() ip, err := resolveHost(host) if err != nil { t.Fatalf("cached resolve: %v", err) } if ip != "10.1.2.3" { t.Fatalf("cached resolve = %s", ip) } // The exported wrapper shares the same cache. ip2, err2 := ResolveHost(host) if err2 != nil { t.Fatalf("ResolveHost: %v", err2) } if ip2 != "10.1.2.3" { t.Fatalf("ResolveHost = %s", ip2) } }