arnaucube
arnaucube/mirror-to-giteaPublic Self-hosted repository
mirror-to-gitea/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.go
vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner.goRaw
  1package specrunner
  2
  3import (
  4	"fmt"
  5	"os"
  6	"os/signal"
  7	"sync"
  8	"syscall"
  9
 10	"github.com/onsi/ginkgo/internal/spec_iterator"
 11
 12	"github.com/onsi/ginkgo/config"
 13	"github.com/onsi/ginkgo/internal/leafnodes"
 14	"github.com/onsi/ginkgo/internal/spec"
 15	Writer "github.com/onsi/ginkgo/internal/writer"
 16	"github.com/onsi/ginkgo/reporters"
 17	"github.com/onsi/ginkgo/types"
 18
 19	"time"
 20)
 21
 22type SpecRunner struct {
 23	description     string
 24	beforeSuiteNode leafnodes.SuiteNode
 25	iterator        spec_iterator.SpecIterator
 26	afterSuiteNode  leafnodes.SuiteNode
 27	reporters       []reporters.Reporter
 28	startTime       time.Time
 29	suiteID         string
 30	runningSpec     *spec.Spec
 31	writer          Writer.WriterInterface
 32	config          config.GinkgoConfigType
 33	interrupted     bool
 34	processedSpecs  []*spec.Spec
 35	lock            *sync.Mutex
 36}
 37
 38func New(description string, beforeSuiteNode leafnodes.SuiteNode, iterator spec_iterator.SpecIterator, afterSuiteNode leafnodes.SuiteNode, reporters []reporters.Reporter, writer Writer.WriterInterface, config config.GinkgoConfigType) *SpecRunner {
 39	return &SpecRunner{
 40		description:     description,
 41		beforeSuiteNode: beforeSuiteNode,
 42		iterator:        iterator,
 43		afterSuiteNode:  afterSuiteNode,
 44		reporters:       reporters,
 45		writer:          writer,
 46		config:          config,
 47		suiteID:         randomID(),
 48		lock:            &sync.Mutex{},
 49	}
 50}
 51
 52func (runner *SpecRunner) Run() bool {
 53	if runner.config.DryRun {
 54		runner.performDryRun()
 55		return true
 56	}
 57
 58	runner.reportSuiteWillBegin()
 59	signalRegistered := make(chan struct{})
 60	go runner.registerForInterrupts(signalRegistered)
 61	<-signalRegistered
 62
 63	suitePassed := runner.runBeforeSuite()
 64
 65	if suitePassed {
 66		suitePassed = runner.runSpecs()
 67	}
 68
 69	runner.blockForeverIfInterrupted()
 70
 71	suitePassed = runner.runAfterSuite() && suitePassed
 72
 73	runner.reportSuiteDidEnd(suitePassed)
 74
 75	return suitePassed
 76}
 77
 78func (runner *SpecRunner) performDryRun() {
 79	runner.reportSuiteWillBegin()
 80
 81	if runner.beforeSuiteNode != nil {
 82		summary := runner.beforeSuiteNode.Summary()
 83		summary.State = types.SpecStatePassed
 84		runner.reportBeforeSuite(summary)
 85	}
 86
 87	for {
 88		spec, err := runner.iterator.Next()
 89		if err == spec_iterator.ErrClosed {
 90			break
 91		}
 92		if err != nil {
 93			fmt.Println("failed to iterate over tests:\n" + err.Error())
 94			break
 95		}
 96
 97		runner.processedSpecs = append(runner.processedSpecs, spec)
 98
 99		summary := spec.Summary(runner.suiteID)
100		runner.reportSpecWillRun(summary)
101		if summary.State == types.SpecStateInvalid {
102			summary.State = types.SpecStatePassed
103		}
104		runner.reportSpecDidComplete(summary, false)
105	}
106
107	if runner.afterSuiteNode != nil {
108		summary := runner.afterSuiteNode.Summary()
109		summary.State = types.SpecStatePassed
110		runner.reportAfterSuite(summary)
111	}
112
113	runner.reportSuiteDidEnd(true)
114}
115
116func (runner *SpecRunner) runBeforeSuite() bool {
117	if runner.beforeSuiteNode == nil || runner.wasInterrupted() {
118		return true
119	}
120
121	runner.writer.Truncate()
122	conf := runner.config
123	passed := runner.beforeSuiteNode.Run(conf.ParallelNode, conf.ParallelTotal, conf.SyncHost)
124	if !passed {
125		runner.writer.DumpOut()
126	}
127	runner.reportBeforeSuite(runner.beforeSuiteNode.Summary())
128	return passed
129}
130
131func (runner *SpecRunner) runAfterSuite() bool {
132	if runner.afterSuiteNode == nil {
133		return true
134	}
135
136	runner.writer.Truncate()
137	conf := runner.config
138	passed := runner.afterSuiteNode.Run(conf.ParallelNode, conf.ParallelTotal, conf.SyncHost)
139	if !passed {
140		runner.writer.DumpOut()
141	}
142	runner.reportAfterSuite(runner.afterSuiteNode.Summary())
143	return passed
144}
145
146func (runner *SpecRunner) runSpecs() bool {
147	suiteFailed := false
148	skipRemainingSpecs := false
149	for {
150		spec, err := runner.iterator.Next()
151		if err == spec_iterator.ErrClosed {
152			break
153		}
154		if err != nil {
155			fmt.Println("failed to iterate over tests:\n" + err.Error())
156			suiteFailed = true
157			break
158		}
159
160		runner.processedSpecs = append(runner.processedSpecs, spec)
161
162		if runner.wasInterrupted() {
163			break
164		}
165		if skipRemainingSpecs {
166			spec.Skip()
167		}
168
169		if !spec.Skipped() && !spec.Pending() {
170			if passed := runner.runSpec(spec); !passed {
171				suiteFailed = true
172			}
173		} else if spec.Pending() && runner.config.FailOnPending {
174			runner.reportSpecWillRun(spec.Summary(runner.suiteID))
175			suiteFailed = true
176			runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed())
177		} else {
178			runner.reportSpecWillRun(spec.Summary(runner.suiteID))
179			runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed())
180		}
181
182		if spec.Failed() && runner.config.FailFast {
183			skipRemainingSpecs = true
184		}
185	}
186
187	return !suiteFailed
188}
189
190func (runner *SpecRunner) runSpec(spec *spec.Spec) (passed bool) {
191	maxAttempts := 1
192	if runner.config.FlakeAttempts > 0 {
193		// uninitialized configs count as 1
194		maxAttempts = runner.config.FlakeAttempts
195	}
196
197	for i := 0; i < maxAttempts; i++ {
198		runner.reportSpecWillRun(spec.Summary(runner.suiteID))
199		runner.runningSpec = spec
200		spec.Run(runner.writer)
201		runner.runningSpec = nil
202		runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed())
203		if !spec.Failed() {
204			return true
205		}
206	}
207	return false
208}
209
210func (runner *SpecRunner) CurrentSpecSummary() (*types.SpecSummary, bool) {
211	if runner.runningSpec == nil {
212		return nil, false
213	}
214
215	return runner.runningSpec.Summary(runner.suiteID), true
216}
217
218func (runner *SpecRunner) registerForInterrupts(signalRegistered chan struct{}) {
219	c := make(chan os.Signal, 1)
220	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
221	close(signalRegistered)
222
223	<-c
224	signal.Stop(c)
225	runner.markInterrupted()
226	go runner.registerForHardInterrupts()
227	runner.writer.DumpOutWithHeader(`
228Received interrupt.  Emitting contents of GinkgoWriter...
229---------------------------------------------------------
230`)
231	if runner.afterSuiteNode != nil {
232		fmt.Fprint(os.Stderr, `
233---------------------------------------------------------
234Received interrupt.  Running AfterSuite...
235^C again to terminate immediately
236`)
237		runner.runAfterSuite()
238	}
239	runner.reportSuiteDidEnd(false)
240	os.Exit(1)
241}
242
243func (runner *SpecRunner) registerForHardInterrupts() {
244	c := make(chan os.Signal, 1)
245	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
246
247	<-c
248	fmt.Fprintln(os.Stderr, "\nReceived second interrupt.  Shutting down.")
249	os.Exit(1)
250}
251
252func (runner *SpecRunner) blockForeverIfInterrupted() {
253	runner.lock.Lock()
254	interrupted := runner.interrupted
255	runner.lock.Unlock()
256
257	if interrupted {
258		select {}
259	}
260}
261
262func (runner *SpecRunner) markInterrupted() {
263	runner.lock.Lock()
264	defer runner.lock.Unlock()
265	runner.interrupted = true
266}
267
268func (runner *SpecRunner) wasInterrupted() bool {
269	runner.lock.Lock()
270	defer runner.lock.Unlock()
271	return runner.interrupted
272}
273
274func (runner *SpecRunner) reportSuiteWillBegin() {
275	runner.startTime = time.Now()
276	summary := runner.suiteWillBeginSummary()
277	for _, reporter := range runner.reporters {
278		reporter.SpecSuiteWillBegin(runner.config, summary)
279	}
280}
281
282func (runner *SpecRunner) reportBeforeSuite(summary *types.SetupSummary) {
283	for _, reporter := range runner.reporters {
284		reporter.BeforeSuiteDidRun(summary)
285	}
286}
287
288func (runner *SpecRunner) reportAfterSuite(summary *types.SetupSummary) {
289	for _, reporter := range runner.reporters {
290		reporter.AfterSuiteDidRun(summary)
291	}
292}
293
294func (runner *SpecRunner) reportSpecWillRun(summary *types.SpecSummary) {
295	runner.writer.Truncate()
296
297	for _, reporter := range runner.reporters {
298		reporter.SpecWillRun(summary)
299	}
300}
301
302func (runner *SpecRunner) reportSpecDidComplete(summary *types.SpecSummary, failed bool) {
303	if len(summary.CapturedOutput) == 0 {
304		summary.CapturedOutput = string(runner.writer.Bytes())
305	}
306	for i := len(runner.reporters) - 1; i >= 1; i-- {
307		runner.reporters[i].SpecDidComplete(summary)
308	}
309
310	if failed {
311		runner.writer.DumpOut()
312	}
313
314	runner.reporters[0].SpecDidComplete(summary)
315}
316
317func (runner *SpecRunner) reportSuiteDidEnd(success bool) {
318	summary := runner.suiteDidEndSummary(success)
319	summary.RunTime = time.Since(runner.startTime)
320	for _, reporter := range runner.reporters {
321		reporter.SpecSuiteDidEnd(summary)
322	}
323}
324
325func (runner *SpecRunner) countSpecsThatRanSatisfying(filter func(ex *spec.Spec) bool) (count int) {
326	count = 0
327
328	for _, spec := range runner.processedSpecs {
329		if filter(spec) {
330			count++
331		}
332	}
333
334	return count
335}
336
337func (runner *SpecRunner) suiteDidEndSummary(success bool) *types.SuiteSummary {
338	numberOfSpecsThatWillBeRun := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
339		return !ex.Skipped() && !ex.Pending()
340	})
341
342	numberOfPendingSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
343		return ex.Pending()
344	})
345
346	numberOfSkippedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
347		return ex.Skipped()
348	})
349
350	numberOfPassedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
351		return ex.Passed()
352	})
353
354	numberOfFlakedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
355		return ex.Flaked()
356	})
357
358	numberOfFailedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool {
359		return ex.Failed()
360	})
361
362	if runner.beforeSuiteNode != nil && !runner.beforeSuiteNode.Passed() && !runner.config.DryRun {
363		var known bool
364		numberOfSpecsThatWillBeRun, known = runner.iterator.NumberOfSpecsThatWillBeRunIfKnown()
365		if !known {
366			numberOfSpecsThatWillBeRun = runner.iterator.NumberOfSpecsPriorToIteration()
367		}
368		numberOfFailedSpecs = numberOfSpecsThatWillBeRun
369	}
370
371	return &types.SuiteSummary{
372		SuiteDescription: runner.description,
373		SuiteSucceeded:   success,
374		SuiteID:          runner.suiteID,
375
376		NumberOfSpecsBeforeParallelization: runner.iterator.NumberOfSpecsPriorToIteration(),
377		NumberOfTotalSpecs:                 len(runner.processedSpecs),
378		NumberOfSpecsThatWillBeRun:         numberOfSpecsThatWillBeRun,
379		NumberOfPendingSpecs:               numberOfPendingSpecs,
380		NumberOfSkippedSpecs:               numberOfSkippedSpecs,
381		NumberOfPassedSpecs:                numberOfPassedSpecs,
382		NumberOfFailedSpecs:                numberOfFailedSpecs,
383		NumberOfFlakedSpecs:                numberOfFlakedSpecs,
384	}
385}
386
387func (runner *SpecRunner) suiteWillBeginSummary() *types.SuiteSummary {
388	numTotal, known := runner.iterator.NumberOfSpecsToProcessIfKnown()
389	if !known {
390		numTotal = -1
391	}
392
393	numToRun, known := runner.iterator.NumberOfSpecsThatWillBeRunIfKnown()
394	if !known {
395		numToRun = -1
396	}
397
398	return &types.SuiteSummary{
399		SuiteDescription: runner.description,
400		SuiteID:          runner.suiteID,
401
402		NumberOfSpecsBeforeParallelization: runner.iterator.NumberOfSpecsPriorToIteration(),
403		NumberOfTotalSpecs:                 numTotal,
404		NumberOfSpecsThatWillBeRun:         numToRun,
405		NumberOfPendingSpecs:               -1,
406		NumberOfSkippedSpecs:               -1,
407		NumberOfPassedSpecs:                -1,
408		NumberOfFailedSpecs:                -1,
409		NumberOfFlakedSpecs:                -1,
410	}
411}