]> Cypherpunks repositories - gostls13.git/commitdiff
net: deflake TestDialTimeoutFDLeak
authorMikio Hara <mikioh.mikioh@gmail.com>
Wed, 1 Apr 2015 13:01:24 +0000 (22:01 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Fri, 3 Apr 2015 00:48:47 +0000 (00:48 +0000)
This change makes TestDialTimeoutFDLeak work on almost all the supported
platforms.

Updates #4384.

Change-Id: I3608f438003003f9b7cfa17c9e5fe7077700fd60
Reviewed-on: https://go-review.googlesource.com/8392
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/dial_test.go

index 39e61d5734bdfb73171cef35be53abfa7251ce6f..448faac7445167436ba6f4a7d4cd9220db4f3a34 100644 (file)
@@ -7,7 +7,7 @@ package net
 import (
        "bytes"
        "fmt"
-       "io"
+       "net/internal/socktest"
        "os"
        "os/exec"
        "reflect"
@@ -179,61 +179,51 @@ func TestInvalidDialAndListenArgs(t *testing.T) {
 }
 
 func TestDialTimeoutFDLeak(t *testing.T) {
-       if runtime.GOOS != "linux" {
-               // TODO(bradfitz): test on other platforms
-               t.Skipf("skipping test on %q", runtime.GOOS)
+       switch runtime.GOOS {
+       case "plan9":
+               t.Skipf("%s does not have full support of socktest", runtime.GOOS)
        }
 
-       ln := newLocalListener(t)
-       defer ln.Close()
+       const T = 100 * time.Millisecond
 
-       type connErr struct {
-               conn Conn
-               err  error
-       }
-       dials := listenerBacklog + 100
-       // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
-       maxGoodConnect := listenerBacklog + runtime.NumCPU()*10
-       resc := make(chan connErr)
-       for i := 0; i < dials; i++ {
-               go func() {
-                       conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
-                       resc <- connErr{conn, err}
-               }()
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               origTestHookDialChannel := testHookDialChannel
+               testHookDialChannel = func() { time.Sleep(2 * T) }
+               defer func() { testHookDialChannel = origTestHookDialChannel }()
+               if runtime.GOOS == "plan9" {
+                       break
+               }
+               fallthrough
+       default:
+               sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+                       time.Sleep(2 * T)
+                       return nil, errTimeout
+               })
+               defer sw.Set(socktest.FilterConnect, nil)
        }
 
-       var firstErr string
-       var ngood int
-       var toClose []io.Closer
-       for i := 0; i < dials; i++ {
-               ce := <-resc
-               if ce.err == nil {
-                       ngood++
-                       if ngood > maxGoodConnect {
-                               t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
+       before := sw.Sockets()
+       const N = 100
+       var wg sync.WaitGroup
+       wg.Add(N)
+       for i := 0; i < N; i++ {
+               go func() {
+                       defer wg.Done()
+                       // This dial never starts to send any SYN
+                       // 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 {
-               t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
+       wg.Wait()
+       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) {
        }
 }
 
-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) {
        ln, err := Listen("tcp4", "127.0.0.1:0")
        if err != nil {