]> Cypherpunks repositories - gostls13.git/commitdiff
all: fix incorrect channel and API usage in some unit tests
authorZiheng Liu <lzhfromustc@gmail.com>
Thu, 13 Feb 2020 21:20:30 +0000 (16:20 -0500)
committerIan Lance Taylor <iant@golang.org>
Thu, 27 Feb 2020 19:04:17 +0000 (19:04 +0000)
This CL changes some unit test functions, making sure that these tests (and goroutines spawned during test) won't block.
Since they are just test functions, I use one CL to fix them all. I hope this won't cause trouble to reviewers and can save time for us.
There are three main categories of incorrect logic fixed by this CL:
1. Use testing.Fatal()/Fatalf() in spawned goroutines, which is forbidden by Go's document.
2. Channels are used in such a way that, when errors or timeout happen, the test will be blocked and never return.
3. Channels are used in such a way that, when errors or timeout happen, the test can return but some spawned goroutines will be leaked, occupying resource until all other tests return and the process is killed.

Change-Id: I3df931ec380794a0cf1404e632c1dd57c65d63e8
Reviewed-on: https://go-review.googlesource.com/c/go/+/219380
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
14 files changed:
src/cmd/compile/internal/gc/lex_test.go
src/cmd/compile/internal/gc/testdata/dupLoad_test.go
src/crypto/tls/handshake_client_test.go
src/crypto/tls/handshake_server_test.go
src/crypto/tls/tls_test.go
src/encoding/base64/base64_test.go
src/expvar/expvar_test.go
src/go/printer/printer_test.go
src/internal/poll/fd_mutex_test.go
src/log/syslog/syslog_test.go
src/net/http/serve_test.go
src/net/http/transport_test.go
src/os/os_test.go
src/sync/atomic/value_test.go

