func (r *SuiteRunner) RunSuites(runners []*testrunner.TestRunner, keepGoing bool, willCompile func(suite testsuite.TestSuite)) (testrunner.RunResult, int) { runResult := testrunner.PassingRunResult() compilers := make([]*compiler, len(runners)) for i, runner := range runners { compilers[i] = &compiler{ runner: runner, compilationError: make(chan error, 1), } } compilerChannel := make(chan *compiler) numCompilers := runtime.NumCPU() for i := 0; i < numCompilers; i++ { go func() { for compiler := range compilerChannel { if willCompile != nil { willCompile(compiler.runner.Suite) } compiler.compile() } }() } go func() { for _, compiler := range compilers { compilerChannel <- compiler } close(compilerChannel) }() numSuitesThatRan := 0 suitesThatFailed := []testsuite.TestSuite{} for i, runner := range runners { if r.interruptHandler.WasInterrupted() { break } compilationError := <-compilers[i].compilationError if compilationError != nil { fmt.Print(compilationError.Error()) } numSuitesThatRan++ suiteRunResult := testrunner.FailingRunResult() if compilationError == nil { suiteRunResult = compilers[i].runner.Run() } r.notifier.SendSuiteCompletionNotification(runner.Suite, suiteRunResult.Passed) runResult = runResult.Merge(suiteRunResult) if !suiteRunResult.Passed { suitesThatFailed = append(suitesThatFailed, runner.Suite) if !keepGoing { break } } if i < len(runners)-1 && !config.DefaultReporterConfig.Succinct { fmt.Println("") } } if keepGoing && !runResult.Passed { r.listFailedSuites(suitesThatFailed) } return runResult, numSuitesThatRan }
func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { r.commandFlags.computeNodes() r.notifier.VerifyNotificationsAreAvailable() suites, skippedPackages := findSuites(args, r.commandFlags.Recurse, r.commandFlags.SkipPackage) if len(skippedPackages) > 0 { fmt.Println("Will skip:") for _, skippedPackage := range skippedPackages { fmt.Println(" " + skippedPackage) } } if len(suites) == 0 { complainAndQuit("Found no test suites") } r.ComputeSuccinctMode(len(suites)) t := time.Now() runners := []*testrunner.TestRunner{} for _, suite := range suites { runners = append(runners, testrunner.New(suite, r.commandFlags.NumCPU, r.commandFlags.ParallelStream, r.commandFlags.Race, r.commandFlags.Cover, r.commandFlags.Tags, additionalArgs)) } numSuites := 0 runResult := testrunner.PassingRunResult() if r.commandFlags.UntilItFails { iteration := 0 for { r.UpdateSeed() randomizedRunners := r.randomizeOrder(runners) runResult, numSuites = r.suiteRunner.RunSuites(randomizedRunners, r.commandFlags.KeepGoing, nil) iteration++ if r.interruptHandler.WasInterrupted() { break } if runResult.Passed { fmt.Printf("\nAll tests passed...\nWill keep running them until they fail.\nThis was attempt #%d\n%s\n", iteration, orcMessage(iteration)) } else { fmt.Printf("\nTests failed on attempt #%d\n\n", iteration) break } } } else { randomizedRunners := r.randomizeOrder(runners) runResult, numSuites = r.suiteRunner.RunSuites(randomizedRunners, r.commandFlags.KeepGoing, nil) } for _, runner := range runners { runner.CleanUp() } fmt.Printf("\nGinkgo ran %d %s in %s\n", numSuites, pluralizedWord("suite", "suites", numSuites), time.Since(t)) if runResult.Passed { if runResult.HasProgrammaticFocus { fmt.Printf("Test Suite Passed\n") fmt.Printf("Detected Programmatic Focus - setting exit status to %d\n", types.GINKGO_FOCUS_EXIT_CODE) os.Exit(types.GINKGO_FOCUS_EXIT_CODE) } else { fmt.Printf("Test Suite Passed\n") os.Exit(0) } } else { fmt.Printf("Test Suite Failed\n") os.Exit(1) } }