arnaucube
arnaucube/mirror-to-giteaPublic Self-hosted repository
mirror-to-gitea/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
vendor/github.com/onsi/ginkgo/ginkgo_dsl.goRaw
  1/*
  2Ginkgo is a BDD-style testing framework for Golang
  3
  4The godoc documentation describes Ginkgo's API.  More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo/
  5
  6Ginkgo's preferred matcher library is [Gomega](http://github.com/onsi/gomega)
  7
  8Ginkgo on Github: http://github.com/onsi/ginkgo
  9
 10Ginkgo is MIT-Licensed
 11*/
 12package ginkgo
 13
 14import (
 15	"flag"
 16	"fmt"
 17	"io"
 18	"net/http"
 19	"os"
 20	"reflect"
 21	"strings"
 22	"time"
 23
 24	"github.com/onsi/ginkgo/config"
 25	"github.com/onsi/ginkgo/internal/codelocation"
 26	"github.com/onsi/ginkgo/internal/global"
 27	"github.com/onsi/ginkgo/internal/remote"
 28	"github.com/onsi/ginkgo/internal/testingtproxy"
 29	"github.com/onsi/ginkgo/internal/writer"
 30	"github.com/onsi/ginkgo/reporters"
 31	"github.com/onsi/ginkgo/reporters/stenographer"
 32	colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable"
 33	"github.com/onsi/ginkgo/types"
 34)
 35
 36var deprecationTracker = types.NewDeprecationTracker()
 37
 38const GINKGO_VERSION = config.VERSION
 39const GINKGO_PANIC = `
 40Your test failed.
 41Ginkgo panics to prevent subsequent assertions from running.
 42Normally Ginkgo rescues this panic so you shouldn't see it.
 43
 44But, if you make an assertion in a goroutine, Ginkgo can't capture the panic.
 45To circumvent this, you should call
 46
 47	defer GinkgoRecover()
 48
 49at the top of the goroutine that caused this panic.
 50`
 51
 52func init() {
 53	config.Flags(flag.CommandLine, "ginkgo", true)
 54	GinkgoWriter = writer.New(os.Stdout)
 55}
 56
 57//GinkgoWriter implements an io.Writer
 58//When running in verbose mode any writes to GinkgoWriter will be immediately printed
 59//to stdout.  Otherwise, GinkgoWriter will buffer any writes produced during the current test and flush them to screen
 60//only if the current test fails.
 61var GinkgoWriter io.Writer
 62
 63//The interface by which Ginkgo receives *testing.T
 64type GinkgoTestingT interface {
 65	Fail()
 66}
 67
 68//GinkgoRandomSeed returns the seed used to randomize spec execution order.  It is
 69//useful for seeding your own pseudorandom number generators (PRNGs) to ensure
 70//consistent executions from run to run, where your tests contain variability (for
 71//example, when selecting random test data).
 72func GinkgoRandomSeed() int64 {
 73	return config.GinkgoConfig.RandomSeed
 74}
 75
 76//GinkgoParallelNode returns the parallel node number for the current ginkgo process
 77//The node number is 1-indexed
 78func GinkgoParallelNode() int {
 79	return config.GinkgoConfig.ParallelNode
 80}
 81
 82//Some matcher libraries or legacy codebases require a *testing.T
 83//GinkgoT implements an interface analogous to *testing.T and can be used if
 84//the library in question accepts *testing.T through an interface
 85//
 86// For example, with testify:
 87// assert.Equal(GinkgoT(), 123, 123, "they should be equal")
 88//
 89// Or with gomock:
 90// gomock.NewController(GinkgoT())
 91//
 92// GinkgoT() takes an optional offset argument that can be used to get the
 93// correct line number associated with the failure.
 94func GinkgoT(optionalOffset ...int) GinkgoTInterface {
 95	offset := 3
 96	if len(optionalOffset) > 0 {
 97		offset = optionalOffset[0]
 98	}
 99	failedFunc := func() bool {
100		return CurrentGinkgoTestDescription().Failed
101	}
102	nameFunc := func() string {
103		return CurrentGinkgoTestDescription().FullTestText
104	}
105	return testingtproxy.New(GinkgoWriter, Fail, Skip, failedFunc, nameFunc, offset)
106}
107
108//The interface returned by GinkgoT().  This covers most of the methods
109//in the testing package's T.
110type GinkgoTInterface interface {
111	Cleanup(func())
112	Error(args ...interface{})
113	Errorf(format string, args ...interface{})
114	Fail()
115	FailNow()
116	Failed() bool
117	Fatal(args ...interface{})
118	Fatalf(format string, args ...interface{})
119	Helper()
120	Log(args ...interface{})
121	Logf(format string, args ...interface{})
122	Name() string
123	Parallel()
124	Skip(args ...interface{})
125	SkipNow()
126	Skipf(format string, args ...interface{})
127	Skipped() bool
128	TempDir() string
129}
130
131//Custom Ginkgo test reporters must implement the Reporter interface.
132//
133//The custom reporter is passed in a SuiteSummary when the suite begins and ends,
134//and a SpecSummary just before a spec begins and just after a spec ends
135type Reporter reporters.Reporter
136
137//Asynchronous specs are given a channel of the Done type.  You must close or write to the channel
138//to tell Ginkgo that your async test is done.
139type Done chan<- interface{}
140
141//GinkgoTestDescription represents the information about the current running test returned by CurrentGinkgoTestDescription
142//	FullTestText: a concatenation of ComponentTexts and the TestText
143//	ComponentTexts: a list of all texts for the Describes & Contexts leading up to the current test
144//	TestText: the text in the actual It or Measure node
145//	IsMeasurement: true if the current test is a measurement
146//	FileName: the name of the file containing the current test
147//	LineNumber: the line number for the current test
148//	Failed: if the current test has failed, this will be true (useful in an AfterEach)
149type GinkgoTestDescription struct {
150	FullTestText   string
151	ComponentTexts []string
152	TestText       string
153
154	IsMeasurement bool
155
156	FileName   string
157	LineNumber int
158
159	Failed   bool
160	Duration time.Duration
161}
162
163//CurrentGinkgoTestDescripton returns information about the current running test.
164func CurrentGinkgoTestDescription() GinkgoTestDescription {
165	summary, ok := global.Suite.CurrentRunningSpecSummary()
166	if !ok {
167		return GinkgoTestDescription{}
168	}
169
170	subjectCodeLocation := summary.ComponentCodeLocations[len(summary.ComponentCodeLocations)-1]
171
172	return GinkgoTestDescription{
173		ComponentTexts: summary.ComponentTexts[1:],
174		FullTestText:   strings.Join(summary.ComponentTexts[1:], " "),
175		TestText:       summary.ComponentTexts[len(summary.ComponentTexts)-1],
176		IsMeasurement:  summary.IsMeasurement,
177		FileName:       subjectCodeLocation.FileName,
178		LineNumber:     subjectCodeLocation.LineNumber,
179		Failed:         summary.HasFailureState(),
180		Duration:       summary.RunTime,
181	}
182}
183
184//Measurement tests receive a Benchmarker.
185//
186//You use the Time() function to time how long the passed in body function takes to run
187//You use the RecordValue() function to track arbitrary numerical measurements.
188//The RecordValueWithPrecision() function can be used alternatively to provide the unit
189//and resolution of the numeric measurement.
190//The optional info argument is passed to the test reporter and can be used to
191// provide the measurement data to a custom reporter with context.
192//
193//See http://onsi.github.io/ginkgo/#benchmark_tests for more details
194type Benchmarker interface {
195	Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration)
196	RecordValue(name string, value float64, info ...interface{})
197	RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{})
198}
199
200//RunSpecs is the entry point for the Ginkgo test runner.
201//You must call this within a Golang testing TestX(t *testing.T) function.
202//
203//To bootstrap a test suite you can use the Ginkgo CLI:
204//
205//	ginkgo bootstrap
206func RunSpecs(t GinkgoTestingT, description string) bool {
207	specReporters := []Reporter{buildDefaultReporter()}
208	if config.DefaultReporterConfig.ReportFile != "" {
209		reportFile := config.DefaultReporterConfig.ReportFile
210		specReporters[0] = reporters.NewJUnitReporter(reportFile)
211		specReporters = append(specReporters, buildDefaultReporter())
212	}
213	return runSpecsWithCustomReporters(t, description, specReporters)
214}
215
216//To run your tests with Ginkgo's default reporter and your custom reporter(s), replace
217//RunSpecs() with this method.
218func RunSpecsWithDefaultAndCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
219	deprecationTracker.TrackDeprecation(types.Deprecations.CustomReporter())
220	specReporters = append(specReporters, buildDefaultReporter())
221	return runSpecsWithCustomReporters(t, description, specReporters)
222}
223
224//To run your tests with your custom reporter(s) (and *not* Ginkgo's default reporter), replace
225//RunSpecs() with this method.  Note that parallel tests will not work correctly without the default reporter
226func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
227	deprecationTracker.TrackDeprecation(types.Deprecations.CustomReporter())
228	return runSpecsWithCustomReporters(t, description, specReporters)
229}
230
231func runSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
232	writer := GinkgoWriter.(*writer.Writer)
233	writer.SetStream(config.DefaultReporterConfig.Verbose)
234	reporters := make([]reporters.Reporter, len(specReporters))
235	for i, reporter := range specReporters {
236		reporters[i] = reporter
237	}
238	passed, hasFocusedTests := global.Suite.Run(t, description, reporters, writer, config.GinkgoConfig)
239
240	if deprecationTracker.DidTrackDeprecations() {
241		fmt.Fprintln(colorable.NewColorableStderr(), deprecationTracker.DeprecationsReport())
242	}
243
244	if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
245		fmt.Println("PASS | FOCUSED")
246		os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
247	}
248	return passed
249}
250
251func buildDefaultReporter() Reporter {
252	remoteReportingServer := config.GinkgoConfig.StreamHost
253	if remoteReportingServer == "" {
254		stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout())
255		return reporters.NewDefaultReporter(config.DefaultReporterConfig, stenographer)
256	} else {
257		debugFile := ""
258		if config.GinkgoConfig.DebugParallel {
259			debugFile = fmt.Sprintf("ginkgo-node-%d.log", config.GinkgoConfig.ParallelNode)
260		}
261		return remote.NewForwardingReporter(config.DefaultReporterConfig, remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor(), GinkgoWriter.(*writer.Writer), debugFile)
262	}
263}
264
265//Skip notifies Ginkgo that the current spec was skipped.
266func Skip(message string, callerSkip ...int) {
267	skip := 0
268	if len(callerSkip) > 0 {
269		skip = callerSkip[0]
270	}
271
272	global.Failer.Skip(message, codelocation.New(skip+1))
273	panic(GINKGO_PANIC)
274}
275
276//Fail notifies Ginkgo that the current spec has failed. (Gomega will call Fail for you automatically when an assertion fails.)
277func Fail(message string, callerSkip ...int) {
278	skip := 0
279	if len(callerSkip) > 0 {
280		skip = callerSkip[0]
281	}
282
283	global.Failer.Fail(message, codelocation.New(skip+1))
284	panic(GINKGO_PANIC)
285}
286
287//GinkgoRecover should be deferred at the top of any spawned goroutine that (may) call `Fail`
288//Since Gomega assertions call fail, you should throw a `defer GinkgoRecover()` at the top of any goroutine that
289//calls out to Gomega
290//
291//Here's why: Ginkgo's `Fail` method records the failure and then panics to prevent
292//further assertions from running.  This panic must be recovered.  Ginkgo does this for you
293//if the panic originates in a Ginkgo node (an It, BeforeEach, etc...)
294//
295//Unfortunately, if a panic originates on a goroutine *launched* from one of these nodes there's no
296//way for Ginkgo to rescue the panic.  To do this, you must remember to `defer GinkgoRecover()` at the top of such a goroutine.
297func GinkgoRecover() {
298	e := recover()
299	if e != nil {
300		global.Failer.Panic(codelocation.New(1), e)
301	}
302}
303
304//Describe blocks allow you to organize your specs.  A Describe block can contain any number of
305//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
306//
307//In addition you can nest Describe, Context and When blocks.  Describe, Context and When blocks are functionally
308//equivalent.  The difference is purely semantic -- you typically Describe the behavior of an object
309//or method and, within that Describe, outline a number of Contexts and Whens.
310func Describe(text string, body func()) bool {
311	global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
312	return true
313}
314
315//You can focus the tests within a describe block using FDescribe
316func FDescribe(text string, body func()) bool {
317	global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
318	return true
319}
320
321//You can mark the tests within a describe block as pending using PDescribe
322func PDescribe(text string, body func()) bool {
323	global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
324	return true
325}
326
327//You can mark the tests within a describe block as pending using XDescribe
328func XDescribe(text string, body func()) bool {
329	global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
330	return true
331}
332
333//Context blocks allow you to organize your specs.  A Context block can contain any number of
334//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
335//
336//In addition you can nest Describe, Context and When blocks.  Describe, Context and When blocks are functionally
337//equivalent.  The difference is purely semantic -- you typical Describe the behavior of an object
338//or method and, within that Describe, outline a number of Contexts and Whens.
339func Context(text string, body func()) bool {
340	global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
341	return true
342}
343
344//You can focus the tests within a describe block using FContext
345func FContext(text string, body func()) bool {
346	global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
347	return true
348}
349
350//You can mark the tests within a describe block as pending using PContext
351func PContext(text string, body func()) bool {
352	global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
353	return true
354}
355
356//You can mark the tests within a describe block as pending using XContext
357func XContext(text string, body func()) bool {
358	global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
359	return true
360}
361
362//When blocks allow you to organize your specs.  A When block can contain any number of
363//BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks.
364//
365//In addition you can nest Describe, Context and When blocks.  Describe, Context and When blocks are functionally
366//equivalent.  The difference is purely semantic -- you typical Describe the behavior of an object
367//or method and, within that Describe, outline a number of Contexts and Whens.
368func When(text string, body func()) bool {
369	global.Suite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
370	return true
371}
372
373//You can focus the tests within a describe block using FWhen
374func FWhen(text string, body func()) bool {
375	global.Suite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
376	return true
377}
378
379//You can mark the tests within a describe block as pending using PWhen
380func PWhen(text string, body func()) bool {
381	global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
382	return true
383}
384
385//You can mark the tests within a describe block as pending using XWhen
386func XWhen(text string, body func()) bool {
387	global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
388	return true
389}
390
391//It blocks contain your test code and assertions.  You cannot nest any other Ginkgo blocks
392//within an It block.
393//
394//Ginkgo will normally run It blocks synchronously.  To perform asynchronous tests, pass a
395//function that accepts a Done channel.  When you do this, you can also provide an optional timeout.
396func It(text string, body interface{}, timeout ...float64) bool {
397	validateBodyFunc(body, codelocation.New(1))
398	global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
399	return true
400}
401
402//You can focus individual Its using FIt
403func FIt(text string, body interface{}, timeout ...float64) bool {
404	validateBodyFunc(body, codelocation.New(1))
405	global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
406	return true
407}
408
409//You can mark Its as pending using PIt
410func PIt(text string, _ ...interface{}) bool {
411	global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
412	return true
413}
414
415//You can mark Its as pending using XIt
416func XIt(text string, _ ...interface{}) bool {
417	global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
418	return true
419}
420
421//Specify blocks are aliases for It blocks and allow for more natural wording in situations
422//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
423//which apply to It blocks.
424func Specify(text string, body interface{}, timeout ...float64) bool {
425	validateBodyFunc(body, codelocation.New(1))
426	global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
427	return true
428}
429
430//You can focus individual Specifys using FSpecify
431func FSpecify(text string, body interface{}, timeout ...float64) bool {
432	validateBodyFunc(body, codelocation.New(1))
433	global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
434	return true
435}
436
437//You can mark Specifys as pending using PSpecify
438func PSpecify(text string, is ...interface{}) bool {
439	global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
440	return true
441}
442
443//You can mark Specifys as pending using XSpecify
444func XSpecify(text string, is ...interface{}) bool {
445	global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
446	return true
447}
448
449//By allows you to better document large Its.
450//
451//Generally you should try to keep your Its short and to the point.  This is not always possible, however,
452//especially in the context of integration tests that capture a particular workflow.
453//
454//By allows you to document such flows.  By must be called within a runnable node (It, BeforeEach, Measure, etc...)
455//By will simply log the passed in text to the GinkgoWriter.  If By is handed a function it will immediately run the function.
456func By(text string, callbacks ...func()) {
457	preamble := "\x1b[1mSTEP\x1b[0m"
458	if config.DefaultReporterConfig.NoColor {
459		preamble = "STEP"
460	}
461	fmt.Fprintln(GinkgoWriter, preamble+": "+text)
462	if len(callbacks) == 1 {
463		callbacks[0]()
464	}
465	if len(callbacks) > 1 {
466		panic("just one callback per By, please")
467	}
468}
469
470//Measure blocks run the passed in body function repeatedly (determined by the samples argument)
471//and accumulate metrics provided to the Benchmarker by the body function.
472//
473//The body function must have the signature:
474//	func(b Benchmarker)
475func Measure(text string, body interface{}, samples int) bool {
476	global.Suite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
477	return true
478}
479
480//You can focus individual Measures using FMeasure
481func FMeasure(text string, body interface{}, samples int) bool {
482	global.Suite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
483	return true
484}
485
486//You can mark Measurements as pending using PMeasure
487func PMeasure(text string, _ ...interface{}) bool {
488	global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
489	return true
490}
491
492//You can mark Measurements as pending using XMeasure
493func XMeasure(text string, _ ...interface{}) bool {
494	global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
495	return true
496}
497
498//BeforeSuite blocks are run just once before any specs are run.  When running in parallel, each
499//parallel node process will call BeforeSuite.
500//
501//BeforeSuite blocks can be made asynchronous by providing a body function that accepts a Done channel
502//
503//You may only register *one* BeforeSuite handler per test suite.  You typically do so in your bootstrap file at the top level.
504func BeforeSuite(body interface{}, timeout ...float64) bool {
505	validateBodyFunc(body, codelocation.New(1))
506	global.Suite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
507	return true
508}
509
510//AfterSuite blocks are *always* run after all the specs regardless of whether specs have passed or failed.
511//Moreover, if Ginkgo receives an interrupt signal (^C) it will attempt to run the AfterSuite before exiting.
512//
513//When running in parallel, each parallel node process will call AfterSuite.
514//
515//AfterSuite blocks can be made asynchronous by providing a body function that accepts a Done channel
516//
517//You may only register *one* AfterSuite handler per test suite.  You typically do so in your bootstrap file at the top level.
518func AfterSuite(body interface{}, timeout ...float64) bool {
519	validateBodyFunc(body, codelocation.New(1))
520	global.Suite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
521	return true
522}
523
524//SynchronizedBeforeSuite blocks are primarily meant to solve the problem of setting up singleton external resources shared across
525//nodes when running tests in parallel.  For example, say you have a shared database that you can only start one instance of that
526//must be used in your tests.  When running in parallel, only one node should set up the database and all other nodes should wait
527//until that node is done before running.
528//
529//SynchronizedBeforeSuite accomplishes this by taking *two* function arguments.  The first is only run on parallel node #1.  The second is
530//run on all nodes, but *only* after the first function completes successfully.  Ginkgo also makes it possible to send data from the first function (on Node 1)
531//to the second function (on all the other nodes).
532//
533//The functions have the following signatures.  The first function (which only runs on node 1) has the signature:
534//
535//	func() []byte
536//
537//or, to run asynchronously:
538//
539//	func(done Done) []byte
540//
541//The byte array returned by the first function is then passed to the second function, which has the signature:
542//
543//	func(data []byte)
544//
545//or, to run asynchronously:
546//
547//	func(data []byte, done Done)
548//
549//Here's a simple pseudo-code example that starts a shared database on Node 1 and shares the database's address with the other nodes:
550//
551//	var dbClient db.Client
552//	var dbRunner db.Runner
553//
554//	var _ = SynchronizedBeforeSuite(func() []byte {
555//		dbRunner = db.NewRunner()
556//		err := dbRunner.Start()
557//		Ω(err).ShouldNot(HaveOccurred())
558//		return []byte(dbRunner.URL)
559//	}, func(data []byte) {
560//		dbClient = db.NewClient()
561//		err := dbClient.Connect(string(data))
562//		Ω(err).ShouldNot(HaveOccurred())
563//	})
564func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool {
565	global.Suite.SetSynchronizedBeforeSuiteNode(
566		node1Body,
567		allNodesBody,
568		codelocation.New(1),
569		parseTimeout(timeout...),
570	)
571	return true
572}
573
574//SynchronizedAfterSuite blocks complement the SynchronizedBeforeSuite blocks in solving the problem of setting up
575//external singleton resources shared across nodes when running tests in parallel.
576//
577//SynchronizedAfterSuite accomplishes this by taking *two* function arguments.  The first runs on all nodes.  The second runs only on parallel node #1
578//and *only* after all other nodes have finished and exited.  This ensures that node 1, and any resources it is running, remain alive until
579//all other nodes are finished.
580//
581//Both functions have the same signature: either func() or func(done Done) to run asynchronously.
582//
583//Here's a pseudo-code example that complements that given in SynchronizedBeforeSuite.  Here, SynchronizedAfterSuite is used to tear down the shared database
584//only after all nodes have finished:
585//
586//	var _ = SynchronizedAfterSuite(func() {
587//		dbClient.Cleanup()
588//	}, func() {
589//		dbRunner.Stop()
590//	})
591func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool {
592	global.Suite.SetSynchronizedAfterSuiteNode(
593		allNodesBody,
594		node1Body,
595		codelocation.New(1),
596		parseTimeout(timeout...),
597	)
598	return true
599}
600
601//BeforeEach blocks are run before It blocks.  When multiple BeforeEach blocks are defined in nested
602//Describe and Context blocks the outermost BeforeEach blocks are run first.
603//
604//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
605//a Done channel
606func BeforeEach(body interface{}, timeout ...float64) bool {
607	validateBodyFunc(body, codelocation.New(1))
608	global.Suite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
609	return true
610}
611
612//JustBeforeEach blocks are run before It blocks but *after* all BeforeEach blocks.  For more details,
613//read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_)
614//
615//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
616//a Done channel
617func JustBeforeEach(body interface{}, timeout ...float64) bool {
618	validateBodyFunc(body, codelocation.New(1))
619	global.Suite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
620	return true
621}
622
623//JustAfterEach blocks are run after It blocks but *before* all AfterEach blocks.  For more details,
624//read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_)
625//
626//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
627//a Done channel
628func JustAfterEach(body interface{}, timeout ...float64) bool {
629	validateBodyFunc(body, codelocation.New(1))
630	global.Suite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
631	return true
632}
633
634//AfterEach blocks are run after It blocks.   When multiple AfterEach blocks are defined in nested
635//Describe and Context blocks the innermost AfterEach blocks are run first.
636//
637//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
638//a Done channel
639func AfterEach(body interface{}, timeout ...float64) bool {
640	validateBodyFunc(body, codelocation.New(1))
641	global.Suite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
642	return true
643}
644
645func validateBodyFunc(body interface{}, cl types.CodeLocation) {
646	t := reflect.TypeOf(body)
647	if t.Kind() != reflect.Func {
648		return
649	}
650
651	if t.NumOut() > 0 {
652		return
653	}
654
655	if t.NumIn() == 0 {
656		return
657	}
658
659	if t.In(0) == reflect.TypeOf(make(Done)) {
660		deprecationTracker.TrackDeprecation(types.Deprecations.Async(), cl)
661	}
662}
663
664func parseTimeout(timeout ...float64) time.Duration {
665	if len(timeout) == 0 {
666		return global.DefaultTimeout
667	} else {
668		return time.Duration(timeout[0] * float64(time.Second))
669	}
670}