// associated with the bubble.
// - T.Run, T.Parallel, and T.Deadline must not be called.
func Test(t *testing.T, f func(*testing.T)) {
+ var ok bool
synctest.Run(func() {
- testingSynctestTest(t, f)
+ ok = testingSynctestTest(t, f)
})
+ if !ok {
+ // Fail the test outside the bubble,
+ // so test durations get set using real time.
+ t.FailNow()
+ }
}
//go:linkname testingSynctestTest testing/synctest.testingSynctestTest
-func testingSynctestTest(t *testing.T, f func(*testing.T))
+func testingSynctestTest(t *testing.T, f func(*testing.T)) bool
// Wait blocks until every goroutine within the current bubble,
// other than the current goroutine, is durably blocked.
t.Logf("cleanup panicked with %v", r)
}
// Flush the output log up to the root before dying.
- for root := &t.common; root.parent != nil; root = root.parent {
+ // Skip this if this *T is a synctest bubble, because we're not a subtest.
+ for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
root.mu.Lock()
root.duration += highPrecisionTimeSince(root.start)
d := root.duration
// It is called by synctest.Test, from within an already-created bubble.
//
//go:linkname testingSynctestTest testing/synctest.testingSynctestTest
-func testingSynctestTest(t *T, f func(*T)) {
+func testingSynctestTest(t *T, f func(*T)) (ok bool) {
if t.cleanupStarted.Load() {
panic("testing: synctest.Run called during t.Cleanup")
}
// parent tests by one of the subtests. Continue aborting up the chain.
runtime.Goexit()
}
+ return !t2.failed
}
// Deadline reports the time at which the test binary will have