Skip to content

Commit 623d653

Browse files
committed
crypto/tls: deflake localPipe in tests
The localPipe implementation assumes that every successful net.Dial results in exactly one successful listener.Accept. I don't believe this is guaranteed by essentially any operating system. For this test, we're seeing flakes on dragonfly (#29583). But see also #19519, flakes due to the same assumption on FreeBSD and macOS in package net's own tests. This CL rewrites localPipe to try a few times to get a matching pair of connections on the dial and accept side. Fixes #29583. Change-Id: Idb045b18c404eae457f091df20456c5ae879a291 Reviewed-on: https://go-review.googlesource.com/c/go/+/184157 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 2e0cd2a commit 623d653

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

src/crypto/tls/handshake_test.go

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -222,28 +222,65 @@ func tempFile(contents string) string {
222222
// localListener is set up by TestMain and used by localPipe to create Conn
223223
// pairs like net.Pipe, but connected by an actual buffered TCP connection.
224224
var localListener struct {
225-
sync.Mutex
226-
net.Listener
225+
mu sync.Mutex
226+
addr net.Addr
227+
ch chan net.Conn
228+
}
229+
230+
const localFlakes = 0 // change to 1 or 2 to exercise localServer/localPipe handling of mismatches
231+
232+
func localServer(l net.Listener) {
233+
for n := 0; ; n++ {
234+
c, err := l.Accept()
235+
if err != nil {
236+
return
237+
}
238+
if localFlakes == 1 && n%2 == 0 {
239+
c.Close()
240+
continue
241+
}
242+
localListener.ch <- c
243+
}
227244
}
228245

229246
func localPipe(t testing.TB) (net.Conn, net.Conn) {
230-
localListener.Lock()
231-
defer localListener.Unlock()
232-
c := make(chan net.Conn)
233-
go func() {
234-
conn, err := localListener.Accept()
247+
localListener.mu.Lock()
248+
defer localListener.mu.Unlock()
249+
250+
addr := localListener.addr
251+
252+
Dialing:
253+
// We expect a rare mismatch, but probably not 5 in a row.
254+
for i := 0; i < 5; i++ {
255+
tooSlow := time.NewTimer(1 * time.Second)
256+
defer tooSlow.Stop()
257+
c1, err := net.Dial(addr.Network(), addr.String())
235258
if err != nil {
236-
t.Errorf("Failed to accept local connection: %v", err)
259+
t.Fatalf("localPipe: %v", err)
260+
}
261+
if localFlakes == 2 && i == 0 {
262+
c1.Close()
263+
continue
264+
}
265+
for {
266+
select {
267+
case <-tooSlow.C:
268+
t.Logf("localPipe: timeout waiting for %v", c1.LocalAddr())
269+
c1.Close()
270+
continue Dialing
271+
272+
case c2 := <-localListener.ch:
273+
if c2.RemoteAddr().String() == c1.LocalAddr().String() {
274+
return c1, c2
275+
}
276+
t.Logf("localPipe: unexpected connection: %v != %v", c2.RemoteAddr(), c1.LocalAddr())
277+
c2.Close()
278+
}
237279
}
238-
c <- conn
239-
}()
240-
addr := localListener.Addr()
241-
c1, err := net.Dial(addr.Network(), addr.String())
242-
if err != nil {
243-
t.Fatalf("Failed to dial local connection: %v", err)
244280
}
245-
c2 := <-c
246-
return c1, c2
281+
282+
t.Fatalf("localPipe: failed to connect")
283+
panic("unreachable")
247284
}
248285

249286
// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
@@ -293,8 +330,10 @@ func runMain(m *testing.M) int {
293330
fmt.Fprintf(os.Stderr, "Failed to open local listener: %v", err)
294331
os.Exit(1)
295332
}
296-
localListener.Listener = l
297-
defer localListener.Close()
333+
localListener.ch = make(chan net.Conn)
334+
localListener.addr = l.Addr()
335+
defer l.Close()
336+
go localServer(l)
298337

299338
if err := checkOpenSSLVersion(); err != nil {
300339
fmt.Fprintf(os.Stderr, "Error: %v", err)

0 commit comments

Comments
 (0)