mirror of
https://github.com/golang/go
synced 2024-11-22 20:40:03 -07:00
testing: allow parallel-subtest goroutines to exit when the subtest is complete
Fixes #45127 Updates #38768 Change-Id: I7f41901d5bcc07741ac9f5f2a24d2b07ef633cb1 Reviewed-on: https://go-review.googlesource.com/c/go/+/303330 Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
482903150d
commit
1c590661e7
52
src/cmd/go/testdata/script/test_finished_subtest_goroutines.txt
vendored
Normal file
52
src/cmd/go/testdata/script/test_finished_subtest_goroutines.txt
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# Regression test for https://golang.org/issue/45127:
|
||||
# Goroutines for completed parallel subtests should exit immediately,
|
||||
# not block until earlier subtests have finished.
|
||||
|
||||
[short] skip
|
||||
|
||||
! go test .
|
||||
stdout 'panic: slow failure'
|
||||
! stdout '\[chan send'
|
||||
|
||||
-- go.mod --
|
||||
module golang.org/issue45127
|
||||
|
||||
go 1.16
|
||||
-- issue45127_test.go --
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTestingGoroutineLeak(t *testing.T) {
|
||||
debug.SetTraceback("all")
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const nFast = 10
|
||||
|
||||
t.Run("slow", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
wg.Wait()
|
||||
for i := 0; i < nFast; i++ {
|
||||
// If the subtest goroutines are going to park on the channel
|
||||
// send, allow them to park now. If they're not going to park,
|
||||
// make sure they have had a chance to run to completion so
|
||||
// that they aren't spuriously parked when we panic.
|
||||
runtime.Gosched()
|
||||
}
|
||||
panic("slow failure")
|
||||
})
|
||||
|
||||
wg.Add(nFast)
|
||||
for i := 0; i < nFast; i++ {
|
||||
t.Run(fmt.Sprintf("leaky%d", i), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
}
|
@ -1258,7 +1258,7 @@ func (t *T) Run(name string, f func(t *T)) bool {
|
||||
t = &T{
|
||||
common: common{
|
||||
barrier: make(chan bool),
|
||||
signal: make(chan bool),
|
||||
signal: make(chan bool, 1),
|
||||
name: testName,
|
||||
parent: &t.common,
|
||||
level: t.level + 1,
|
||||
@ -1539,7 +1539,7 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
|
||||
ctx.deadline = deadline
|
||||
t := &T{
|
||||
common: common{
|
||||
signal: make(chan bool),
|
||||
signal: make(chan bool, 1),
|
||||
barrier: make(chan bool),
|
||||
w: os.Stdout,
|
||||
},
|
||||
@ -1552,11 +1552,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
|
||||
for _, test := range tests {
|
||||
t.Run(test.Name, test.F)
|
||||
}
|
||||
// Run catching the signal rather than the tRunner as a separate
|
||||
// goroutine to avoid adding a goroutine during the sequential
|
||||
// phase as this pollutes the stacktrace output when aborting.
|
||||
go func() { <-t.signal }()
|
||||
})
|
||||
select {
|
||||
case <-t.signal:
|
||||
default:
|
||||
panic("internal error: tRunner exited without sending on t.signal")
|
||||
}
|
||||
ok = ok && !t.Failed()
|
||||
ran = ran || t.ran
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user