mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-12-10 01:55:35 +00:00
Ginkgo 1.10.0 includes the relevant fix for dumping the full stack (https://github.com/onsi/ginkgo/pull/590), so when using that release we can simplify the logging unit test. By changing the skipping, we can avoid the rather volatile util.go entries. However, that gomega is part of the stack trace still needs to be fixed in Gingko.
174 lines
5.3 KiB
Go
174 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
|
|
"github.com/onsi/ginkgo/config"
|
|
"github.com/onsi/ginkgo/ginkgo/interrupthandler"
|
|
"github.com/onsi/ginkgo/ginkgo/testrunner"
|
|
"github.com/onsi/ginkgo/ginkgo/testsuite"
|
|
colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
|
|
)
|
|
|
|
type compilationInput struct {
|
|
runner *testrunner.TestRunner
|
|
result chan compilationOutput
|
|
}
|
|
|
|
type compilationOutput struct {
|
|
runner *testrunner.TestRunner
|
|
err error
|
|
}
|
|
|
|
type SuiteRunner struct {
|
|
notifier *Notifier
|
|
interruptHandler *interrupthandler.InterruptHandler
|
|
}
|
|
|
|
func NewSuiteRunner(notifier *Notifier, interruptHandler *interrupthandler.InterruptHandler) *SuiteRunner {
|
|
return &SuiteRunner{
|
|
notifier: notifier,
|
|
interruptHandler: interruptHandler,
|
|
}
|
|
}
|
|
|
|
func (r *SuiteRunner) compileInParallel(runners []*testrunner.TestRunner, numCompilers int, willCompile func(suite testsuite.TestSuite)) chan compilationOutput {
|
|
//we return this to the consumer, it will return each runner in order as it compiles
|
|
compilationOutputs := make(chan compilationOutput, len(runners))
|
|
|
|
//an array of channels - the nth runner's compilation output is sent to the nth channel in this array
|
|
//we read from these channels in order to ensure we run the suites in order
|
|
orderedCompilationOutputs := []chan compilationOutput{}
|
|
for range runners {
|
|
orderedCompilationOutputs = append(orderedCompilationOutputs, make(chan compilationOutput, 1))
|
|
}
|
|
|
|
//we're going to spin up numCompilers compilers - they're going to run concurrently and will consume this channel
|
|
//we prefill the channel then close it, this ensures we compile things in the correct order
|
|
workPool := make(chan compilationInput, len(runners))
|
|
for i, runner := range runners {
|
|
workPool <- compilationInput{runner, orderedCompilationOutputs[i]}
|
|
}
|
|
close(workPool)
|
|
|
|
//pick a reasonable numCompilers
|
|
if numCompilers == 0 {
|
|
numCompilers = runtime.NumCPU()
|
|
}
|
|
|
|
//a WaitGroup to help us wait for all compilers to shut down
|
|
wg := &sync.WaitGroup{}
|
|
wg.Add(numCompilers)
|
|
|
|
//spin up the concurrent compilers
|
|
for i := 0; i < numCompilers; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for input := range workPool {
|
|
if r.interruptHandler.WasInterrupted() {
|
|
return
|
|
}
|
|
|
|
if willCompile != nil {
|
|
willCompile(input.runner.Suite)
|
|
}
|
|
|
|
//We retry because Go sometimes steps on itself when multiple compiles happen in parallel. This is ugly, but should help resolve flakiness...
|
|
var err error
|
|
retries := 0
|
|
for retries <= 5 {
|
|
if r.interruptHandler.WasInterrupted() {
|
|
return
|
|
}
|
|
if err = input.runner.Compile(); err == nil {
|
|
break
|
|
}
|
|
retries++
|
|
}
|
|
|
|
input.result <- compilationOutput{input.runner, err}
|
|
}
|
|
}()
|
|
}
|
|
|
|
//read from the compilation output channels *in order* and send them to the caller
|
|
//close the compilationOutputs channel to tell the caller we're done
|
|
go func() {
|
|
defer close(compilationOutputs)
|
|
for _, orderedCompilationOutput := range orderedCompilationOutputs {
|
|
select {
|
|
case compilationOutput := <-orderedCompilationOutput:
|
|
compilationOutputs <- compilationOutput
|
|
case <-r.interruptHandler.C:
|
|
//interrupt detected, wait for the compilers to shut down then bail
|
|
//this ensure we clean up after ourselves as we don't leave any compilation processes running
|
|
wg.Wait()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
return compilationOutputs
|
|
}
|
|
|
|
func (r *SuiteRunner) RunSuites(runners []*testrunner.TestRunner, numCompilers int, keepGoing bool, willCompile func(suite testsuite.TestSuite)) (testrunner.RunResult, int) {
|
|
runResult := testrunner.PassingRunResult()
|
|
|
|
compilationOutputs := r.compileInParallel(runners, numCompilers, willCompile)
|
|
|
|
numSuitesThatRan := 0
|
|
suitesThatFailed := []testsuite.TestSuite{}
|
|
for compilationOutput := range compilationOutputs {
|
|
if compilationOutput.err != nil {
|
|
fmt.Print(compilationOutput.err.Error())
|
|
}
|
|
numSuitesThatRan++
|
|
suiteRunResult := testrunner.FailingRunResult()
|
|
if compilationOutput.err == nil {
|
|
suiteRunResult = compilationOutput.runner.Run()
|
|
}
|
|
r.notifier.SendSuiteCompletionNotification(compilationOutput.runner.Suite, suiteRunResult.Passed)
|
|
r.notifier.RunCommand(compilationOutput.runner.Suite, suiteRunResult.Passed)
|
|
runResult = runResult.Merge(suiteRunResult)
|
|
if !suiteRunResult.Passed {
|
|
suitesThatFailed = append(suitesThatFailed, compilationOutput.runner.Suite)
|
|
if !keepGoing {
|
|
break
|
|
}
|
|
}
|
|
if numSuitesThatRan < len(runners) && !config.DefaultReporterConfig.Succinct {
|
|
fmt.Println("")
|
|
}
|
|
}
|
|
|
|
if keepGoing && !runResult.Passed {
|
|
r.listFailedSuites(suitesThatFailed)
|
|
}
|
|
|
|
return runResult, numSuitesThatRan
|
|
}
|
|
|
|
func (r *SuiteRunner) listFailedSuites(suitesThatFailed []testsuite.TestSuite) {
|
|
fmt.Println("")
|
|
fmt.Println("There were failures detected in the following suites:")
|
|
|
|
maxPackageNameLength := 0
|
|
for _, suite := range suitesThatFailed {
|
|
if len(suite.PackageName) > maxPackageNameLength {
|
|
maxPackageNameLength = len(suite.PackageName)
|
|
}
|
|
}
|
|
|
|
packageNameFormatter := fmt.Sprintf("%%%ds", maxPackageNameLength)
|
|
|
|
for _, suite := range suitesThatFailed {
|
|
if config.DefaultReporterConfig.NoColor {
|
|
fmt.Printf("\t"+packageNameFormatter+" %s\n", suite.PackageName, suite.Path)
|
|
} else {
|
|
fmt.Fprintf(colorable.NewColorableStdout(), "\t%s"+packageNameFormatter+"%s %s%s%s\n", redColor, suite.PackageName, defaultStyle, lightGrayColor, suite.Path, defaultStyle)
|
|
}
|
|
}
|
|
}
|