Source file src/net/main_test.go

     1  // Copyright 2015 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  	"flag"
     9  	"fmt"
    10  	"net/internal/socktest"
    11  	"os"
    12  	"runtime"
    13  	"slices"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  var (
    21  	sw socktest.Switch
    22  
    23  	// uninstallTestHooks runs just before a run of benchmarks.
    24  	testHookUninstaller sync.Once
    25  )
    26  
    27  var (
    28  	testTCPBig = flag.Bool("tcpbig", false, "whether to test massive size of data per read or write call on TCP connection")
    29  
    30  	testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
    31  
    32  	// If external IPv4 connectivity exists, we can try dialing
    33  	// non-node/interface local scope IPv4 addresses.
    34  	// On Windows, Lookup APIs may not return IPv4-related
    35  	// resource records when a node has no external IPv4
    36  	// connectivity.
    37  	testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists")
    38  
    39  	// If external IPv6 connectivity exists, we can try dialing
    40  	// non-node/interface local scope IPv6 addresses.
    41  	// On Windows, Lookup APIs may not return IPv6-related
    42  	// resource records when a node has no external IPv6
    43  	// connectivity.
    44  	testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists")
    45  )
    46  
    47  func TestMain(m *testing.M) {
    48  	setupTestData()
    49  	installTestHooks()
    50  
    51  	st := m.Run()
    52  
    53  	testHookUninstaller.Do(uninstallTestHooks)
    54  	if testing.Verbose() {
    55  		printRunningGoroutines()
    56  		printInflightSockets()
    57  		printSocketStats()
    58  	}
    59  	forceCloseSockets()
    60  	os.Exit(st)
    61  }
    62  
    63  // mustSetDeadline calls the bound method m to set a deadline on a Conn.
    64  // If the call fails, mustSetDeadline skips t if the current GOOS is believed
    65  // not to support deadlines, or fails the test otherwise.
    66  func mustSetDeadline(t testing.TB, m func(time.Time) error, d time.Duration) {
    67  	err := m(time.Now().Add(d))
    68  	if err != nil {
    69  		t.Helper()
    70  		if runtime.GOOS == "plan9" {
    71  			t.Skipf("skipping: %s does not support deadlines", runtime.GOOS)
    72  		}
    73  		t.Fatal(err)
    74  	}
    75  }
    76  
    77  type ipv6LinkLocalUnicastTest struct {
    78  	network, address string
    79  	nameLookup       bool
    80  }
    81  
    82  var (
    83  	ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest
    84  	ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest
    85  )
    86  
    87  func setupTestData() {
    88  	if supportsIPv4() {
    89  		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
    90  			{"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
    91  			{"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
    92  		}...)
    93  		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
    94  			{"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
    95  			{"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
    96  		}...)
    97  		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
    98  			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
    99  			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
   100  		}...)
   101  	}
   102  
   103  	if supportsIPv6() {
   104  		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil})
   105  		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil})
   106  		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
   107  
   108  		// Issue 20911: don't return IPv4 addresses for
   109  		// Resolve*Addr calls of the IPv6 unspecified address.
   110  		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp", "[::]:4", &TCPAddr{IP: IPv6unspecified, Port: 4}, nil})
   111  		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp", "[::]:4", &UDPAddr{IP: IPv6unspecified, Port: 4}, nil})
   112  		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip", "::", &IPAddr{IP: IPv6unspecified}, nil})
   113  	}
   114  
   115  	ifi := loopbackInterface()
   116  	if ifi != nil {
   117  		index := fmt.Sprintf("%v", ifi.Index)
   118  		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
   119  			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
   120  			{"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
   121  		}...)
   122  		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
   123  			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil},
   124  			{"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
   125  		}...)
   126  		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
   127  			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneCache.name(ifi.Index)}, nil},
   128  			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
   129  		}...)
   130  	}
   131  
   132  	addr := ipv6LinkLocalUnicastAddr(ifi)
   133  	if addr != "" {
   134  		if runtime.GOOS != "dragonfly" {
   135  			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
   136  				{"tcp", "[" + addr + "%" + ifi.Name + "]:0", false},
   137  			}...)
   138  			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
   139  				{"udp", "[" + addr + "%" + ifi.Name + "]:0", false},
   140  			}...)
   141  		}
   142  		ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
   143  			{"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false},
   144  		}...)
   145  		ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
   146  			{"udp6", "[" + addr + "%" + ifi.Name + "]:0", false},
   147  		}...)
   148  		switch runtime.GOOS {
   149  		case "darwin", "ios", "dragonfly", "freebsd", "openbsd", "netbsd":
   150  			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
   151  				{"tcp", "[localhost%" + ifi.Name + "]:0", true},
   152  				{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
   153  			}...)
   154  			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
   155  				{"udp", "[localhost%" + ifi.Name + "]:0", true},
   156  				{"udp6", "[localhost%" + ifi.Name + "]:0", true},
   157  			}...)
   158  		case "linux":
   159  			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
   160  				{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
   161  				{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
   162  			}...)
   163  			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
   164  				{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
   165  				{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
   166  			}...)
   167  		}
   168  	}
   169  }
   170  
   171  func printRunningGoroutines() {
   172  	gss := runningGoroutines()
   173  	if len(gss) == 0 {
   174  		return
   175  	}
   176  	fmt.Fprintf(os.Stderr, "Running goroutines:\n")
   177  	for _, gs := range gss {
   178  		fmt.Fprintf(os.Stderr, "%v\n", gs)
   179  	}
   180  	fmt.Fprintf(os.Stderr, "\n")
   181  }
   182  
   183  // runningGoroutines returns a list of remaining goroutines.
   184  func runningGoroutines() []string {
   185  	var gss []string
   186  	b := make([]byte, 2<<20)
   187  	b = b[:runtime.Stack(b, true)]
   188  	for _, s := range strings.Split(string(b), "\n\n") {
   189  		_, stack, _ := strings.Cut(s, "\n")
   190  		stack = strings.TrimSpace(stack)
   191  		if !strings.Contains(stack, "created by net") {
   192  			continue
   193  		}
   194  		gss = append(gss, stack)
   195  	}
   196  	slices.Sort(gss)
   197  	return gss
   198  }
   199  
   200  func printInflightSockets() {
   201  	sos := sw.Sockets()
   202  	if len(sos) == 0 {
   203  		return
   204  	}
   205  	fmt.Fprintf(os.Stderr, "Inflight sockets:\n")
   206  	for s, so := range sos {
   207  		fmt.Fprintf(os.Stderr, "%v: %v\n", s, so)
   208  	}
   209  	fmt.Fprintf(os.Stderr, "\n")
   210  }
   211  
   212  func printSocketStats() {
   213  	sts := sw.Stats()
   214  	if len(sts) == 0 {
   215  		return
   216  	}
   217  	fmt.Fprintf(os.Stderr, "Socket statistical information:\n")
   218  	for _, st := range sts {
   219  		fmt.Fprintf(os.Stderr, "%v\n", st)
   220  	}
   221  	fmt.Fprintf(os.Stderr, "\n")
   222  }
   223  

View as plain text