]> Cypherpunks repositories - gostls13.git/commitdiff
net: attempt to deflake TestListenCloseListen
authorBryan C. Mills <bcmills@google.com>
Sat, 20 Jan 2024 00:05:53 +0000 (19:05 -0500)
committerGopher Robot <gobot@golang.org>
Mon, 22 Jan 2024 16:30:46 +0000 (16:30 +0000)
Also make it flakier in longtest mode by burning through more
ephemeral ports. (Burning through the ports raised the failure rate
for me locally enough to reliably reproduce the failure in #65175 with
-count=10.)

Fixes #65175 (I hope).

Change-Id: I5f5b68b6bf6a6aa92e66f0288078817041656a3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/557177
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/net/net_test.go

index b448a79cce79d8926e80b97a391197185fe1b61d..f2fa84844219ed117cbb3d429fd5a64059fd574e 100644 (file)
@@ -11,6 +11,7 @@ import (
        "net/internal/socktest"
        "os"
        "runtime"
+       "sync"
        "testing"
        "time"
 )
@@ -294,27 +295,72 @@ func TestPacketConnClose(t *testing.T) {
 }
 
 func TestListenCloseListen(t *testing.T) {
-       const maxTries = 10
-       for tries := 0; tries < maxTries; tries++ {
-               ln := newLocalListener(t, "tcp")
-               addr := ln.Addr().String()
-               // TODO: This is racy. The selected address could be reused in between this
-               // Close and the subsequent Listen.
-               if err := ln.Close(); err != nil {
-                       if perr := parseCloseError(err, false); perr != nil {
-                               t.Error(perr)
-                       }
-                       t.Fatal(err)
+       if testing.Short() {
+               t.Parallel()
+       }
+
+       ln := newLocalListener(t, "tcp")
+       addr := ln.Addr().String()
+
+       var wg sync.WaitGroup
+       wg.Add(1)
+       go func() {
+               for {
+                       c, err := ln.Accept()
+                       if err != nil {
+                               wg.Done()
+                               return
+                       }
+                       wg.Add(1)
+                       go func() {
+                               io.Copy(io.Discard, c)
+                               c.Close()
+                               wg.Done()
+                       }()
                }
-               ln, err := Listen("tcp", addr)
-               if err == nil {
-                       // Success. (This test didn't always make it here earlier.)
-                       ln.Close()
-                       return
+       }()
+       defer wg.Wait()
+
+       // Keep a connection alive while we close the listener to try to discourage
+       // the kernel from reusing the listener's port for some other process.
+       //
+       // TODO(bcmills): This empirically seems to work, and we also rely on it in
+       // TestDialClosedPortFailFast, but I can't find a reference documenting this
+       // port-reuse behavior.
+       c, err := Dial("tcp", addr)
+       defer c.Close()
+
+       if err := ln.Close(); err != nil {
+               if perr := parseCloseError(err, false); perr != nil {
+                       t.Error(perr)
+               }
+               t.Fatal(err)
+       }
+
+       if !testing.Short() {
+               // Burn through some ephemeral ports (without actually accepting any
+               // connections on them) to try to encourage the kernel to reuse the address
+               // if it is going to.
+               lns := make(chan []Listener, 1)
+               lns <- nil
+               for i := 0; i < 4000; i++ {
+                       ln := newLocalListener(t, "tcp")
+                       lns <- append(<-lns, ln)
                }
-               t.Errorf("failed on try %d/%d: %v", tries+1, maxTries, err)
+               defer func() {
+                       for _, ln := range <-lns {
+                               ln.Close()
+                       }
+               }()
+       }
+
+       ln, err = Listen("tcp", addr)
+       if err == nil {
+               // Success. (This test didn't always make it here earlier.)
+               ln.Close()
+               return
        }
-       t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
+       t.Fatalf("failed to listen/close/listen on same address")
 }
 
 // See golang.org/issue/6163, golang.org/issue/6987.