1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
17 func TestDialContextCancelRace(t
*testing
.T
) {
18 oldConnectFunc
:= connectFunc
19 oldGetsockoptIntFunc
:= getsockoptIntFunc
20 oldTestHookCanceledDial
:= testHookCanceledDial
22 connectFunc
= oldConnectFunc
23 getsockoptIntFunc
= oldGetsockoptIntFunc
24 testHookCanceledDial
= oldTestHookCanceledDial
27 ln
, err
:= newLocalListener("tcp")
31 listenerDone
:= make(chan struct{})
33 defer close(listenerDone
)
39 defer func() { <-listenerDone
}()
42 sawCancel
:= make(chan bool, 1)
43 testHookCanceledDial
= func() {
47 ctx
, cancelCtx
:= context
.WithCancel(context
.Background())
49 connectFunc
= func(fd
int, addr syscall
.Sockaddr
) error
{
50 err
:= oldConnectFunc(fd
, addr
)
51 t
.Logf("connect(%d, addr) = %v", fd
, err
)
53 // On some operating systems, localhost
54 // connects _sometimes_ succeed immediately.
55 // Prevent that, so we exercise the code path
56 // we're interested in testing. This seems
57 // harmless. It makes FreeBSD 10.10 work when
58 // run with many iterations. It failed about
59 // half the time previously.
60 return syscall
.EINPROGRESS
65 getsockoptIntFunc
= func(fd
, level
, opt
int) (val
int, err error
) {
66 val
, err
= oldGetsockoptIntFunc(fd
, level
, opt
)
67 t
.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd
, level
, opt
, val
, err
)
68 if level
== syscall
.SOL_SOCKET
&& opt
== syscall
.SO_ERROR
&& err
== nil && val
== 0 {
69 t
.Logf("canceling context")
71 // Cancel the context at just the moment which
72 // caused the race in issue 16523.
75 // And wait for the "interrupter" goroutine to
76 // cancel the dial by messing with its write
77 // timeout before returning.
81 case <-time
.After(5 * time
.Second
):
82 t
.Errorf("didn't see cancel after 5 seconds")
89 c
, err
:= d
.DialContext(ctx
, "tcp", ln
.Addr().String())
92 t
.Fatal("unexpected successful dial; want context canceled error")
97 case <-time
.After(5 * time
.Second
):
98 t
.Fatal("expected context to be canceled")
101 oe
, ok
:= err
.(*OpError
)
102 if !ok || oe
.Op
!= "dial" {
103 t
.Fatalf("Dial error = %#v; want dial *OpError", err
)
106 if oe
.Err
!= errCanceled
{
107 t
.Errorf("DialContext = (%v, %v); want OpError with error %v", c
, err
, errCanceled
)