}
// Only print the output if we know we are not going to proceed.
// Otherwise it is printed in processBench.
- if atomic.LoadInt32(&b.hasSub) != 0 || b.finished {
+ b.mu.RLock()
+ finished := b.finished
+ b.mu.RUnlock()
+ if atomic.LoadInt32(&b.hasSub) != 0 || finished {
tag := "BENCH"
if b.skipped {
tag = "SKIP"
}
- if b.chatty != nil && (len(b.output) > 0 || b.finished) {
+ if b.chatty != nil && (len(b.output) > 0 || finished) {
b.trimOutput()
fmt.Fprintf(b.w, "--- %s: %s\n%s", tag, b.name, b.output)
}
})
}
+func TestRunParallelFatal(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ if b.N > 1 {
+ b.Fatal("error")
+ }
+ }
+ })
+ })
+}
+
+func TestRunParallelSkipNow(t *testing.T) {
+ testing.Benchmark(func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ if b.N > 1 {
+ b.SkipNow()
+ }
+ }
+ })
+ })
+}
+
func ExampleB_RunParallel() {
// Parallel benchmark for text/template.Template.Execute on a single object.
testing.Benchmark(func(b *testing.B) {
cleanups []func() // optional functions to be called at the end of the test
cleanupName string // Name of the cleanup function.
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
+ finished bool // Test function has completed.
chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
bench bool // Whether the current test is a benchmark.
- finished bool // Test function has completed.
hasSub int32 // Written atomically.
raceErrors int // Number of races detected during test.
runner string // Function name of tRunner running the test.
// it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
+ c.mu.Lock()
c.finished = true
+ c.mu.Unlock()
runtime.Goexit()
}
// other goroutines created during the test. Calling SkipNow does not stop
// those other goroutines.
func (c *common) SkipNow() {
- c.skip()
- c.finished = true
- runtime.Goexit()
-}
-
-func (c *common) skip() {
c.mu.Lock()
- defer c.mu.Unlock()
c.skipped = true
+ c.finished = true
+ c.mu.Unlock()
+ runtime.Goexit()
}
// Skipped reports whether the test was skipped.
err := recover()
signal := true
- if !t.finished && err == nil {
+ t.mu.RLock()
+ finished := t.finished
+ t.mu.RUnlock()
+ if !finished && err == nil {
err = errNilPanicOrGoexit
for p := t.parent; p != nil; p = p.parent {
- if p.finished {
+ p.mu.RLock()
+ finished = p.finished
+ p.mu.RUnlock()
+ if finished {
t.Errorf("%v: subtest may have called FailNow on a parent test", err)
err = nil
signal = false
fn(t)
// code beyond here will not be executed when FailNow is invoked
+ t.mu.Lock()
t.finished = true
+ t.mu.Unlock()
}
// Run runs f as a subtest of t called name. It runs f in a separate goroutine