github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/net/lookup_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // TODO It would be nice to use a mock DNS server, to eliminate
     6  // external dependencies.
     7  
     8  package net
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
    19  
    20  var lookupGoogleSRVTests = []struct {
    21  	service, proto, name string
    22  	cname, target        string
    23  }{
    24  	{
    25  		"xmpp-server", "tcp", "google.com",
    26  		".google.com", ".google.com",
    27  	},
    28  	{
    29  		"", "", "_xmpp-server._tcp.google.com", // non-standard back door
    30  		".google.com", ".google.com",
    31  	},
    32  }
    33  
    34  func TestLookupGoogleSRV(t *testing.T) {
    35  	if testing.Short() || !*testExternal {
    36  		t.Skip("skipping test to avoid external network")
    37  	}
    38  
    39  	for _, tt := range lookupGoogleSRVTests {
    40  		cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
    41  		if err != nil {
    42  			t.Fatal(err)
    43  		}
    44  		if len(srvs) == 0 {
    45  			t.Error("got no record")
    46  		}
    47  		if !strings.Contains(cname, tt.cname) {
    48  			t.Errorf("got %q; want %q", cname, tt.cname)
    49  		}
    50  		for _, srv := range srvs {
    51  			if !strings.Contains(srv.Target, tt.target) {
    52  				t.Errorf("got %v; want a record containing %q", srv, tt.target)
    53  			}
    54  		}
    55  	}
    56  }
    57  
    58  func TestLookupGmailMX(t *testing.T) {
    59  	if testing.Short() || !*testExternal {
    60  		t.Skip("skipping test to avoid external network")
    61  	}
    62  
    63  	mxs, err := LookupMX("gmail.com")
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	if len(mxs) == 0 {
    68  		t.Error("got no record")
    69  	}
    70  	for _, mx := range mxs {
    71  		if !strings.Contains(mx.Host, ".google.com") {
    72  			t.Errorf("got %v; want a record containing .google.com.", mx)
    73  		}
    74  	}
    75  }
    76  
    77  func TestLookupGmailNS(t *testing.T) {
    78  	if testing.Short() || !*testExternal {
    79  		t.Skip("skipping test to avoid external network")
    80  	}
    81  
    82  	nss, err := LookupNS("gmail.com")
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	if len(nss) == 0 {
    87  		t.Error("got no record")
    88  	}
    89  	for _, ns := range nss {
    90  		if !strings.Contains(ns.Host, ".google.com") {
    91  			t.Errorf("got %v; want a record containing .google.com.", ns)
    92  		}
    93  	}
    94  }
    95  
    96  func TestLookupGmailTXT(t *testing.T) {
    97  	if testing.Short() || !*testExternal {
    98  		t.Skip("skipping test to avoid external network")
    99  	}
   100  
   101  	txts, err := LookupTXT("gmail.com")
   102  	if err != nil {
   103  		t.Fatal(err)
   104  	}
   105  	if len(txts) == 0 {
   106  		t.Error("got no record")
   107  	}
   108  	for _, txt := range txts {
   109  		if !strings.Contains(txt, "spf") {
   110  			t.Errorf("got %q; want a spf record", txt)
   111  		}
   112  	}
   113  }
   114  
   115  var lookupGooglePublicDNSAddrs = []struct {
   116  	addr string
   117  	name string
   118  }{
   119  	{"8.8.8.8", ".google.com."},
   120  	{"8.8.4.4", ".google.com."},
   121  	{"2001:4860:4860::8888", ".google.com."},
   122  	{"2001:4860:4860::8844", ".google.com."},
   123  }
   124  
   125  func TestLookupGooglePublicDNSAddr(t *testing.T) {
   126  	if testing.Short() || !*testExternal {
   127  		t.Skip("skipping test to avoid external network")
   128  	}
   129  
   130  	for _, tt := range lookupGooglePublicDNSAddrs {
   131  		names, err := LookupAddr(tt.addr)
   132  		if err != nil {
   133  			t.Fatal(err)
   134  		}
   135  		if len(names) == 0 {
   136  			t.Error("got no record")
   137  		}
   138  		for _, name := range names {
   139  			if !strings.HasSuffix(name, tt.name) {
   140  				t.Errorf("got %q; want a record containing %q", name, tt.name)
   141  			}
   142  		}
   143  	}
   144  }
   145  
   146  func TestLookupIANACNAME(t *testing.T) {
   147  	if testing.Short() || !*testExternal {
   148  		t.Skip("skipping test to avoid external network")
   149  	}
   150  
   151  	cname, err := LookupCNAME("www.iana.org")
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  	if !strings.HasSuffix(cname, ".icann.org.") {
   156  		t.Errorf("got %q; want a record containing .icann.org.", cname)
   157  	}
   158  }
   159  
   160  func TestLookupGoogleHost(t *testing.T) {
   161  	if testing.Short() || !*testExternal {
   162  		t.Skip("skipping test to avoid external network")
   163  	}
   164  
   165  	addrs, err := LookupHost("google.com")
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	if len(addrs) == 0 {
   170  		t.Error("got no record")
   171  	}
   172  	for _, addr := range addrs {
   173  		if ParseIP(addr) == nil {
   174  			t.Errorf("got %q; want a literal ip address", addr)
   175  		}
   176  	}
   177  }
   178  
   179  func TestLookupGoogleIP(t *testing.T) {
   180  	if testing.Short() || !*testExternal {
   181  		t.Skip("skipping test to avoid external network")
   182  	}
   183  
   184  	ips, err := LookupIP("google.com")
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	if len(ips) == 0 {
   189  		t.Error("got no record")
   190  	}
   191  	for _, ip := range ips {
   192  		if ip.To4() == nil && ip.To16() == nil {
   193  			t.Errorf("got %v; want an ip address", ip)
   194  		}
   195  	}
   196  }
   197  
   198  var revAddrTests = []struct {
   199  	Addr      string
   200  	Reverse   string
   201  	ErrPrefix string
   202  }{
   203  	{"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
   204  	{"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
   205  	{"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
   206  	{"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
   207  	{"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
   208  	{"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
   209  	{"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
   210  	{"1.2.3", "", "unrecognized address"},
   211  	{"1.2.3.4.5", "", "unrecognized address"},
   212  	{"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
   213  	{"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
   214  }
   215  
   216  func TestReverseAddress(t *testing.T) {
   217  	for i, tt := range revAddrTests {
   218  		a, err := reverseaddr(tt.Addr)
   219  		if len(tt.ErrPrefix) > 0 && err == nil {
   220  			t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
   221  			continue
   222  		}
   223  		if len(tt.ErrPrefix) == 0 && err != nil {
   224  			t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
   225  		}
   226  		if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
   227  			t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
   228  		}
   229  		if a != tt.Reverse {
   230  			t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
   231  		}
   232  	}
   233  }
   234  
   235  var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
   236  
   237  func TestLookupIPDeadline(t *testing.T) {
   238  	if !*testDNSFlood {
   239  		t.Skip("test disabled; use -dnsflood to enable")
   240  	}
   241  
   242  	const N = 5000
   243  	const timeout = 3 * time.Second
   244  	c := make(chan error, 2*N)
   245  	for i := 0; i < N; i++ {
   246  		name := fmt.Sprintf("%d.net-test.golang.org", i)
   247  		go func() {
   248  			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
   249  			c <- err
   250  		}()
   251  		go func() {
   252  			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
   253  			c <- err
   254  		}()
   255  	}
   256  	qstats := struct {
   257  		succeeded, failed         int
   258  		timeout, temporary, other int
   259  		unknown                   int
   260  	}{}
   261  	deadline := time.After(timeout + time.Second)
   262  	for i := 0; i < 2*N; i++ {
   263  		select {
   264  		case <-deadline:
   265  			t.Fatal("deadline exceeded")
   266  		case err := <-c:
   267  			switch err := err.(type) {
   268  			case nil:
   269  				qstats.succeeded++
   270  			case Error:
   271  				qstats.failed++
   272  				if err.Timeout() {
   273  					qstats.timeout++
   274  				}
   275  				if err.Temporary() {
   276  					qstats.temporary++
   277  				}
   278  				if !err.Timeout() && !err.Temporary() {
   279  					qstats.other++
   280  				}
   281  			default:
   282  				qstats.failed++
   283  				qstats.unknown++
   284  			}
   285  		}
   286  	}
   287  
   288  	// A high volume of DNS queries for sub-domain of golang.org
   289  	// would be coordinated by authoritative or recursive server,
   290  	// or stub resolver which implements query-response rate
   291  	// limitation, so we can expect some query successes and more
   292  	// failures including timeout, temporary and other here.
   293  	// As a rule, unknown must not be shown but it might possibly
   294  	// happen due to issue 4856 for now.
   295  	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)
   296  }