Commit 167562f6 authored by Mikio Hara's avatar Mikio Hara

net: deflake TestDialTimeoutFDLeak

This change makes TestDialTimeoutFDLeak work on almost all the supported
platforms.

Updates #4384.

Change-Id: I3608f438003003f9b7cfa17c9e5fe7077700fd60
Reviewed-on: https://go-review.googlesource.com/8392Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 88399b2e
...@@ -7,7 +7,7 @@ package net ...@@ -7,7 +7,7 @@ package net
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io" "net/internal/socktest"
"os" "os"
"os/exec" "os/exec"
"reflect" "reflect"
...@@ -179,61 +179,51 @@ func TestInvalidDialAndListenArgs(t *testing.T) { ...@@ -179,61 +179,51 @@ func TestInvalidDialAndListenArgs(t *testing.T) {
} }
func TestDialTimeoutFDLeak(t *testing.T) { func TestDialTimeoutFDLeak(t *testing.T) {
if runtime.GOOS != "linux" { switch runtime.GOOS {
// TODO(bradfitz): test on other platforms case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS) t.Skipf("%s does not have full support of socktest", runtime.GOOS)
} }
ln := newLocalListener(t) const T = 100 * time.Millisecond
defer ln.Close()
type connErr struct { switch runtime.GOOS {
conn Conn case "plan9", "windows":
err error origTestHookDialChannel := testHookDialChannel
} testHookDialChannel = func() { time.Sleep(2 * T) }
dials := listenerBacklog + 100 defer func() { testHookDialChannel = origTestHookDialChannel }()
// used to be listenerBacklog + 5, but was found to be unreliable, issue 4384. if runtime.GOOS == "plan9" {
maxGoodConnect := listenerBacklog + runtime.NumCPU()*10 break
resc := make(chan connErr) }
for i := 0; i < dials; i++ { fallthrough
go func() { default:
conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond) sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
resc <- connErr{conn, err} time.Sleep(2 * T)
}() return nil, errTimeout
})
defer sw.Set(socktest.FilterConnect, nil)
} }
var firstErr string before := sw.Sockets()
var ngood int const N = 100
var toClose []io.Closer var wg sync.WaitGroup
for i := 0; i < dials; i++ { wg.Add(N)
ce := <-resc for i := 0; i < N; i++ {
if ce.err == nil { go func() {
ngood++ defer wg.Done()
if ngood > maxGoodConnect { // This dial never starts to send any SYN
t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect) // segment because of above socket filter and
// test hook.
c, err := DialTimeout("tcp", "127.0.0.1:0", T)
if err == nil {
t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
c.Close()
} }
toClose = append(toClose, ce.conn) }()
continue
}
err := ce.err
if firstErr == "" {
firstErr = err.Error()
} else if err.Error() != firstErr {
t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
}
}
for _, c := range toClose {
c.Close()
}
for i := 0; i < 100; i++ {
if got := numFD(); got < dials {
// Test passes.
return
}
time.Sleep(10 * time.Millisecond)
} }
if got := numFD(); got >= dials { wg.Wait()
t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials) after := sw.Sockets()
if len(after) != len(before) {
t.Errorf("got %d; want %d", len(after), len(before))
} }
} }
...@@ -329,23 +319,6 @@ func TestDialMultiFDLeak(t *testing.T) { ...@@ -329,23 +319,6 @@ func TestDialMultiFDLeak(t *testing.T) {
} }
} }
func numFD() int {
if runtime.GOOS == "linux" {
f, err := os.Open("/proc/self/fd")
if err != nil {
panic(err)
}
defer f.Close()
names, err := f.Readdirnames(0)
if err != nil {
panic(err)
}
return len(names)
}
// All tests using this should be skipped anyway, but:
panic("numFDs not implemented on " + runtime.GOOS)
}
func TestDialer(t *testing.T) { func TestDialer(t *testing.T) {
ln, err := Listen("tcp4", "127.0.0.1:0") ln, err := Listen("tcp4", "127.0.0.1:0")
if err != nil { if err != nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment