rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/dial_test.go (about)

     1  // Copyright 2011 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  package net
     6  
     7  import (
     8  	"fmt"
     9  	"net/internal/socktest"
    10  	"reflect"
    11  	"regexp"
    12  	"runtime"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func TestSelfConnect(t *testing.T) {
    19  	if runtime.GOOS == "windows" {
    20  		// TODO(brainman): do not know why it hangs.
    21  		t.Skip("skipping known-broken test on windows")
    22  	}
    23  
    24  	// Test that Dial does not honor self-connects.
    25  	// See the comment in DialTCP.
    26  
    27  	// Find a port that would be used as a local address.
    28  	l, err := Listen("tcp", "127.0.0.1:0")
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	c, err := Dial("tcp", l.Addr().String())
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	addr := c.LocalAddr().String()
    37  	c.Close()
    38  	l.Close()
    39  
    40  	// Try to connect to that address repeatedly.
    41  	n := 100000
    42  	if testing.Short() {
    43  		n = 1000
    44  	}
    45  	switch runtime.GOOS {
    46  	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
    47  		// Non-Linux systems take a long time to figure
    48  		// out that there is nothing listening on localhost.
    49  		n = 100
    50  	}
    51  	for i := 0; i < n; i++ {
    52  		c, err := DialTimeout("tcp", addr, time.Millisecond)
    53  		if err == nil {
    54  			if c.LocalAddr().String() == addr {
    55  				t.Errorf("#%d: Dial %q self-connect", i, addr)
    56  			} else {
    57  				t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
    58  			}
    59  			c.Close()
    60  		}
    61  	}
    62  }
    63  
    64  type DialErrorTest struct {
    65  	Net     string
    66  	Raddr   string
    67  	Pattern string
    68  }
    69  
    70  var dialErrorTests = []DialErrorTest{
    71  	{
    72  		"datakit", "mh/astro/r70",
    73  		"dial datakit mh/astro/r70: unknown network datakit",
    74  	},
    75  	{
    76  		"tcp", "127.0.0.1:☺",
    77  		"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
    78  	},
    79  	{
    80  		"tcp", "no-such-name.google.com.:80",
    81  		"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
    82  	},
    83  	{
    84  		"tcp", "no-such-name.no-such-top-level-domain.:80",
    85  		"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
    86  	},
    87  	{
    88  		"tcp", "no-such-name:80",
    89  		`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
    90  	},
    91  	{
    92  		"tcp", "mh/astro/r70:http",
    93  		"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
    94  	},
    95  	{
    96  		"unix", "/etc/file-not-found",
    97  		"dial unix /etc/file-not-found: no such file or directory",
    98  	},
    99  	{
   100  		"unix", "/etc/",
   101  		"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
   102  	},
   103  	{
   104  		"unixpacket", "/etc/file-not-found",
   105  		"dial unixpacket /etc/file-not-found: no such file or directory",
   106  	},
   107  	{
   108  		"unixpacket", "/etc/",
   109  		"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
   110  	},
   111  }
   112  
   113  var duplicateErrorPattern = `dial (.*) dial (.*)`
   114  
   115  func TestDialError(t *testing.T) {
   116  	if !*runErrorTest {
   117  		t.Logf("test disabled; use -run_error_test to enable")
   118  		return
   119  	}
   120  	for i, tt := range dialErrorTests {
   121  		c, err := Dial(tt.Net, tt.Raddr)
   122  		if c != nil {
   123  			c.Close()
   124  		}
   125  		if err == nil {
   126  			t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
   127  			continue
   128  		}
   129  		s := err.Error()
   130  		match, _ := regexp.MatchString(tt.Pattern, s)
   131  		if !match {
   132  			t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
   133  		}
   134  		match, _ = regexp.MatchString(duplicateErrorPattern, s)
   135  		if match {
   136  			t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
   137  		}
   138  	}
   139  }
   140  
   141  var invalidDialAndListenArgTests = []struct {
   142  	net  string
   143  	addr string
   144  	err  error
   145  }{
   146  	{"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}},
   147  	{"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}},
   148  	{"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}},
   149  }
   150  
   151  func TestInvalidDialAndListenArgs(t *testing.T) {
   152  	for _, tt := range invalidDialAndListenArgTests {
   153  		var err error
   154  		switch tt.err.(*OpError).Op {
   155  		case "dial":
   156  			_, err = Dial(tt.net, tt.addr)
   157  		case "listen":
   158  			_, err = Listen(tt.net, tt.addr)
   159  		}
   160  		if !reflect.DeepEqual(tt.err, err) {
   161  			t.Fatalf("got %#v; expected %#v", err, tt.err)
   162  		}
   163  	}
   164  }
   165  
   166  func TestDialTimeoutFDLeak(t *testing.T) {
   167  	switch runtime.GOOS {
   168  	case "plan9":
   169  		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
   170  	}
   171  
   172  	const T = 100 * time.Millisecond
   173  
   174  	switch runtime.GOOS {
   175  	case "plan9", "windows":
   176  		origTestHookDialChannel := testHookDialChannel
   177  		testHookDialChannel = func() { time.Sleep(2 * T) }
   178  		defer func() { testHookDialChannel = origTestHookDialChannel }()
   179  		if runtime.GOOS == "plan9" {
   180  			break
   181  		}
   182  		fallthrough
   183  	default:
   184  		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
   185  			time.Sleep(2 * T)
   186  			return nil, errTimeout
   187  		})
   188  		defer sw.Set(socktest.FilterConnect, nil)
   189  	}
   190  
   191  	before := sw.Sockets()
   192  	const N = 100
   193  	var wg sync.WaitGroup
   194  	wg.Add(N)
   195  	for i := 0; i < N; i++ {
   196  		go func() {
   197  			defer wg.Done()
   198  			// This dial never starts to send any SYN
   199  			// segment because of above socket filter and
   200  			// test hook.
   201  			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
   202  			if err == nil {
   203  				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
   204  				c.Close()
   205  			}
   206  		}()
   207  	}
   208  	wg.Wait()
   209  	after := sw.Sockets()
   210  	if len(after) != len(before) {
   211  		t.Errorf("got %d; want %d", len(after), len(before))
   212  	}
   213  }
   214  
   215  func TestDialerDualStackFDLeak(t *testing.T) {
   216  	switch runtime.GOOS {
   217  	case "plan9":
   218  		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
   219  	case "windows":
   220  		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
   221  	}
   222  	if !supportsIPv4 || !supportsIPv6 {
   223  		t.Skip("ipv4 or ipv6 is not supported")
   224  	}
   225  
   226  	origTestHookLookupIP := testHookLookupIP
   227  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   228  	testHookLookupIP = lookupLocalhost
   229  	handler := func(dss *dualStackServer, ln Listener) {
   230  		for {
   231  			c, err := ln.Accept()
   232  			if err != nil {
   233  				return
   234  			}
   235  			c.Close()
   236  		}
   237  	}
   238  	dss, err := newDualStackServer([]streamListener{
   239  		{network: "tcp4", address: "127.0.0.1"},
   240  		{network: "tcp6", address: "::1"},
   241  	})
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	defer dss.teardown()
   246  	if err := dss.buildup(handler); err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	before := sw.Sockets()
   251  	const T = 100 * time.Millisecond
   252  	const N = 10
   253  	var wg sync.WaitGroup
   254  	wg.Add(N)
   255  	d := &Dialer{DualStack: true, Timeout: T}
   256  	for i := 0; i < N; i++ {
   257  		go func() {
   258  			defer wg.Done()
   259  			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
   260  			if err != nil {
   261  				t.Error(err)
   262  				return
   263  			}
   264  			c.Close()
   265  		}()
   266  	}
   267  	wg.Wait()
   268  	time.Sleep(2 * T) // wait for the dial racers to stop
   269  	after := sw.Sockets()
   270  	if len(after) != len(before) {
   271  		t.Errorf("got %d; want %d", len(after), len(before))
   272  	}
   273  }
   274  
   275  func TestDialerLocalAddr(t *testing.T) {
   276  	ch := make(chan error, 1)
   277  	handler := func(ls *localServer, ln Listener) {
   278  		c, err := ln.Accept()
   279  		if err != nil {
   280  			ch <- fmt.Errorf("Accept failed: %v", err)
   281  			return
   282  		}
   283  		defer c.Close()
   284  		ch <- nil
   285  	}
   286  	ls, err := newLocalServer("tcp")
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	defer ls.teardown()
   291  	if err := ls.buildup(handler); err != nil {
   292  		t.Fatal(err)
   293  	}
   294  
   295  	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
   296  	if err != nil {
   297  		t.Fatalf("ResolveTCPAddr failed: %v", err)
   298  	}
   299  	laddr.Port = 0
   300  	d := &Dialer{LocalAddr: laddr}
   301  	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
   302  	if err != nil {
   303  		t.Fatalf("Dial failed: %v", err)
   304  	}
   305  	defer c.Close()
   306  	c.Read(make([]byte, 1))
   307  	err = <-ch
   308  	if err != nil {
   309  		t.Error(err)
   310  	}
   311  }
   312  
   313  func TestDialerDualStack(t *testing.T) {
   314  	if !supportsIPv4 || !supportsIPv6 {
   315  		t.Skip("ipv4 or ipv6 is not supported")
   316  	}
   317  
   318  	origTestHookLookupIP := testHookLookupIP
   319  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   320  	testHookLookupIP = lookupLocalhost
   321  	handler := func(dss *dualStackServer, ln Listener) {
   322  		for {
   323  			c, err := ln.Accept()
   324  			if err != nil {
   325  				return
   326  			}
   327  			c.Close()
   328  		}
   329  	}
   330  	dss, err := newDualStackServer([]streamListener{
   331  		{network: "tcp4", address: "127.0.0.1"},
   332  		{network: "tcp6", address: "::1"},
   333  	})
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	defer dss.teardown()
   338  	if err := dss.buildup(handler); err != nil {
   339  		t.Fatal(err)
   340  	}
   341  
   342  	const T = 100 * time.Millisecond
   343  	d := &Dialer{DualStack: true, Timeout: T}
   344  	for range dss.lns {
   345  		c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
   346  		if err != nil {
   347  			t.Error(err)
   348  			continue
   349  		}
   350  		switch addr := c.LocalAddr().(*TCPAddr); {
   351  		case addr.IP.To4() != nil:
   352  			dss.teardownNetwork("tcp4")
   353  		case addr.IP.To16() != nil && addr.IP.To4() == nil:
   354  			dss.teardownNetwork("tcp6")
   355  		}
   356  		c.Close()
   357  	}
   358  	time.Sleep(2 * T) // wait for the dial racers to stop
   359  }
   360  
   361  func TestDialerKeepAlive(t *testing.T) {
   362  	handler := func(ls *localServer, ln Listener) {
   363  		for {
   364  			c, err := ln.Accept()
   365  			if err != nil {
   366  				return
   367  			}
   368  			c.Close()
   369  		}
   370  	}
   371  	ls, err := newLocalServer("tcp")
   372  	if err != nil {
   373  		t.Fatal(err)
   374  	}
   375  	defer ls.teardown()
   376  	if err := ls.buildup(handler); err != nil {
   377  		t.Fatal(err)
   378  	}
   379  	defer func() {
   380  		testHookSetKeepAlive = func() {}
   381  	}()
   382  
   383  	for _, keepAlive := range []bool{false, true} {
   384  		got := false
   385  		testHookSetKeepAlive = func() { got = true }
   386  		var d Dialer
   387  		if keepAlive {
   388  			d.KeepAlive = 30 * time.Second
   389  		}
   390  		c, err := d.Dial("tcp", ls.Listener.Addr().String())
   391  		if err != nil {
   392  			t.Fatal(err)
   393  		}
   394  		c.Close()
   395  		if got != keepAlive {
   396  			t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
   397  		}
   398  	}
   399  }