summaryrefslogtreecommitdiff
path: root/libgo/go/net/lookup_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/lookup_test.go')
-rw-r--r--libgo/go/net/lookup_test.go444
1 files changed, 358 insertions, 86 deletions
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 057e1322b99..86957b55756 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -2,18 +2,34 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO It would be nice to use a mock DNS server, to eliminate
-// external dependencies.
-
package net
import (
- "flag"
+ "bytes"
+ "fmt"
"strings"
"testing"
+ "time"
)
-var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+ switch host {
+ case "localhost":
+ return []IPAddr{
+ {IP: IPv4(127, 0, 0, 1)},
+ {IP: IPv6loopback},
+ }, nil
+ default:
+ return fn(host)
+ }
+}
+
+// The Lookup APIs use various sources such as local database, DNS or
+// mDNS, and may use platform-dependent DNS stub resolver if possible.
+// The APIs accept any of forms for a query; host name in various
+// encodings, UTF-8 encoded net name, domain name, FQDN or absolute
+// FQDN, but the result would be one of the forms and it depends on
+// the circumstances.
var lookupGoogleSRVTests = []struct {
service, proto, name string
@@ -21,17 +37,30 @@ var lookupGoogleSRVTests = []struct {
}{
{
"xmpp-server", "tcp", "google.com",
- ".google.com", ".google.com",
+ "google.com", "google.com",
+ },
+ {
+ "xmpp-server", "tcp", "google.com.",
+ "google.com", "google.com",
+ },
+
+ // non-standard back door
+ {
+ "", "", "_xmpp-server._tcp.google.com",
+ "google.com", "google.com",
},
{
- "", "", "_xmpp-server._tcp.google.com", // non-standard back door
- ".google.com", ".google.com",
+ "", "", "_xmpp-server._tcp.google.com.",
+ "google.com", "google.com",
},
}
func TestLookupGoogleSRV(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
+ }
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
for _, tt := range lookupGoogleSRVTests {
@@ -42,90 +71,128 @@ func TestLookupGoogleSRV(t *testing.T) {
if len(srvs) == 0 {
t.Error("got no record")
}
- if !strings.Contains(cname, tt.cname) {
- t.Errorf("got %q; want %q", cname, tt.cname)
+ if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+ t.Errorf("got %s; want %s", cname, tt.cname)
}
for _, srv := range srvs {
- if !strings.Contains(srv.Target, tt.target) {
- t.Errorf("got %v; want a record containing %q", srv, tt.target)
+ if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") {
+ t.Errorf("got %v; want a record containing %s", srv, tt.target)
}
}
}
}
+var lookupGmailMXTests = []struct {
+ name, host string
+}{
+ {"gmail.com", "google.com"},
+ {"gmail.com.", "google.com"},
+}
+
func TestLookupGmailMX(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- mxs, err := LookupMX("gmail.com")
- if err != nil {
- t.Fatal(err)
- }
- if len(mxs) == 0 {
- t.Error("got no record")
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- for _, mx := range mxs {
- if !strings.Contains(mx.Host, ".google.com") {
- t.Errorf("got %v; want a record containing .google.com.", mx)
+
+ for _, tt := range lookupGmailMXTests {
+ mxs, err := LookupMX(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(mxs) == 0 {
+ t.Error("got no record")
+ }
+ for _, mx := range mxs {
+ if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") {
+ t.Errorf("got %v; want a record containing %s", mx, tt.host)
+ }
}
}
}
+var lookupGmailNSTests = []struct {
+ name, host string
+}{
+ {"gmail.com", "google.com"},
+ {"gmail.com.", "google.com"},
+}
+
func TestLookupGmailNS(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- nss, err := LookupNS("gmail.com")
- if err != nil {
- t.Fatal(err)
- }
- if len(nss) == 0 {
- t.Error("got no record")
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- for _, ns := range nss {
- if !strings.Contains(ns.Host, ".google.com") {
- t.Errorf("got %v; want a record containing .google.com.", ns)
+
+ for _, tt := range lookupGmailNSTests {
+ nss, err := LookupNS(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(nss) == 0 {
+ t.Error("got no record")
+ }
+ for _, ns := range nss {
+ if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") {
+ t.Errorf("got %v; want a record containing %s", ns, tt.host)
+ }
}
}
}
+var lookupGmailTXTTests = []struct {
+ name, txt, host string
+}{
+ {"gmail.com", "spf", "google.com"},
+ {"gmail.com.", "spf", "google.com"},
+}
+
func TestLookupGmailTXT(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- txts, err := LookupTXT("gmail.com")
- if err != nil {
- t.Fatal(err)
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- if len(txts) == 0 {
- t.Error("got no record")
- }
- for _, txt := range txts {
- if !strings.Contains(txt, "spf") {
- t.Errorf("got %q; want a spf record", txt)
+
+ for _, tt := range lookupGmailTXTTests {
+ txts, err := LookupTXT(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(txts) == 0 {
+ t.Error("got no record")
+ }
+ for _, txt := range txts {
+ if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
+ t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
+ }
}
}
}
-var lookupGooglePublicDNSAddrs = []struct {
- addr string
- name string
+var lookupGooglePublicDNSAddrTests = []struct {
+ addr, name string
}{
- {"8.8.8.8", ".google.com."},
- {"8.8.4.4", ".google.com."},
- {"2001:4860:4860::8888", ".google.com."},
- {"2001:4860:4860::8844", ".google.com."},
+ {"8.8.8.8", ".google.com"},
+ {"8.8.4.4", ".google.com"},
+ {"2001:4860:4860::8888", ".google.com"},
+ {"2001:4860:4860::8844", ".google.com"},
}
func TestLookupGooglePublicDNSAddr(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
+ }
+ if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+ t.Skip("both IPv4 and IPv6 are required")
}
- for _, tt := range lookupGooglePublicDNSAddrs {
+ for _, tt := range lookupGooglePublicDNSAddrTests {
names, err := LookupAddr(tt.addr)
if err != nil {
t.Fatal(err)
@@ -134,61 +201,97 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
t.Error("got no record")
}
for _, name := range names {
- if !strings.HasSuffix(name, tt.name) {
- t.Errorf("got %q; want a record containing %q", name, tt.name)
+ if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") {
+ t.Errorf("got %s; want a record containing %s", name, tt.name)
}
}
}
}
+var lookupIANACNAMETests = []struct {
+ name, cname string
+}{
+ {"www.iana.org", "icann.org"},
+ {"www.iana.org.", "icann.org"},
+}
+
func TestLookupIANACNAME(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- cname, err := LookupCNAME("www.iana.org")
- if err != nil {
- t.Fatal(err)
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- if !strings.HasSuffix(cname, ".icann.org.") {
- t.Errorf("got %q; want a record containing .icann.org.", cname)
+
+ for _, tt := range lookupIANACNAMETests {
+ cname, err := LookupCNAME(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+ t.Errorf("got %s; want a record containing %s", cname, tt.cname)
+ }
}
}
+var lookupGoogleHostTests = []struct {
+ name string
+}{
+ {"google.com"},
+ {"google.com."},
+}
+
func TestLookupGoogleHost(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- addrs, err := LookupHost("google.com")
- if err != nil {
- t.Fatal(err)
- }
- if len(addrs) == 0 {
- t.Error("got no record")
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- for _, addr := range addrs {
- if ParseIP(addr) == nil {
- t.Errorf("got %q; want a literal ip address", addr)
+
+ for _, tt := range lookupGoogleHostTests {
+ addrs, err := LookupHost(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(addrs) == 0 {
+ t.Error("got no record")
+ }
+ for _, addr := range addrs {
+ if ParseIP(addr) == nil {
+ t.Errorf("got %q; want a literal IP address", addr)
+ }
}
}
}
+var lookupGoogleIPTests = []struct {
+ name string
+}{
+ {"google.com"},
+ {"google.com."},
+}
+
func TestLookupGoogleIP(t *testing.T) {
if testing.Short() || !*testExternal {
- t.Skip("skipping test to avoid external network")
+ t.Skip("avoid external network")
}
-
- ips, err := LookupIP("google.com")
- if err != nil {
- t.Fatal(err)
- }
- if len(ips) == 0 {
- t.Error("got no record")
+ if !supportsIPv4 || !*testIPv4 {
+ t.Skip("IPv4 is required")
}
- for _, ip := range ips {
- if ip.To4() == nil && ip.To16() == nil {
- t.Errorf("got %v; want an ip address", ip)
+
+ for _, tt := range lookupGoogleIPTests {
+ ips, err := LookupIP(tt.name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(ips) == 0 {
+ t.Error("got no record")
+ }
+ for _, ip := range ips {
+ if ip.To4() == nil && ip.To16() == nil {
+ t.Errorf("got %v; want an IP address", ip)
+ }
}
}
}
@@ -229,3 +332,172 @@ func TestReverseAddress(t *testing.T) {
}
}
}
+
+func TestLookupIPDeadline(t *testing.T) {
+ if !*testDNSFlood {
+ t.Skip("test disabled; use -dnsflood to enable")
+ }
+
+ const N = 5000
+ const timeout = 3 * time.Second
+ c := make(chan error, 2*N)
+ for i := 0; i < N; i++ {
+ name := fmt.Sprintf("%d.net-test.golang.org", i)
+ go func() {
+ _, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
+ c <- err
+ }()
+ go func() {
+ _, err := lookupIPDeadline(name, time.Now().Add(timeout))
+ c <- err
+ }()
+ }
+ qstats := struct {
+ succeeded, failed int
+ timeout, temporary, other int
+ unknown int
+ }{}
+ deadline := time.After(timeout + time.Second)
+ for i := 0; i < 2*N; i++ {
+ select {
+ case <-deadline:
+ t.Fatal("deadline exceeded")
+ case err := <-c:
+ switch err := err.(type) {
+ case nil:
+ qstats.succeeded++
+ case Error:
+ qstats.failed++
+ if err.Timeout() {
+ qstats.timeout++
+ }
+ if err.Temporary() {
+ qstats.temporary++
+ }
+ if !err.Timeout() && !err.Temporary() {
+ qstats.other++
+ }
+ default:
+ qstats.failed++
+ qstats.unknown++
+ }
+ }
+ }
+
+ // A high volume of DNS queries for sub-domain of golang.org
+ // would be coordinated by authoritative or recursive server,
+ // or stub resolver which implements query-response rate
+ // limitation, so we can expect some query successes and more
+ // failures including timeout, temporary and other here.
+ // As a rule, unknown must not be shown but it might possibly
+ // happen due to issue 4856 for now.
+ t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
+}
+
+func TestLookupDots(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skipf("skipping external network test")
+ }
+
+ fixup := forceGoDNS()
+ defer fixup()
+ testDots(t, "go")
+
+ if forceCgoDNS() {
+ testDots(t, "cgo")
+ }
+}
+
+func testDots(t *testing.T, mode string) {
+ names, err := LookupAddr("8.8.8.8") // Google dns server
+ if err != nil {
+ t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
+ } else {
+ for _, name := range names {
+ if !strings.HasSuffix(name, ".google.com.") {
+ t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
+ break
+ }
+ }
+ }
+
+ cname, err := LookupCNAME("www.mit.edu")
+ if err != nil || !strings.HasSuffix(cname, ".") {
+ t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode)
+ }
+
+ mxs, err := LookupMX("google.com")
+ if err != nil {
+ t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
+ } else {
+ for _, mx := range mxs {
+ if !strings.HasSuffix(mx.Host, ".google.com.") {
+ t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
+ break
+ }
+ }
+ }
+
+ nss, err := LookupNS("google.com")
+ if err != nil {
+ t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
+ } else {
+ for _, ns := range nss {
+ if !strings.HasSuffix(ns.Host, ".google.com.") {
+ t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
+ break
+ }
+ }
+ }
+
+ cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+ if err != nil {
+ t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
+ } else {
+ if !strings.HasSuffix(cname, ".google.com.") {
+ t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
+ }
+ for _, srv := range srvs {
+ if !strings.HasSuffix(srv.Target, ".google.com.") {
+ t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode)
+ break
+ }
+ }
+ }
+}
+
+func mxString(mxs []*MX) string {
+ var buf bytes.Buffer
+ sep := ""
+ fmt.Fprintf(&buf, "[")
+ for _, mx := range mxs {
+ fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
+ sep = " "
+ }
+ fmt.Fprintf(&buf, "]")
+ return buf.String()
+}
+
+func nsString(nss []*NS) string {
+ var buf bytes.Buffer
+ sep := ""
+ fmt.Fprintf(&buf, "[")
+ for _, ns := range nss {
+ fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
+ sep = " "
+ }
+ fmt.Fprintf(&buf, "]")
+ return buf.String()
+}
+
+func srvString(srvs []*SRV) string {
+ var buf bytes.Buffer
+ sep := ""
+ fmt.Fprintf(&buf, "[")
+ for _, srv := range srvs {
+ fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
+ sep = " "
+ }
+ fmt.Fprintf(&buf, "]")
+ return buf.String()
+}