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