
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.
250 lines
8.9 KiB
Go
250 lines
8.9 KiB
Go
/*
|
|
|
|
Aggregator is a reporter used by the Ginkgo CLI to aggregate and present parallel test output
|
|
coherently as tests complete. You shouldn't need to use this in your code. To run tests in parallel:
|
|
|
|
ginkgo -nodes=N
|
|
|
|
where N is the number of nodes you desire.
|
|
*/
|
|
package remote
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/onsi/ginkgo/config"
|
|
"github.com/onsi/ginkgo/reporters/stenographer"
|
|
"github.com/onsi/ginkgo/types"
|
|
)
|
|
|
|
type configAndSuite struct {
|
|
config config.GinkgoConfigType
|
|
summary *types.SuiteSummary
|
|
}
|
|
|
|
type Aggregator struct {
|
|
nodeCount int
|
|
config config.DefaultReporterConfigType
|
|
stenographer stenographer.Stenographer
|
|
result chan bool
|
|
|
|
suiteBeginnings chan configAndSuite
|
|
aggregatedSuiteBeginnings []configAndSuite
|
|
|
|
beforeSuites chan *types.SetupSummary
|
|
aggregatedBeforeSuites []*types.SetupSummary
|
|
|
|
afterSuites chan *types.SetupSummary
|
|
aggregatedAfterSuites []*types.SetupSummary
|
|
|
|
specCompletions chan *types.SpecSummary
|
|
completedSpecs []*types.SpecSummary
|
|
|
|
suiteEndings chan *types.SuiteSummary
|
|
aggregatedSuiteEndings []*types.SuiteSummary
|
|
specs []*types.SpecSummary
|
|
|
|
startTime time.Time
|
|
}
|
|
|
|
func NewAggregator(nodeCount int, result chan bool, config config.DefaultReporterConfigType, stenographer stenographer.Stenographer) *Aggregator {
|
|
aggregator := &Aggregator{
|
|
nodeCount: nodeCount,
|
|
result: result,
|
|
config: config,
|
|
stenographer: stenographer,
|
|
|
|
suiteBeginnings: make(chan configAndSuite),
|
|
beforeSuites: make(chan *types.SetupSummary),
|
|
afterSuites: make(chan *types.SetupSummary),
|
|
specCompletions: make(chan *types.SpecSummary),
|
|
suiteEndings: make(chan *types.SuiteSummary),
|
|
}
|
|
|
|
go aggregator.mux()
|
|
|
|
return aggregator
|
|
}
|
|
|
|
func (aggregator *Aggregator) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
|
|
aggregator.suiteBeginnings <- configAndSuite{config, summary}
|
|
}
|
|
|
|
func (aggregator *Aggregator) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
|
|
aggregator.beforeSuites <- setupSummary
|
|
}
|
|
|
|
func (aggregator *Aggregator) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
|
|
aggregator.afterSuites <- setupSummary
|
|
}
|
|
|
|
func (aggregator *Aggregator) SpecWillRun(specSummary *types.SpecSummary) {
|
|
//noop
|
|
}
|
|
|
|
func (aggregator *Aggregator) SpecDidComplete(specSummary *types.SpecSummary) {
|
|
aggregator.specCompletions <- specSummary
|
|
}
|
|
|
|
func (aggregator *Aggregator) SpecSuiteDidEnd(summary *types.SuiteSummary) {
|
|
aggregator.suiteEndings <- summary
|
|
}
|
|
|
|
func (aggregator *Aggregator) mux() {
|
|
loop:
|
|
for {
|
|
select {
|
|
case configAndSuite := <-aggregator.suiteBeginnings:
|
|
aggregator.registerSuiteBeginning(configAndSuite)
|
|
case setupSummary := <-aggregator.beforeSuites:
|
|
aggregator.registerBeforeSuite(setupSummary)
|
|
case setupSummary := <-aggregator.afterSuites:
|
|
aggregator.registerAfterSuite(setupSummary)
|
|
case specSummary := <-aggregator.specCompletions:
|
|
aggregator.registerSpecCompletion(specSummary)
|
|
case suite := <-aggregator.suiteEndings:
|
|
finished, passed := aggregator.registerSuiteEnding(suite)
|
|
if finished {
|
|
aggregator.result <- passed
|
|
break loop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (aggregator *Aggregator) registerSuiteBeginning(configAndSuite configAndSuite) {
|
|
aggregator.aggregatedSuiteBeginnings = append(aggregator.aggregatedSuiteBeginnings, configAndSuite)
|
|
|
|
if len(aggregator.aggregatedSuiteBeginnings) == 1 {
|
|
aggregator.startTime = time.Now()
|
|
}
|
|
|
|
if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount {
|
|
return
|
|
}
|
|
|
|
aggregator.stenographer.AnnounceSuite(configAndSuite.summary.SuiteDescription, configAndSuite.config.RandomSeed, configAndSuite.config.RandomizeAllSpecs, aggregator.config.Succinct)
|
|
|
|
totalNumberOfSpecs := 0
|
|
if len(aggregator.aggregatedSuiteBeginnings) > 0 {
|
|
totalNumberOfSpecs = configAndSuite.summary.NumberOfSpecsBeforeParallelization
|
|
}
|
|
|
|
aggregator.stenographer.AnnounceTotalNumberOfSpecs(totalNumberOfSpecs, aggregator.config.Succinct)
|
|
aggregator.stenographer.AnnounceAggregatedParallelRun(aggregator.nodeCount, aggregator.config.Succinct)
|
|
aggregator.flushCompletedSpecs()
|
|
}
|
|
|
|
func (aggregator *Aggregator) registerBeforeSuite(setupSummary *types.SetupSummary) {
|
|
aggregator.aggregatedBeforeSuites = append(aggregator.aggregatedBeforeSuites, setupSummary)
|
|
aggregator.flushCompletedSpecs()
|
|
}
|
|
|
|
func (aggregator *Aggregator) registerAfterSuite(setupSummary *types.SetupSummary) {
|
|
aggregator.aggregatedAfterSuites = append(aggregator.aggregatedAfterSuites, setupSummary)
|
|
aggregator.flushCompletedSpecs()
|
|
}
|
|
|
|
func (aggregator *Aggregator) registerSpecCompletion(specSummary *types.SpecSummary) {
|
|
aggregator.completedSpecs = append(aggregator.completedSpecs, specSummary)
|
|
aggregator.specs = append(aggregator.specs, specSummary)
|
|
aggregator.flushCompletedSpecs()
|
|
}
|
|
|
|
func (aggregator *Aggregator) flushCompletedSpecs() {
|
|
if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount {
|
|
return
|
|
}
|
|
|
|
for _, setupSummary := range aggregator.aggregatedBeforeSuites {
|
|
aggregator.announceBeforeSuite(setupSummary)
|
|
}
|
|
|
|
for _, specSummary := range aggregator.completedSpecs {
|
|
aggregator.announceSpec(specSummary)
|
|
}
|
|
|
|
for _, setupSummary := range aggregator.aggregatedAfterSuites {
|
|
aggregator.announceAfterSuite(setupSummary)
|
|
}
|
|
|
|
aggregator.aggregatedBeforeSuites = []*types.SetupSummary{}
|
|
aggregator.completedSpecs = []*types.SpecSummary{}
|
|
aggregator.aggregatedAfterSuites = []*types.SetupSummary{}
|
|
}
|
|
|
|
func (aggregator *Aggregator) announceBeforeSuite(setupSummary *types.SetupSummary) {
|
|
aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput)
|
|
if setupSummary.State != types.SpecStatePassed {
|
|
aggregator.stenographer.AnnounceBeforeSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
|
|
}
|
|
}
|
|
|
|
func (aggregator *Aggregator) announceAfterSuite(setupSummary *types.SetupSummary) {
|
|
aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput)
|
|
if setupSummary.State != types.SpecStatePassed {
|
|
aggregator.stenographer.AnnounceAfterSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
|
|
}
|
|
}
|
|
|
|
func (aggregator *Aggregator) announceSpec(specSummary *types.SpecSummary) {
|
|
if aggregator.config.Verbose && specSummary.State != types.SpecStatePending && specSummary.State != types.SpecStateSkipped {
|
|
aggregator.stenographer.AnnounceSpecWillRun(specSummary)
|
|
}
|
|
|
|
aggregator.stenographer.AnnounceCapturedOutput(specSummary.CapturedOutput)
|
|
|
|
switch specSummary.State {
|
|
case types.SpecStatePassed:
|
|
if specSummary.IsMeasurement {
|
|
aggregator.stenographer.AnnounceSuccesfulMeasurement(specSummary, aggregator.config.Succinct)
|
|
} else if specSummary.RunTime.Seconds() >= aggregator.config.SlowSpecThreshold {
|
|
aggregator.stenographer.AnnounceSuccesfulSlowSpec(specSummary, aggregator.config.Succinct)
|
|
} else {
|
|
aggregator.stenographer.AnnounceSuccesfulSpec(specSummary)
|
|
}
|
|
|
|
case types.SpecStatePending:
|
|
aggregator.stenographer.AnnouncePendingSpec(specSummary, aggregator.config.NoisyPendings && !aggregator.config.Succinct)
|
|
case types.SpecStateSkipped:
|
|
aggregator.stenographer.AnnounceSkippedSpec(specSummary, aggregator.config.Succinct || !aggregator.config.NoisySkippings, aggregator.config.FullTrace)
|
|
case types.SpecStateTimedOut:
|
|
aggregator.stenographer.AnnounceSpecTimedOut(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
|
|
case types.SpecStatePanicked:
|
|
aggregator.stenographer.AnnounceSpecPanicked(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
|
|
case types.SpecStateFailed:
|
|
aggregator.stenographer.AnnounceSpecFailed(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
|
|
}
|
|
}
|
|
|
|
func (aggregator *Aggregator) registerSuiteEnding(suite *types.SuiteSummary) (finished bool, passed bool) {
|
|
aggregator.aggregatedSuiteEndings = append(aggregator.aggregatedSuiteEndings, suite)
|
|
if len(aggregator.aggregatedSuiteEndings) < aggregator.nodeCount {
|
|
return false, false
|
|
}
|
|
|
|
aggregatedSuiteSummary := &types.SuiteSummary{}
|
|
aggregatedSuiteSummary.SuiteSucceeded = true
|
|
|
|
for _, suiteSummary := range aggregator.aggregatedSuiteEndings {
|
|
if !suiteSummary.SuiteSucceeded {
|
|
aggregatedSuiteSummary.SuiteSucceeded = false
|
|
}
|
|
|
|
aggregatedSuiteSummary.NumberOfSpecsThatWillBeRun += suiteSummary.NumberOfSpecsThatWillBeRun
|
|
aggregatedSuiteSummary.NumberOfTotalSpecs += suiteSummary.NumberOfTotalSpecs
|
|
aggregatedSuiteSummary.NumberOfPassedSpecs += suiteSummary.NumberOfPassedSpecs
|
|
aggregatedSuiteSummary.NumberOfFailedSpecs += suiteSummary.NumberOfFailedSpecs
|
|
aggregatedSuiteSummary.NumberOfPendingSpecs += suiteSummary.NumberOfPendingSpecs
|
|
aggregatedSuiteSummary.NumberOfSkippedSpecs += suiteSummary.NumberOfSkippedSpecs
|
|
aggregatedSuiteSummary.NumberOfFlakedSpecs += suiteSummary.NumberOfFlakedSpecs
|
|
}
|
|
|
|
aggregatedSuiteSummary.RunTime = time.Since(aggregator.startTime)
|
|
|
|
aggregator.stenographer.SummarizeFailures(aggregator.specs)
|
|
aggregator.stenographer.AnnounceSpecRunCompletion(aggregatedSuiteSummary, aggregator.config.Succinct)
|
|
|
|
return true, aggregatedSuiteSummary.SuiteSucceeded
|
|
}
|