// Run runs the tests. It returns an exit code to pass to os.Exit. func (m *M) Run() int { // TestMain may have already called flag.Parse. if !flag.Parsed() { flag.Parse() } parseCpuList() m.before() startAlarm() haveExamples = len(m.examples) > 0 testRan, testOk := runTests(m.deps.MatchString, m.tests) exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples) if !testRan && !exampleRan && *matchBenchmarks == "" { fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") } if !testOk || !exampleOk || !runBenchmarks(m.deps.MatchString, m.benchmarks) || race.Errors() > 0 { fmt.Println("FAIL") m.after() return 1 } fmt.Println("PASS") m.after() return 0 }
// Parallel signals that this test is to be run in parallel with (and only with) // other parallel tests. func (t *T) Parallel() { if t.isParallel { panic("testing: t.Parallel called multiple times") } t.isParallel = true // We don't want to include the time we spend waiting for serial tests // in the test duration. Record the elapsed time thus far and reset the // timer afterwards. t.duration += time.Since(t.start) // Add to the list of tests to be released by the parent. t.parent.sub = append(t.parent.sub, t) t.raceErrors += race.Errors() t.signal <- true // Release calling test. <-t.parent.barrier // Wait for the parent test to complete. t.context.waitParallel() t.start = time.Now() t.raceErrors += -race.Errors() }
// runN runs a single benchmark for the specified number of iterations. func (b *B) runN(n int) { b.ctx, b.cancel = context.WithCancel(b.parentContext()) defer b.cancel() benchmarkLock.Lock() defer benchmarkLock.Unlock() // Try to get a comparable environment for each run // by clearing garbage from previous runs. runtime.GC() b.raceErrors = -race.Errors() b.N = n b.parallelism = 1 b.ResetTimer() b.StartTimer() b.benchFunc(b) b.StopTimer() b.previousN = n b.previousDuration = b.duration b.raceErrors += race.Errors() if b.raceErrors > 0 { b.Errorf("race detected during execution of benchmark") } }
func tRunner(t *T, fn func(t *T)) { t.ctx, t.cancel = context.WithCancel(t.parentContext()) defer t.cancel() // When this goroutine is done, either because fn(t) // returned normally or because a test failure triggered // a call to runtime.Goexit, record the duration and send // a signal saying that the test is done. defer func() { t.raceErrors += race.Errors() if t.raceErrors > 0 { t.Errorf("race detected during execution of test") } t.duration += time.Now().Sub(t.start) // If the test panicked, print any test output before dying. err := recover() if !t.finished && err == nil { err = fmt.Errorf("test executed panic(nil) or runtime.Goexit") } if err != nil { t.Fail() t.report() panic(err) } if len(t.sub) > 0 { // Run parallel subtests. // Decrease the running count for this test. t.context.release() // Release the parallel subtests. close(t.barrier) // Wait for subtests to complete. for _, sub := range t.sub { <-sub.signal } if !t.isParallel { // Reacquire the count for sequential tests. See comment in Run. t.context.waitParallel() } } else if t.isParallel { // Only release the count for this test if it was run as a parallel // test. See comment in Run method. t.context.release() } 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 if t.parent != nil && !t.hasSub { t.setRan() } t.signal <- true }() t.start = time.Now() t.raceErrors = -race.Errors() fn(t) t.finished = true }