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}