aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/testing.go')
-rw-r--r--src/testing/testing.go12
1 files changed, 10 insertions, 2 deletions
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 3a7a135a3c..9943fa6b4d 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -196,13 +196,14 @@ var (
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
- mu sync.RWMutex // guards output and failed
+ mu sync.RWMutex // guards output, failed, and done.
output []byte // Output generated by test or benchmark.
w io.Writer // For flushToParent.
chatty bool // A copy of the chatty flag.
failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
- finished bool
+ finished bool // Test function has completed.
+ done bool // Test is finished and all subtests have completed.
parent *common
level int // Nesting depth of test or benchmark.
@@ -351,6 +352,10 @@ func (c *common) Fail() {
}
c.mu.Lock()
defer c.mu.Unlock()
+ // c.done needs to be locked to synchronize checks to c.done in parent tests.
+ if c.done {
+ panic("Fail in goroutine after " + c.name + " has completed")
+ }
c.failed = true
}
@@ -540,6 +545,9 @@ func tRunner(t *T, fn func(t *T)) {
}
t.report() // Report after all subtests have finished.
+ // Do not lock t.done to allow race detector to detect race in case
+ // the user does not appropriately synchronizes a goroutine.
+ t.done = true
t.signal <- true
}()