github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/net/tcp_test.go (about)

     1  // Copyright 2012 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  	"io"
     9  	"reflect"
    10  	"runtime"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func BenchmarkTCP4OneShot(b *testing.B) {
    17  	benchmarkTCP(b, false, false, "127.0.0.1:0")
    18  }
    19  
    20  func BenchmarkTCP4OneShotTimeout(b *testing.B) {
    21  	benchmarkTCP(b, false, true, "127.0.0.1:0")
    22  }
    23  
    24  func BenchmarkTCP4Persistent(b *testing.B) {
    25  	benchmarkTCP(b, true, false, "127.0.0.1:0")
    26  }
    27  
    28  func BenchmarkTCP4PersistentTimeout(b *testing.B) {
    29  	benchmarkTCP(b, true, true, "127.0.0.1:0")
    30  }
    31  
    32  func BenchmarkTCP6OneShot(b *testing.B) {
    33  	if !supportsIPv6 {
    34  		b.Skip("ipv6 is not supported")
    35  	}
    36  	benchmarkTCP(b, false, false, "[::1]:0")
    37  }
    38  
    39  func BenchmarkTCP6OneShotTimeout(b *testing.B) {
    40  	if !supportsIPv6 {
    41  		b.Skip("ipv6 is not supported")
    42  	}
    43  	benchmarkTCP(b, false, true, "[::1]:0")
    44  }
    45  
    46  func BenchmarkTCP6Persistent(b *testing.B) {
    47  	if !supportsIPv6 {
    48  		b.Skip("ipv6 is not supported")
    49  	}
    50  	benchmarkTCP(b, true, false, "[::1]:0")
    51  }
    52  
    53  func BenchmarkTCP6PersistentTimeout(b *testing.B) {
    54  	if !supportsIPv6 {
    55  		b.Skip("ipv6 is not supported")
    56  	}
    57  	benchmarkTCP(b, true, true, "[::1]:0")
    58  }
    59  
    60  func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
    61  	testHookUninstaller.Do(uninstallTestHooks)
    62  
    63  	const msgLen = 512
    64  	conns := b.N
    65  	numConcurrent := runtime.GOMAXPROCS(-1) * 2
    66  	msgs := 1
    67  	if persistent {
    68  		conns = numConcurrent
    69  		msgs = b.N / conns
    70  		if msgs == 0 {
    71  			msgs = 1
    72  		}
    73  		if conns > b.N {
    74  			conns = b.N
    75  		}
    76  	}
    77  	sendMsg := func(c Conn, buf []byte) bool {
    78  		n, err := c.Write(buf)
    79  		if n != len(buf) || err != nil {
    80  			b.Log(err)
    81  			return false
    82  		}
    83  		return true
    84  	}
    85  	recvMsg := func(c Conn, buf []byte) bool {
    86  		for read := 0; read != len(buf); {
    87  			n, err := c.Read(buf)
    88  			read += n
    89  			if err != nil {
    90  				b.Log(err)
    91  				return false
    92  			}
    93  		}
    94  		return true
    95  	}
    96  	ln, err := Listen("tcp", laddr)
    97  	if err != nil {
    98  		b.Fatal(err)
    99  	}
   100  	defer ln.Close()
   101  	serverSem := make(chan bool, numConcurrent)
   102  	// Acceptor.
   103  	go func() {
   104  		for {
   105  			c, err := ln.Accept()
   106  			if err != nil {
   107  				break
   108  			}
   109  			serverSem <- true
   110  			// Server connection.
   111  			go func(c Conn) {
   112  				defer func() {
   113  					c.Close()
   114  					<-serverSem
   115  				}()
   116  				if timeout {
   117  					c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
   118  				}
   119  				var buf [msgLen]byte
   120  				for m := 0; m < msgs; m++ {
   121  					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
   122  						break
   123  					}
   124  				}
   125  			}(c)
   126  		}
   127  	}()
   128  	clientSem := make(chan bool, numConcurrent)
   129  	for i := 0; i < conns; i++ {
   130  		clientSem <- true
   131  		// Client connection.
   132  		go func() {
   133  			defer func() {
   134  				<-clientSem
   135  			}()
   136  			c, err := Dial("tcp", ln.Addr().String())
   137  			if err != nil {
   138  				b.Log(err)
   139  				return
   140  			}
   141  			defer c.Close()
   142  			if timeout {
   143  				c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
   144  			}
   145  			var buf [msgLen]byte
   146  			for m := 0; m < msgs; m++ {
   147  				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
   148  					break
   149  				}
   150  			}
   151  		}()
   152  	}
   153  	for i := 0; i < numConcurrent; i++ {
   154  		clientSem <- true
   155  		serverSem <- true
   156  	}
   157  }
   158  
   159  func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
   160  	benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
   161  }
   162  
   163  func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
   164  	if !supportsIPv6 {
   165  		b.Skip("ipv6 is not supported")
   166  	}
   167  	benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
   168  }
   169  
   170  func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
   171  	testHookUninstaller.Do(uninstallTestHooks)
   172  
   173  	// The benchmark creates GOMAXPROCS client/server pairs.
   174  	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
   175  	// The benchmark stresses concurrent reading and writing to the same connection.
   176  	// Such pattern is used in net/http and net/rpc.
   177  
   178  	b.StopTimer()
   179  
   180  	P := runtime.GOMAXPROCS(0)
   181  	N := b.N / P
   182  	W := 1000
   183  
   184  	// Setup P client/server connections.
   185  	clients := make([]Conn, P)
   186  	servers := make([]Conn, P)
   187  	ln, err := Listen("tcp", laddr)
   188  	if err != nil {
   189  		b.Fatal(err)
   190  	}
   191  	defer ln.Close()
   192  	done := make(chan bool)
   193  	go func() {
   194  		for p := 0; p < P; p++ {
   195  			s, err := ln.Accept()
   196  			if err != nil {
   197  				b.Error(err)
   198  				return
   199  			}
   200  			servers[p] = s
   201  		}
   202  		done <- true
   203  	}()
   204  	for p := 0; p < P; p++ {
   205  		c, err := Dial("tcp", ln.Addr().String())
   206  		if err != nil {
   207  			b.Fatal(err)
   208  		}
   209  		clients[p] = c
   210  	}
   211  	<-done
   212  
   213  	b.StartTimer()
   214  
   215  	var wg sync.WaitGroup
   216  	wg.Add(4 * P)
   217  	for p := 0; p < P; p++ {
   218  		// Client writer.
   219  		go func(c Conn) {
   220  			defer wg.Done()
   221  			var buf [1]byte
   222  			for i := 0; i < N; i++ {
   223  				v := byte(i)
   224  				for w := 0; w < W; w++ {
   225  					v *= v
   226  				}
   227  				buf[0] = v
   228  				_, err := c.Write(buf[:])
   229  				if err != nil {
   230  					b.Error(err)
   231  					return
   232  				}
   233  			}
   234  		}(clients[p])
   235  
   236  		// Pipe between server reader and server writer.
   237  		pipe := make(chan byte, 128)
   238  
   239  		// Server reader.
   240  		go func(s Conn) {
   241  			defer wg.Done()
   242  			var buf [1]byte
   243  			for i := 0; i < N; i++ {
   244  				_, err := s.Read(buf[:])
   245  				if err != nil {
   246  					b.Error(err)
   247  					return
   248  				}
   249  				pipe <- buf[0]
   250  			}
   251  		}(servers[p])
   252  
   253  		// Server writer.
   254  		go func(s Conn) {
   255  			defer wg.Done()
   256  			var buf [1]byte
   257  			for i := 0; i < N; i++ {
   258  				v := <-pipe
   259  				for w := 0; w < W; w++ {
   260  					v *= v
   261  				}
   262  				buf[0] = v
   263  				_, err := s.Write(buf[:])
   264  				if err != nil {
   265  					b.Error(err)
   266  					return
   267  				}
   268  			}
   269  			s.Close()
   270  		}(servers[p])
   271  
   272  		// Client reader.
   273  		go func(c Conn) {
   274  			defer wg.Done()
   275  			var buf [1]byte
   276  			for i := 0; i < N; i++ {
   277  				_, err := c.Read(buf[:])
   278  				if err != nil {
   279  					b.Error(err)
   280  					return
   281  				}
   282  			}
   283  			c.Close()
   284  		}(clients[p])
   285  	}
   286  	wg.Wait()
   287  }
   288  
   289  type resolveTCPAddrTest struct {
   290  	network       string
   291  	litAddrOrName string
   292  	addr          *TCPAddr
   293  	err           error
   294  }
   295  
   296  var resolveTCPAddrTests = []resolveTCPAddrTest{
   297  	{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
   298  	{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
   299  
   300  	{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
   301  	{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
   302  
   303  	{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
   304  	{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
   305  
   306  	{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
   307  	{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
   308  
   309  	{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
   310  
   311  	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
   312  }
   313  
   314  func TestResolveTCPAddr(t *testing.T) {
   315  	origTestHookLookupIP := testHookLookupIP
   316  	defer func() { testHookLookupIP = origTestHookLookupIP }()
   317  	testHookLookupIP = lookupLocalhost
   318  
   319  	for i, tt := range resolveTCPAddrTests {
   320  		addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
   321  		if err != tt.err {
   322  			t.Errorf("#%d: %v", i, err)
   323  		} else if !reflect.DeepEqual(addr, tt.addr) {
   324  			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
   325  		}
   326  		if err != nil {
   327  			continue
   328  		}
   329  		rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
   330  		if err != nil {
   331  			t.Errorf("#%d: %v", i, err)
   332  		} else if !reflect.DeepEqual(rtaddr, addr) {
   333  			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
   334  		}
   335  	}
   336  }
   337  
   338  var tcpListenerNameTests = []struct {
   339  	net   string
   340  	laddr *TCPAddr
   341  }{
   342  	{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
   343  	{"tcp4", &TCPAddr{}},
   344  	{"tcp4", nil},
   345  }
   346  
   347  func TestTCPListenerName(t *testing.T) {
   348  	if testing.Short() || !*testExternal {
   349  		t.Skip("avoid external network")
   350  	}
   351  
   352  	for _, tt := range tcpListenerNameTests {
   353  		ln, err := ListenTCP(tt.net, tt.laddr)
   354  		if err != nil {
   355  			t.Fatal(err)
   356  		}
   357  		defer ln.Close()
   358  		la := ln.Addr()
   359  		if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
   360  			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
   361  		}
   362  	}
   363  }
   364  
   365  func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
   366  	if testing.Short() || !*testExternal {
   367  		t.Skip("avoid external network")
   368  	}
   369  	if !supportsIPv6 {
   370  		t.Skip("IPv6 is not supported")
   371  	}
   372  
   373  	for i, tt := range ipv6LinkLocalUnicastTCPTests {
   374  		ln, err := Listen(tt.network, tt.address)
   375  		if err != nil {
   376  			// It might return "LookupHost returned no
   377  			// suitable address" error on some platforms.
   378  			t.Log(err)
   379  			continue
   380  		}
   381  		ls, err := (&streamListener{Listener: ln}).newLocalServer()
   382  		if err != nil {
   383  			t.Fatal(err)
   384  		}
   385  		defer ls.teardown()
   386  		ch := make(chan error, 1)
   387  		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
   388  		if err := ls.buildup(handler); err != nil {
   389  			t.Fatal(err)
   390  		}
   391  		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   392  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   393  		}
   394  
   395  		c, err := Dial(tt.network, ls.Listener.Addr().String())
   396  		if err != nil {
   397  			t.Fatal(err)
   398  		}
   399  		defer c.Close()
   400  		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   401  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   402  		}
   403  		if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
   404  			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
   405  		}
   406  
   407  		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
   408  			t.Fatal(err)
   409  		}
   410  		b := make([]byte, 32)
   411  		if _, err := c.Read(b); err != nil {
   412  			t.Fatal(err)
   413  		}
   414  
   415  		for err := range ch {
   416  			t.Errorf("#%d: %v", i, err)
   417  		}
   418  	}
   419  }
   420  
   421  func TestTCPConcurrentAccept(t *testing.T) {
   422  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   423  	ln, err := Listen("tcp", "127.0.0.1:0")
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  	const N = 10
   428  	var wg sync.WaitGroup
   429  	wg.Add(N)
   430  	for i := 0; i < N; i++ {
   431  		go func() {
   432  			for {
   433  				c, err := ln.Accept()
   434  				if err != nil {
   435  					break
   436  				}
   437  				c.Close()
   438  			}
   439  			wg.Done()
   440  		}()
   441  	}
   442  	attempts := 10 * N
   443  	fails := 0
   444  	d := &Dialer{Timeout: 200 * time.Millisecond}
   445  	for i := 0; i < attempts; i++ {
   446  		c, err := d.Dial("tcp", ln.Addr().String())
   447  		if err != nil {
   448  			fails++
   449  		} else {
   450  			c.Close()
   451  		}
   452  	}
   453  	ln.Close()
   454  	wg.Wait()
   455  	if fails > attempts/9 { // see issues 7400 and 7541
   456  		t.Fatalf("too many Dial failed: %v", fails)
   457  	}
   458  	if fails > 0 {
   459  		t.Logf("# of failed Dials: %v", fails)
   460  	}
   461  }
   462  
   463  func TestTCPReadWriteAllocs(t *testing.T) {
   464  	switch runtime.GOOS {
   465  	case "nacl", "windows":
   466  		// NaCl needs to allocate pseudo file descriptor
   467  		// stuff. See syscall/fd_nacl.go.
   468  		// Windows uses closures and channels for IO
   469  		// completion port-based netpoll. See fd_windows.go.
   470  		t.Skipf("not supported on %s", runtime.GOOS)
   471  	}
   472  
   473  	ln, err := Listen("tcp", "127.0.0.1:0")
   474  	if err != nil {
   475  		t.Fatal(err)
   476  	}
   477  	defer ln.Close()
   478  	var server Conn
   479  	errc := make(chan error)
   480  	go func() {
   481  		var err error
   482  		server, err = ln.Accept()
   483  		errc <- err
   484  	}()
   485  	client, err := Dial("tcp", ln.Addr().String())
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	defer client.Close()
   490  	if err := <-errc; err != nil {
   491  		t.Fatal(err)
   492  	}
   493  	defer server.Close()
   494  	var buf [128]byte
   495  	allocs := testing.AllocsPerRun(1000, func() {
   496  		_, err := server.Write(buf[:])
   497  		if err != nil {
   498  			t.Fatal(err)
   499  		}
   500  		_, err = io.ReadFull(client, buf[:])
   501  		if err != nil {
   502  			t.Fatal(err)
   503  		}
   504  	})
   505  	if allocs > 0 {
   506  		t.Fatalf("got %v; want 0", allocs)
   507  	}
   508  }
   509  
   510  func TestTCPStress(t *testing.T) {
   511  	const conns = 2
   512  	const msgLen = 512
   513  	msgs := int(1e4)
   514  	if testing.Short() {
   515  		msgs = 1e2
   516  	}
   517  
   518  	sendMsg := func(c Conn, buf []byte) bool {
   519  		n, err := c.Write(buf)
   520  		if n != len(buf) || err != nil {
   521  			t.Log(err)
   522  			return false
   523  		}
   524  		return true
   525  	}
   526  	recvMsg := func(c Conn, buf []byte) bool {
   527  		for read := 0; read != len(buf); {
   528  			n, err := c.Read(buf)
   529  			read += n
   530  			if err != nil {
   531  				t.Log(err)
   532  				return false
   533  			}
   534  		}
   535  		return true
   536  	}
   537  
   538  	ln, err := Listen("tcp", "127.0.0.1:0")
   539  	if err != nil {
   540  		t.Fatal(err)
   541  	}
   542  	defer ln.Close()
   543  	// Acceptor.
   544  	go func() {
   545  		for {
   546  			c, err := ln.Accept()
   547  			if err != nil {
   548  				break
   549  			}
   550  			// Server connection.
   551  			go func(c Conn) {
   552  				defer c.Close()
   553  				var buf [msgLen]byte
   554  				for m := 0; m < msgs; m++ {
   555  					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
   556  						break
   557  					}
   558  				}
   559  			}(c)
   560  		}
   561  	}()
   562  	done := make(chan bool)
   563  	for i := 0; i < conns; i++ {
   564  		// Client connection.
   565  		go func() {
   566  			defer func() {
   567  				done <- true
   568  			}()
   569  			c, err := Dial("tcp", ln.Addr().String())
   570  			if err != nil {
   571  				t.Log(err)
   572  				return
   573  			}
   574  			defer c.Close()
   575  			var buf [msgLen]byte
   576  			for m := 0; m < msgs; m++ {
   577  				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
   578  					break
   579  				}
   580  			}
   581  		}()
   582  	}
   583  	for i := 0; i < conns; i++ {
   584  		<-done
   585  	}
   586  }