github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/net/dial_unix_test.go (about) 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. 4 5 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 7 8 package net 9 10 import ( 11 "context" 12 "syscall" 13 "testing" 14 "time" 15 ) 16 17 // Issue 16523 18 func TestDialContextCancelRace(t *testing.T) { 19 oldConnectFunc := connectFunc 20 oldGetsockoptIntFunc := getsockoptIntFunc 21 oldTestHookCanceledDial := testHookCanceledDial 22 defer func() { 23 connectFunc = oldConnectFunc 24 getsockoptIntFunc = oldGetsockoptIntFunc 25 testHookCanceledDial = oldTestHookCanceledDial 26 }() 27 28 ln, err := newLocalListener("tcp") 29 if err != nil { 30 t.Fatal(err) 31 } 32 listenerDone := make(chan struct{}) 33 go func() { 34 defer close(listenerDone) 35 c, err := ln.Accept() 36 if err == nil { 37 c.Close() 38 } 39 }() 40 defer func() { <-listenerDone }() 41 defer ln.Close() 42 43 sawCancel := make(chan bool, 1) 44 testHookCanceledDial = func() { 45 sawCancel <- true 46 } 47 48 ctx, cancelCtx := context.WithCancel(context.Background()) 49 50 connectFunc = func(fd int, addr syscall.Sockaddr) error { 51 err := oldConnectFunc(fd, addr) 52 t.Logf("connect(%d, addr) = %v", fd, err) 53 if err == nil { 54 // On some operating systems, localhost 55 // connects _sometimes_ succeed immediately. 56 // Prevent that, so we exercise the code path 57 // we're interested in testing. This seems 58 // harmless. It makes FreeBSD 10.10 work when 59 // run with many iterations. It failed about 60 // half the time previously. 61 return syscall.EINPROGRESS 62 } 63 return err 64 } 65 66 getsockoptIntFunc = func(fd, level, opt int) (val int, err error) { 67 val, err = oldGetsockoptIntFunc(fd, level, opt) 68 t.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd, level, opt, val, err) 69 if level == syscall.SOL_SOCKET && opt == syscall.SO_ERROR && err == nil && val == 0 { 70 t.Logf("canceling context") 71 72 // Cancel the context at just the moment which 73 // caused the race in issue 16523. 74 cancelCtx() 75 76 // And wait for the "interrupter" goroutine to 77 // cancel the dial by messing with its write 78 // timeout before returning. 79 select { 80 case <-sawCancel: 81 t.Logf("saw cancel") 82 case <-time.After(5 * time.Second): 83 t.Errorf("didn't see cancel after 5 seconds") 84 } 85 } 86 return 87 } 88 89 var d Dialer 90 c, err := d.DialContext(ctx, "tcp", ln.Addr().String()) 91 if err == nil { 92 c.Close() 93 t.Fatal("unexpected successful dial; want context canceled error") 94 } 95 96 select { 97 case <-ctx.Done(): 98 case <-time.After(5 * time.Second): 99 t.Fatal("expected context to be canceled") 100 } 101 102 oe, ok := err.(*OpError) 103 if !ok || oe.Op != "dial" { 104 t.Fatalf("Dial error = %#v; want dial *OpError", err) 105 } 106 107 if oe.Err != errCanceled { 108 t.Errorf("DialContext = (%v, %v); want OpError with error %v", c, err, errCanceled) 109 } 110 }