mirror-to-gitea/vendor/github.com/onsi/ginkgo/internal/remote/aggregator.go
vendor/github.com/onsi/ginkgo/internal/remote/aggregator.goRaw
1/*
2
3Aggregator is a reporter used by the Ginkgo CLI to aggregate and present parallel test output
4coherently as tests complete. You shouldn't need to use this in your code. To run tests in parallel:
5
6 ginkgo -nodes=N
7
8where N is the number of nodes you desire.
9*/
10package remote
11
12import (
13 "time"
14
15 "github.com/onsi/ginkgo/config"
16 "github.com/onsi/ginkgo/reporters/stenographer"
17 "github.com/onsi/ginkgo/types"
18)
19
20type configAndSuite struct {
21 config config.GinkgoConfigType
22 summary *types.SuiteSummary
23}
24
25type Aggregator struct {
26 nodeCount int
27 config config.DefaultReporterConfigType
28 stenographer stenographer.Stenographer
29 result chan bool
30
31 suiteBeginnings chan configAndSuite
32 aggregatedSuiteBeginnings []configAndSuite
33
34 beforeSuites chan *types.SetupSummary
35 aggregatedBeforeSuites []*types.SetupSummary
36
37 afterSuites chan *types.SetupSummary
38 aggregatedAfterSuites []*types.SetupSummary
39
40 specCompletions chan *types.SpecSummary
41 completedSpecs []*types.SpecSummary
42
43 suiteEndings chan *types.SuiteSummary
44 aggregatedSuiteEndings []*types.SuiteSummary
45 specs []*types.SpecSummary
46
47 startTime time.Time
48}
49
50func NewAggregator(nodeCount int, result chan bool, config config.DefaultReporterConfigType, stenographer stenographer.Stenographer) *Aggregator {
51 aggregator := &Aggregator{
52 nodeCount: nodeCount,
53 result: result,
54 config: config,
55 stenographer: stenographer,
56
57 suiteBeginnings: make(chan configAndSuite),
58 beforeSuites: make(chan *types.SetupSummary),
59 afterSuites: make(chan *types.SetupSummary),
60 specCompletions: make(chan *types.SpecSummary),
61 suiteEndings: make(chan *types.SuiteSummary),
62 }
63
64 go aggregator.mux()
65
66 return aggregator
67}
68
69func (aggregator *Aggregator) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
70 aggregator.suiteBeginnings <- configAndSuite{config, summary}
71}
72
73func (aggregator *Aggregator) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
74 aggregator.beforeSuites <- setupSummary
75}
76
77func (aggregator *Aggregator) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
78 aggregator.afterSuites <- setupSummary
79}
80
81func (aggregator *Aggregator) SpecWillRun(specSummary *types.SpecSummary) {
82 //noop
83}
84
85func (aggregator *Aggregator) SpecDidComplete(specSummary *types.SpecSummary) {
86 aggregator.specCompletions <- specSummary
87}
88
89func (aggregator *Aggregator) SpecSuiteDidEnd(summary *types.SuiteSummary) {
90 aggregator.suiteEndings <- summary
91}
92
93func (aggregator *Aggregator) mux() {
94loop:
95 for {
96 select {
97 case configAndSuite := <-aggregator.suiteBeginnings:
98 aggregator.registerSuiteBeginning(configAndSuite)
99 case setupSummary := <-aggregator.beforeSuites:
100 aggregator.registerBeforeSuite(setupSummary)
101 case setupSummary := <-aggregator.afterSuites:
102 aggregator.registerAfterSuite(setupSummary)
103 case specSummary := <-aggregator.specCompletions:
104 aggregator.registerSpecCompletion(specSummary)
105 case suite := <-aggregator.suiteEndings:
106 finished, passed := aggregator.registerSuiteEnding(suite)
107 if finished {
108 aggregator.result <- passed
109 break loop
110 }
111 }
112 }
113}
114
115func (aggregator *Aggregator) registerSuiteBeginning(configAndSuite configAndSuite) {
116 aggregator.aggregatedSuiteBeginnings = append(aggregator.aggregatedSuiteBeginnings, configAndSuite)
117
118 if len(aggregator.aggregatedSuiteBeginnings) == 1 {
119 aggregator.startTime = time.Now()
120 }
121
122 if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount {
123 return
124 }
125
126 aggregator.stenographer.AnnounceSuite(configAndSuite.summary.SuiteDescription, configAndSuite.config.RandomSeed, configAndSuite.config.RandomizeAllSpecs, aggregator.config.Succinct)
127
128 totalNumberOfSpecs := 0
129 if len(aggregator.aggregatedSuiteBeginnings) > 0 {
130 totalNumberOfSpecs = configAndSuite.summary.NumberOfSpecsBeforeParallelization
131 }
132
133 aggregator.stenographer.AnnounceTotalNumberOfSpecs(totalNumberOfSpecs, aggregator.config.Succinct)
134 aggregator.stenographer.AnnounceAggregatedParallelRun(aggregator.nodeCount, aggregator.config.Succinct)
135 aggregator.flushCompletedSpecs()
136}
137
138func (aggregator *Aggregator) registerBeforeSuite(setupSummary *types.SetupSummary) {
139 aggregator.aggregatedBeforeSuites = append(aggregator.aggregatedBeforeSuites, setupSummary)
140 aggregator.flushCompletedSpecs()
141}
142
143func (aggregator *Aggregator) registerAfterSuite(setupSummary *types.SetupSummary) {
144 aggregator.aggregatedAfterSuites = append(aggregator.aggregatedAfterSuites, setupSummary)
145 aggregator.flushCompletedSpecs()
146}
147
148func (aggregator *Aggregator) registerSpecCompletion(specSummary *types.SpecSummary) {
149 aggregator.completedSpecs = append(aggregator.completedSpecs, specSummary)
150 aggregator.specs = append(aggregator.specs, specSummary)
151 aggregator.flushCompletedSpecs()
152}
153
154func (aggregator *Aggregator) flushCompletedSpecs() {
155 if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount {
156 return
157 }
158
159 for _, setupSummary := range aggregator.aggregatedBeforeSuites {
160 aggregator.announceBeforeSuite(setupSummary)
161 }
162
163 for _, specSummary := range aggregator.completedSpecs {
164 aggregator.announceSpec(specSummary)
165 }
166
167 for _, setupSummary := range aggregator.aggregatedAfterSuites {
168 aggregator.announceAfterSuite(setupSummary)
169 }
170
171 aggregator.aggregatedBeforeSuites = []*types.SetupSummary{}
172 aggregator.completedSpecs = []*types.SpecSummary{}
173 aggregator.aggregatedAfterSuites = []*types.SetupSummary{}
174}
175
176func (aggregator *Aggregator) announceBeforeSuite(setupSummary *types.SetupSummary) {
177 aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput)
178 if setupSummary.State != types.SpecStatePassed {
179 aggregator.stenographer.AnnounceBeforeSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
180 }
181}
182
183func (aggregator *Aggregator) announceAfterSuite(setupSummary *types.SetupSummary) {
184 aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput)
185 if setupSummary.State != types.SpecStatePassed {
186 aggregator.stenographer.AnnounceAfterSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
187 }
188}
189
190func (aggregator *Aggregator) announceSpec(specSummary *types.SpecSummary) {
191 if aggregator.config.Verbose && specSummary.State != types.SpecStatePending && specSummary.State != types.SpecStateSkipped {
192 aggregator.stenographer.AnnounceSpecWillRun(specSummary)
193 }
194
195 aggregator.stenographer.AnnounceCapturedOutput(specSummary.CapturedOutput)
196
197 switch specSummary.State {
198 case types.SpecStatePassed:
199 if specSummary.IsMeasurement {
200 aggregator.stenographer.AnnounceSuccessfulMeasurement(specSummary, aggregator.config.Succinct)
201 } else if specSummary.RunTime.Seconds() >= aggregator.config.SlowSpecThreshold {
202 aggregator.stenographer.AnnounceSuccessfulSlowSpec(specSummary, aggregator.config.Succinct)
203 } else {
204 aggregator.stenographer.AnnounceSuccessfulSpec(specSummary)
205 }
206
207 case types.SpecStatePending:
208 aggregator.stenographer.AnnouncePendingSpec(specSummary, aggregator.config.NoisyPendings && !aggregator.config.Succinct)
209 case types.SpecStateSkipped:
210 aggregator.stenographer.AnnounceSkippedSpec(specSummary, aggregator.config.Succinct || !aggregator.config.NoisySkippings, aggregator.config.FullTrace)
211 case types.SpecStateTimedOut:
212 aggregator.stenographer.AnnounceSpecTimedOut(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
213 case types.SpecStatePanicked:
214 aggregator.stenographer.AnnounceSpecPanicked(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
215 case types.SpecStateFailed:
216 aggregator.stenographer.AnnounceSpecFailed(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace)
217 }
218}
219
220func (aggregator *Aggregator) registerSuiteEnding(suite *types.SuiteSummary) (finished bool, passed bool) {
221 aggregator.aggregatedSuiteEndings = append(aggregator.aggregatedSuiteEndings, suite)
222 if len(aggregator.aggregatedSuiteEndings) < aggregator.nodeCount {
223 return false, false
224 }
225
226 aggregatedSuiteSummary := &types.SuiteSummary{}
227 aggregatedSuiteSummary.SuiteSucceeded = true
228
229 for _, suiteSummary := range aggregator.aggregatedSuiteEndings {
230 if !suiteSummary.SuiteSucceeded {
231 aggregatedSuiteSummary.SuiteSucceeded = false
232 }
233
234 aggregatedSuiteSummary.NumberOfSpecsThatWillBeRun += suiteSummary.NumberOfSpecsThatWillBeRun
235 aggregatedSuiteSummary.NumberOfTotalSpecs += suiteSummary.NumberOfTotalSpecs
236 aggregatedSuiteSummary.NumberOfPassedSpecs += suiteSummary.NumberOfPassedSpecs
237 aggregatedSuiteSummary.NumberOfFailedSpecs += suiteSummary.NumberOfFailedSpecs
238 aggregatedSuiteSummary.NumberOfPendingSpecs += suiteSummary.NumberOfPendingSpecs
239 aggregatedSuiteSummary.NumberOfSkippedSpecs += suiteSummary.NumberOfSkippedSpecs
240 aggregatedSuiteSummary.NumberOfFlakedSpecs += suiteSummary.NumberOfFlakedSpecs
241 }
242
243 aggregatedSuiteSummary.RunTime = time.Since(aggregator.startTime)
244
245 aggregator.stenographer.SummarizeFailures(aggregator.specs)
246 aggregator.stenographer.AnnounceSpecRunCompletion(aggregatedSuiteSummary, aggregator.config.Succinct)
247
248 return true, aggregatedSuiteSummary.SuiteSucceeded
249}