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