package net
import (
- "bytes"
"fmt"
"net/internal/socktest"
- "os"
- "os/exec"
"reflect"
"regexp"
"runtime"
- "strconv"
"sync"
"testing"
"time"
}
}
-func numTCP() (ntcp, nopen, nclose int, err error) {
- lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
- if err != nil {
- return 0, 0, 0, err
- }
- ntcp += bytes.Count(lsof, []byte("TCP"))
- for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} {
- nopen += bytes.Count(lsof, []byte(state))
- }
- for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} {
- nclose += bytes.Count(lsof, []byte(state))
+func TestDialerDualStackFDLeak(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+ case "windows":
+ t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
}
- return ntcp, nopen, nclose, nil
-}
-
-func TestDialMultiFDLeak(t *testing.T) {
- t.Skip("flaky test - golang.org/issue/8764")
-
if !supportsIPv4 || !supportsIPv6 {
- t.Skip("neither ipv4 nor ipv6 is supported")
+ t.Skip("ipv4 or ipv6 is not supported")
}
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
handler := func(dss *dualStackServer, ln Listener) {
for {
- if c, err := ln.Accept(); err != nil {
+ c, err := ln.Accept()
+ if err != nil {
return
- } else {
- // It just keeps established
- // connections like a half-dead server
- // does.
- dss.putConn(c)
}
+ c.Close()
}
}
dss, err := newDualStackServer([]streamListener{
{network: "tcp6", address: "::1"},
})
if err != nil {
- t.Fatalf("newDualStackServer failed: %v", err)
+ t.Fatal(err)
}
defer dss.teardown()
if err := dss.buildup(handler); err != nil {
- t.Fatalf("dualStackServer.buildup failed: %v", err)
- }
-
- _, before, _, err := numTCP()
- if err != nil {
- t.Skipf("skipping test; error finding or running lsof: %v", err)
+ t.Fatal(err)
}
- var wg sync.WaitGroup
- portnum, _, _ := dtoi(dss.port, 0)
- ras := addrList{
- // Losers that will fail to connect, see RFC 6890.
- &TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum},
- &TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum},
-
- // Winner candidates of this race.
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
- &TCPAddr{IP: IPv6loopback, Port: portnum},
-
- // Losers that will have established connections.
- &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
- &TCPAddr{IP: IPv6loopback, Port: portnum},
- }
- const T1 = 10 * time.Millisecond
- const T2 = 2 * T1
+ before := sw.Sockets()
+ const T = 100 * time.Millisecond
const N = 10
+ var wg sync.WaitGroup
+ wg.Add(N)
+ d := &Dialer{DualStack: true, Timeout: T}
for i := 0; i < N; i++ {
- wg.Add(1)
go func() {
defer wg.Done()
- if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil {
- c.Close()
+ c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+ if err != nil {
+ t.Error(err)
+ return
}
+ c.Close()
}()
}
wg.Wait()
- time.Sleep(T2)
-
- ntcp, after, nclose, err := numTCP()
- if err != nil {
- t.Skipf("skipping test; error finding or running lsof: %v", err)
- }
- t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose)
-
- if after != before {
- t.Fatalf("got %v open sessions; expected %v", after, before)
+ time.Sleep(2 * T) // wait for the dial racers to stop
+ after := sw.Sockets()
+ if len(after) != len(before) {
+ t.Errorf("got %d; want %d", len(after), len(before))
}
}
}
func TestDialerDualStack(t *testing.T) {
- switch runtime.GOOS {
- case "nacl":
- t.Skipf("skipping test on %q", runtime.GOOS)
- }
-
- if ips, err := LookupIP("localhost"); err != nil {
- t.Fatalf("LookupIP failed: %v", err)
- } else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 {
- t.Skip("localhost doesn't have a pair of different address family IP addresses")
+ if !supportsIPv4 || !supportsIPv6 {
+ t.Skip("ipv4 or ipv6 is not supported")
}
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
handler := func(dss *dualStackServer, ln Listener) {
for {
- if c, err := ln.Accept(); err != nil {
+ c, err := ln.Accept()
+ if err != nil {
return
- } else {
- c.Close()
}
+ c.Close()
}
}
dss, err := newDualStackServer([]streamListener{
{network: "tcp6", address: "::1"},
})
if err != nil {
- t.Fatalf("newDualStackServer failed: %v", err)
+ t.Fatal(err)
}
defer dss.teardown()
if err := dss.buildup(handler); err != nil {
- t.Fatalf("dualStackServer.buildup failed: %v", err)
+ t.Fatal(err)
}
- d := &Dialer{DualStack: true}
+ const T = 100 * time.Millisecond
+ d := &Dialer{DualStack: true, Timeout: T}
for range dss.lns {
- if c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)); err != nil {
- t.Errorf("Dial failed: %v", err)
- } else {
- if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil {
- dss.teardownNetwork("tcp4")
- } else if addr.IP.To16() != nil && addr.IP.To4() == nil {
- dss.teardownNetwork("tcp6")
- }
- c.Close()
+ c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ switch addr := c.LocalAddr().(*TCPAddr); {
+ case addr.IP.To4() != nil:
+ dss.teardownNetwork("tcp4")
+ case addr.IP.To16() != nil && addr.IP.To4() == nil:
+ dss.teardownNetwork("tcp6")
}
+ c.Close()
}
+ time.Sleep(2 * T) // wait for the dial racers to stop
}
func TestDialerKeepAlive(t *testing.T) {
package net
import (
- "fmt"
"reflect"
"testing"
)
// golang.org/x/net/icmp
type resolveIPAddrTest struct {
- net string
+ network string
litAddrOrName string
addr *IPAddr
err error
{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
}
-func init() {
- if ifi := loopbackInterface(); ifi != nil {
- index := fmt.Sprintf("%v", ifi.Index)
- resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
- {"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
- {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
- }...)
- }
- if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
- resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
- {"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
- {"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
- {"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil},
- }...)
- }
-}
-
func TestResolveIPAddr(t *testing.T) {
if !testableNetwork("ip+nopriv") {
t.Skip("ip+nopriv test")
}
- for _, tt := range resolveIPAddrTests {
- addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
+
+ for i, tt := range resolveIPAddrTests {
+ addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
if err != tt.err {
- t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err)
+ t.Errorf("#%d: %v", i, err)
} else if !reflect.DeepEqual(addr, tt.addr) {
- t.Fatalf("got %#v; expected %#v", addr, tt.addr)
+ t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+ }
+ if err != nil {
+ continue
+ }
+ rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
+ if err != nil {
+ t.Errorf("#%d: %v", i, err)
+ } else if !reflect.DeepEqual(rtaddr, addr) {
+ t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
}
}
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO It would be nice to use a mock DNS server, to eliminate
-// external dependencies.
-
package net
import (
"time"
)
+func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+ switch host {
+ case "localhost":
+ return []IPAddr{
+ {IP: IPv4(127, 0, 0, 1)},
+ {IP: IPv6loopback},
+ }, nil
+ default:
+ return fn(host)
+ }
+}
+
var lookupGoogleSRVTests = []struct {
service, proto, name string
cname, target string
)
func TestMain(m *testing.M) {
+ setupTestData()
installTestHooks()
st := m.Run()
os.Exit(st)
}
+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})
+ }
+
+ if ifi := loopbackInterface(); 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: zoneToString(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: zoneToString(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: zoneToString(ifi.Index)}, nil},
+ {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
+ }...)
+ }
+}
+
func printLeakedGoroutines() {
gss := leakedGoroutines()
if len(gss) == 0 {
package net
import (
- "fmt"
"io"
"reflect"
"runtime"
}
type resolveTCPAddrTest struct {
- net string
+ network string
litAddrOrName string
addr *TCPAddr
err error
{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
- {"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
- {"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
+ {"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+ {"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
}
-func init() {
- if ifi := loopbackInterface(); ifi != nil {
- index := fmt.Sprintf("%v", ifi.Index)
- resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
- {"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
- {"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
- }...)
- }
- if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
- resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
- {"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil},
- {"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil},
- {"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil},
- }...)
- }
-}
-
func TestResolveTCPAddr(t *testing.T) {
- for _, tt := range resolveTCPAddrTests {
- addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName)
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
+
+ for i, tt := range resolveTCPAddrTests {
+ addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
if err != tt.err {
- t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
+ t.Errorf("#%d: %v", i, err)
+ } else if !reflect.DeepEqual(addr, tt.addr) {
+ t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
}
- if !reflect.DeepEqual(addr, tt.addr) {
- t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr)
+ if err != nil {
+ continue
}
- if err == nil {
- str := addr.String()
- addr1, err := ResolveTCPAddr(tt.net, str)
- if err != nil {
- t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err)
- }
- if !reflect.DeepEqual(addr1, addr) {
- t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr)
- }
+ rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
+ if err != nil {
+ t.Errorf("#%d: %v", i, err)
+ } else if !reflect.DeepEqual(rtaddr, addr) {
+ t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
}
}
}
import (
"reflect"
"runtime"
- "strings"
"testing"
"time"
)
+type resolveUDPAddrTest struct {
+ network string
+ litAddrOrName string
+ addr *UDPAddr
+ err error
+}
+
+var resolveUDPAddrTests = []resolveUDPAddrTest{
+ {"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
+ {"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
+
+ {"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+ {"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
+
+ {"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
+ {"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
+
+ {"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
+ {"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
+
+ {"udp", ":12345", &UDPAddr{Port: 12345}, nil},
+
+ {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+}
+
func TestResolveUDPAddr(t *testing.T) {
- for _, tt := range resolveTCPAddrTests {
- net := strings.Replace(tt.net, "tcp", "udp", -1)
- addr, err := ResolveUDPAddr(net, tt.litAddrOrName)
+ origTestHookLookupIP := testHookLookupIP
+ defer func() { testHookLookupIP = origTestHookLookupIP }()
+ testHookLookupIP = lookupLocalhost
+
+ for i, tt := range resolveUDPAddrTests {
+ addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
if err != tt.err {
- t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, tt.litAddrOrName, err)
+ t.Errorf("#%d: %v", i, err)
+ } else if !reflect.DeepEqual(addr, tt.addr) {
+ t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
}
- if !reflect.DeepEqual(addr, (*UDPAddr)(tt.addr)) {
- t.Fatalf("ResolveUDPAddr(%q, %q) = %#v, want %#v", net, tt.litAddrOrName, addr, tt.addr)
+ if err != nil {
+ continue
}
- if err == nil {
- str := addr.String()
- addr1, err := ResolveUDPAddr(net, str)
- if err != nil {
- t.Fatalf("ResolveUDPAddr(%q, %q) [from %q]: %v", net, str, tt.litAddrOrName, err)
- }
- if !reflect.DeepEqual(addr1, addr) {
- t.Fatalf("ResolveUDPAddr(%q, %q) [from %q] = %#v, want %#v", net, str, tt.litAddrOrName, addr1, addr)
- }
+ rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
+ if err != nil {
+ t.Errorf("#%d: %v", i, err)
+ } else if !reflect.DeepEqual(rtaddr, addr) {
+ t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
}
}
}