index e05726c9f35fa961c12f99f9297a97f1c0b1c322..b2081a1732bbb49382645b492351e7cdccba9cb0 100644 (file)
@@ -93,7 +93,7 @@ func TestPragcgo(t *testing.T) {
        for _, tt := range tests {
 
                p.err = make(chan syntax.Error)
-               gotch := make(chan [][]string)
+               gotch := make(chan [][]string, 1)
                go func() {
                        p.pragcgobuf = nil
                        p.pragcgo(nopos, tt.in)
index 9d65f54946d250aba213f16f799cfae11858e72e..d85912309da87261c91e6d6290e2d58191e49fab 100644 (file)
@@ -19,23 +19,25 @@ func read1(b []byte) (uint16, uint16) {
 
 func main1(t *testing.T) {
        const N = 100000
-       done := make(chan struct{})
+       done := make(chan bool, 2)
        b := make([]byte, 2)
        go func() {
                for i := 0; i < N; i++ {
                        b[0] = byte(i)
                        b[1] = byte(i)
                }
-               done <- struct{}{}
+               done <- true
        }()
        go func() {
                for i := 0; i < N; i++ {
                        x, y := read1(b)
                        if byte(x) != byte(y) {
-                               t.Fatalf("x=%x y=%x\n", x, y)
+                               t.Errorf("x=%x y=%x\n", x, y)
+                               done <- false
+                               return
                        }
                }
-               done <- struct{}{}
+               done <- true
        }()
        <-done
        <-done
@@ -51,23 +53,25 @@ func read2(b []byte) (uint16, uint16) {
 
 func main2(t *testing.T) {
        const N = 100000
-       done := make(chan struct{})
+       done := make(chan bool, 2)
        b := make([]byte, 2)
        go func() {
                for i := 0; i < N; i++ {
                        b[0] = byte(i)
                        b[1] = byte(i)
                }
-               done <- struct{}{}
+               done <- true
        }()
        go func() {
                for i := 0; i < N; i++ {
                        x, y := read2(b)
                        if x&0xff00 != y&0xff00 {
-                               t.Fatalf("x=%x y=%x\n", x, y)
+                               t.Errorf("x=%x y=%x\n", x, y)
+                               done <- false
+                               return
                        }
                }
-               done <- struct{}{}
+               done <- true
        }()
        <-done
        <-done
index 6bd3c374ce2f7934c9f42d024121a6545384cbcc..8632d98697a7b7168b4045cd5726862bb2461689 100644 (file)
@@ -1748,7 +1748,7 @@ func TestHandshakeRace(t *testing.T) {
 
                startWrite := make(chan struct{})
                startRead := make(chan struct{})
-               readDone := make(chan struct{})
+               readDone := make(chan struct{}, 1)
 
                client := Client(c, testConfig)
                go func() {
index 1e5da1e12e1503744cb71a448761b8b67f3b2747..953ca0026edbddb49a83bf14e48f95e6b0b211d0 100644 (file)
@@ -182,7 +182,7 @@ func TestRenegotiationExtension(t *testing.T) {
                cipherSuites:                 []uint16{TLS_RSA_WITH_RC4_128_SHA},
        }
 
-       bufChan := make(chan []byte)
+       bufChan := make(chan []byte, 1)
        c, s := localPipe(t)
 
        go func() {
@@ -575,11 +575,12 @@ func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
                return nil, nil, err
        }
 
-       connChan := make(chan interface{})
+       connChan := make(chan interface{}, 1)
        go func() {
                tcpConn, err := l.Accept()
                if err != nil {
                        connChan <- err
+                       return
                }
                connChan <- tcpConn
        }()
index 178b519f1cc7c7fdb4a7aaaa26f926967acc96f0..89fac607e1728fd4c166f784d10f840339d797e8 100644 (file)
@@ -294,7 +294,11 @@ func TestTLSUniqueMatches(t *testing.T) {
        defer ln.Close()
 
        serverTLSUniques := make(chan []byte)
+       parentDone := make(chan struct{})
+       childDone := make(chan struct{})
+       defer close(parentDone)
        go func() {
+               defer close(childDone)
                for i := 0; i < 2; i++ {
                        sconn, err := ln.Accept()
                        if err != nil {
@@ -308,7 +312,11 @@ func TestTLSUniqueMatches(t *testing.T) {
                                t.Error(err)
                                return
                        }
-                       serverTLSUniques <- srv.ConnectionState().TLSUnique
+                       select {
+                       case <-parentDone:
+                               return
+                       case serverTLSUniques <- srv.ConnectionState().TLSUnique:
+                       }
                }
        }()
 
@@ -318,7 +326,15 @@ func TestTLSUniqueMatches(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) {
+
+       var serverTLSUniquesValue []byte
+       select {
+       case <-childDone:
+               return
+       case serverTLSUniquesValue = <-serverTLSUniques:
+       }
+
+       if !bytes.Equal(conn.ConnectionState().TLSUnique, serverTLSUniquesValue) {
                t.Error("client and server channel bindings differ")
        }
        conn.Close()
@@ -331,7 +347,14 @@ func TestTLSUniqueMatches(t *testing.T) {
        if !conn.ConnectionState().DidResume {
                t.Error("second session did not use resumption")
        }
-       if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) {
+
+       select {
+       case <-childDone:
+               return
+       case serverTLSUniquesValue = <-serverTLSUniques:
+       }
+
+       if !bytes.Equal(conn.ConnectionState().TLSUnique, serverTLSUniquesValue) {
                t.Error("client and server channel bindings differ when session resumption is used")
        }
 }
index bc67036f5bcfbb81e1b8ddaf2f300599f29962c1..c2c9478a4373d707b3bb0d070caaab4c3c418ce3 100644 (file)
@@ -401,7 +401,7 @@ func TestDecoderIssue3577(t *testing.T) {
                source: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig...
                nextc:  next,
        })
-       errc := make(chan error)
+       errc := make(chan error, 1)
        go func() {
                _, err := ioutil.ReadAll(d)
                errc <- err
index 7b1f83a7d77f127be9f0b214617f14b916291283..69b0a76058f8d503e829875d5349e8bdbcc62761 100644 (file)
@@ -489,12 +489,13 @@ func BenchmarkRealworldExpvarUsage(b *testing.B) {
                b.Fatalf("Listen failed: %v", err)
        }
        defer ln.Close()
-       done := make(chan bool)
+       done := make(chan bool, 1)
        go func() {
                for p := 0; p < P; p++ {
                        s, err := ln.Accept()
                        if err != nil {
                                b.Errorf("Accept failed: %v", err)
+                               done <- false
                                return
                        }
                        servers[p] = s
@@ -504,11 +505,14 @@ func BenchmarkRealworldExpvarUsage(b *testing.B) {
        for p := 0; p < P; p++ {
                c, err := net.Dial("tcp", ln.Addr().String())
                if err != nil {
+                       <-done
                        b.Fatalf("Dial failed: %v", err)
                }
                clients[p] = c
        }
-       <-done
+       if !<-done {
+               b.FailNow()
+       }
 
        b.StartTimer()
 
index 8f9cd534b434ccb3d6a2c473ba633f7a1ace8f9b..d2650399dae550259c52e9838b787fdb2867ac6e 100644 (file)
@@ -165,7 +165,7 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
 
 func check(t *testing.T, source, golden string, mode checkMode) {
        // run the test
-       cc := make(chan int)
+       cc := make(chan int, 1)
        go func() {
                runcheck(t, source, golden, mode)
                cc <- 0
index 2c53c4561fbb73b956dd3539beb893290a501171..3029b9a6811f1fe79fa64dc3cad5980459dedd26 100644 (file)
@@ -59,7 +59,7 @@ func TestMutexClose(t *testing.T) {
 }
 
 func TestMutexCloseUnblock(t *testing.T) {
-       c := make(chan bool)
+       c := make(chan bool, 4)
        var mu FDMutex
        mu.RWLock(true)
        for i := 0; i < 4; i++ {
@@ -151,12 +151,15 @@ func TestMutexStress(t *testing.T) {
                N = 1e4
        }
        defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
-       done := make(chan bool)
+       done := make(chan bool, P)
        var mu FDMutex
        var readState [2]uint64
        var writeState [2]uint64
        for p := 0; p < P; p++ {
                go func() {
+                       defer func() {
+                               done <- !t.Failed()
+                       }()
                        r := rand.New(rand.NewSource(rand.Int63()))
                        for i := 0; i < N; i++ {
                                switch r.Intn(3) {
@@ -203,11 +206,12 @@ func TestMutexStress(t *testing.T) {
                                        }
                                }
                        }
-                       done <- true
                }()
        }
        for p := 0; p < P; p++ {
-               <-done
+               if !<-done {
+                       t.FailNow()
+               }
        }
        if !mu.IncrefAndClose() {
                t.Fatal("broken")
index 8df8ebbf585694a6fbdb59a765d3b0d18edfa361..b2cf8df4b9374a625e5f3829fc6d064129346e6b 100644 (file)
@@ -356,7 +356,7 @@ func TestConcurrentReconnect(t *testing.T) {
        }
 
        // count all the messages arriving
-       count := make(chan int)
+       count := make(chan int, 1)
        go func() {
                ct := 0
                for range done {
index 29b937993e0b35d9235129f5c00d0bc90d8872fb..aa6d87251d028278ec0fd76c5c0cb1b13d02a1db 100644 (file)
@@ -947,7 +947,7 @@ func TestOnlyWriteTimeout(t *testing.T) {
 
        c := ts.Client()
 
-       errc := make(chan error)
+       errc := make(chan error, 1)
        go func() {
                res, err := c.Get(ts.URL)
                if err != nil {
@@ -5167,8 +5167,14 @@ func BenchmarkClient(b *testing.B) {
        }
 
        done := make(chan error)
+       stop := make(chan struct{})
+       defer close(stop)
        go func() {
-               done <- cmd.Wait()
+               select {
+               case <-stop:
+                       return
+               case done <- cmd.Wait():
+               }
        }()
 
        // Do b.N requests to the server.
index 3ca7ce93b29a5be4ae32c36564a9b765847aee05..f4014d95bb4c615e1ebfbd22e77124acf1892832 100644 (file)
@@ -451,14 +451,23 @@ func TestTransportReadToEndReusesConn(t *testing.T) {
 
 func TestTransportMaxPerHostIdleConns(t *testing.T) {
        defer afterTest(t)
+       stop := make(chan struct{}) // stop marks the exit of main Test goroutine
+       defer close(stop)
+
        resch := make(chan string)
        gotReq := make(chan bool)
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                gotReq <- true
-               msg := <-resch
+               var msg string
+               select {
+               case <-stop:
+                       return
+               case msg = <-resch:
+               }
                _, err := w.Write([]byte(msg))
                if err != nil {
-                       t.Fatalf("Write: %v", err)
+                       t.Errorf("Write: %v", err)
+                       return
                }
        }))
        defer ts.Close()
@@ -472,6 +481,13 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
        // Their responses will hang until we write to resch, though.
        donech := make(chan bool)
        doReq := func() {
+               defer func() {
+                       select {
+                       case <-stop:
+                               return
+                       case donech <- t.Failed():
+                       }
+               }()
                resp, err := c.Get(ts.URL)
                if err != nil {
                        t.Error(err)
@@ -481,7 +497,6 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
                        t.Errorf("ReadAll: %v", err)
                        return
                }
-               donech <- true
        }
        go doReq()
        <-gotReq
@@ -842,7 +857,9 @@ func TestStressSurpriseServerCloses(t *testing.T) {
                                        // where we won the race.
                                        res.Body.Close()
                                }
-                               activityc <- true
+                               if !<-activityc { // Receives false when close(activityc) is executed
+                                       return
+                               }
                        }
                }()
        }
@@ -850,8 +867,9 @@ func TestStressSurpriseServerCloses(t *testing.T) {
        // Make sure all the request come back, one way or another.
        for i := 0; i < numClients*reqsPerClient; i++ {
                select {
-               case <-activityc:
+               case activityc <- true:
                case <-time.After(5 * time.Second):
+                       close(activityc)
                        t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile")
                }
        }
@@ -2361,7 +2379,9 @@ func TestTransportCancelRequestInDial(t *testing.T) {
        tr := &Transport{
                Dial: func(network, addr string) (net.Conn, error) {
                        eventLog.Println("dial: blocking")
-                       inDial <- true
+                       if !<-inDial {
+                               return nil, errors.New("main Test goroutine exited")
+                       }
                        <-unblockDial
                        return nil, errors.New("nope")
                },
@@ -2376,8 +2396,9 @@ func TestTransportCancelRequestInDial(t *testing.T) {
        }()
 
        select {
-       case <-inDial:
+       case inDial <- true:
        case <-time.After(5 * time.Second):
+               close(inDial)
                t.Fatal("timeout; never saw blocking dial")
        }
 
index 802ecc4e498e6b90b0214301cb07f3635526f8f0..1d8442d8083e2fa76d49249ed6850278f7c1cef7 100644 (file)
@@ -1325,8 +1325,9 @@ func TestChdirAndGetwd(t *testing.T) {
 // Test that Chdir+Getwd is program-wide.
 func TestProgWideChdir(t *testing.T) {
        const N = 10
+       const ErrPwd = "Error!"
        c := make(chan bool)
-       cpwd := make(chan string)
+       cpwd := make(chan string, N)
        for i := 0; i < N; i++ {
                go func(i int) {
                        // Lock half the goroutines in their own operating system
@@ -1339,10 +1340,15 @@ func TestProgWideChdir(t *testing.T) {
                                // See issue 9428.
                                runtime.LockOSThread()
                        }
-                       <-c
+                       hasErr, closed := <-c
+                       if !closed && hasErr {
+                               cpwd <- ErrPwd
+                               return
+                       }
                        pwd, err := Getwd()
                        if err != nil {
                                t.Errorf("Getwd on goroutine %d: %v", i, err)
+                               cpwd <- ErrPwd
                                return
                        }
                        cpwd <- pwd
@@ -1350,10 +1356,12 @@ func TestProgWideChdir(t *testing.T) {
        }
        oldwd, err := Getwd()
        if err != nil {
+               c <- true
                t.Fatalf("Getwd: %v", err)
        }
        d, err := ioutil.TempDir("", "test")
        if err != nil {
+               c <- true
                t.Fatalf("TempDir: %v", err)
        }
        defer func() {
@@ -1363,17 +1371,22 @@ func TestProgWideChdir(t *testing.T) {
                RemoveAll(d)
        }()
        if err := Chdir(d); err != nil {
+               c <- true
                t.Fatalf("Chdir: %v", err)
        }
        // OS X sets TMPDIR to a symbolic link.
        // So we resolve our working directory again before the test.
        d, err = Getwd()
        if err != nil {
+               c <- true
                t.Fatalf("Getwd: %v", err)
        }
        close(c)
        for i := 0; i < N; i++ {
                pwd := <-cpwd
+               if pwd == ErrPwd {
+                       t.FailNow()
+               }
                if pwd != d {
                        t.Errorf("Getwd returned %q; want %q", pwd, d)
                }
index fd69ba30dc39409948a8f34753a44c754fd19a19..f289766340416a388dab8a5d8ee0277258988197 100644 (file)
@@ -91,10 +91,11 @@ func TestValueConcurrent(t *testing.T) {
        }
        for _, test := range tests {
                var v Value
-               done := make(chan bool)
+               done := make(chan bool, p)
                for i := 0; i < p; i++ {
                        go func() {
                                r := rand.New(rand.NewSource(rand.Int63()))
+                               expected := true
                        loop:
                                for j := 0; j < N; j++ {
                                        x := test[r.Intn(len(test))]
@@ -106,9 +107,10 @@ func TestValueConcurrent(t *testing.T) {
                                                }
                                        }
                                        t.Logf("loaded unexpected value %+v, want %+v", x, test)
-                                       done <- false
+                                       expected = false
+                                       break
                                }
-                               done <- true
+                               done <- expected
                        }()
                }
                for i := 0; i < p; i++ {