// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package net import ( "flag" "fmt" "net/internal/socktest" "os" "runtime" "sort" "strings" "sync" "testing" "time" ) var ( sw socktest.Switch // uninstallTestHooks runs just before a run of benchmarks. testHookUninstaller sync.Once ) var ( testTCPBig = flag.Bool("tcpbig", false, "whether to test massive size of data per read or write call on TCP connection") testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding") // If external IPv4 connectivity exists, we can try dialing // non-node/interface local scope IPv4 addresses. // On Windows, Lookup APIs may not return IPv4-related // resource records when a node has no external IPv4 // connectivity. testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists") // If external IPv6 connectivity exists, we can try dialing // non-node/interface local scope IPv6 addresses. // On Windows, Lookup APIs may not return IPv6-related // resource records when a node has no external IPv6 // connectivity. testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists") ) func TestMain(m *testing.M) { setupTestData() installTestHooks() st := m.Run() testHookUninstaller.Do(uninstallTestHooks) if testing.Verbose() { printRunningGoroutines() printInflightSockets() printSocketStats() } forceCloseSockets() os.Exit(st) } // mustSetDeadline calls the bound method m to set a deadline on a Conn. // If the call fails, mustSetDeadline skips t if the current GOOS is believed // not to support deadlines, or fails the test otherwise. func mustSetDeadline(t testing.TB, m func(time.Time) error, d time.Duration) { err := m(time.Now().Add(d)) if err != nil { t.Helper() if runtime.GOOS == "plan9" { t.Skipf("skipping: %s does not support deadlines", runtime.GOOS) } t.Fatal(err) } } type ipv6LinkLocalUnicastTest struct { network, address string nameLookup bool } var ( ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest ) func setupTestData() { if supportsIPv4() { resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ {"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil}, {"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil}, }...) resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{ {"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil}, {"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil}, }...) resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ {"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, {"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, }...) } if supportsIPv6() { resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil}) resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil}) resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil}) // Issue 20911: don't return IPv4 addresses for // Resolve*Addr calls of the IPv6 unspecified address. resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp", "[::]:4", &TCPAddr{IP: IPv6unspecified, Port: 4}, nil}) resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp", "[::]:4", &UDPAddr{IP: IPv6unspecified, Port: 4}, nil}) resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip", "::", &IPAddr{IP: IPv6unspecified}, nil}) } ifi := loopbackInterface() if ifi != nil { index := fmt.Sprintf("%v", ifi.Index) resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ {"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil}, {"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil}, }...) resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{ {"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneCache.name(ifi.Index)}, nil}, {"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil}, }...) resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ {"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneCache.name(ifi.Index)}, nil}, {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil}, }...) } addr := ipv6LinkLocalUnicastAddr(ifi) if addr != "" { if runtime.GOOS != "dragonfly" { ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ {"tcp", "[" + addr + "%" + ifi.Name + "]:0", false}, }...) ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ {"udp", "[" + addr + "%" + ifi.Name + "]:0", false}, }...) } ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ {"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false}, }...) ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ {"udp6", "[" + addr + "%" + ifi.Name + "]:0", false}, }...) switch runtime.GOOS { case "darwin", "ios", "dragonfly", "freebsd", "openbsd", "netbsd": ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ {"tcp", "[localhost%" + ifi.Name + "]:0", true}, {"tcp6", "[localhost%" + ifi.Name + "]:0", true}, }...) ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ {"udp", "[localhost%" + ifi.Name + "]:0", true}, {"udp6", "[localhost%" + ifi.Name + "]:0", true}, }...) case "linux": ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true}, {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, }...) ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ {"udp", "[ip6-localhost%" + ifi.Name + "]:0", true}, {"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, }...) } } } func printRunningGoroutines() { gss := runningGoroutines() if len(gss) == 0 { return } fmt.Fprintf(os.Stderr, "Running goroutines:\n") for _, gs := range gss { fmt.Fprintf(os.Stderr, "%v\n", gs) } fmt.Fprintf(os.Stderr, "\n") } // runningGoroutines returns a list of remaining goroutines. func runningGoroutines() []string { var gss []string b := make([]byte, 2<<20) b = b[:runtime.Stack(b, true)] for _, s := range strings.Split(string(b), "\n\n") { _, stack, _ := strings.Cut(s, "\n") stack = strings.TrimSpace(stack) if !strings.Contains(stack, "created by net") { continue } gss = append(gss, stack) } sort.Strings(gss) return gss } func printInflightSockets() { sos := sw.Sockets() if len(sos) == 0 { return } fmt.Fprintf(os.Stderr, "Inflight sockets:\n") for s, so := range sos { fmt.Fprintf(os.Stderr, "%v: %v\n", s, so) } fmt.Fprintf(os.Stderr, "\n") } func printSocketStats() { sts := sw.Stats() if len(sts) == 0 { return } fmt.Fprintf(os.Stderr, "Socket statistical information:\n") for _, st := range sts { fmt.Fprintf(os.Stderr, "%v\n", st) } fmt.Fprintf(os.Stderr, "\n") }