arnaucube
arnaucube/mirror-to-giteaPublic Self-hosted repository
mirror-to-gitea/vendor/github.com/onsi/ginkgo/internal/suite/suite.go
vendor/github.com/onsi/ginkgo/internal/suite/suite.goRaw
  1package suite
  2
  3import (
  4	"math/rand"
  5	"net/http"
  6	"time"
  7
  8	"github.com/onsi/ginkgo/internal/spec_iterator"
  9
 10	"github.com/onsi/ginkgo/config"
 11	"github.com/onsi/ginkgo/internal/containernode"
 12	"github.com/onsi/ginkgo/internal/failer"
 13	"github.com/onsi/ginkgo/internal/leafnodes"
 14	"github.com/onsi/ginkgo/internal/spec"
 15	"github.com/onsi/ginkgo/internal/specrunner"
 16	"github.com/onsi/ginkgo/internal/writer"
 17	"github.com/onsi/ginkgo/reporters"
 18	"github.com/onsi/ginkgo/types"
 19)
 20
 21type ginkgoTestingT interface {
 22	Fail()
 23}
 24
 25type deferredContainerNode struct {
 26	text         string
 27	body         func()
 28	flag         types.FlagType
 29	codeLocation types.CodeLocation
 30}
 31
 32type Suite struct {
 33	topLevelContainer *containernode.ContainerNode
 34	currentContainer  *containernode.ContainerNode
 35
 36	deferredContainerNodes []deferredContainerNode
 37
 38	containerIndex      int
 39	beforeSuiteNode     leafnodes.SuiteNode
 40	afterSuiteNode      leafnodes.SuiteNode
 41	runner              *specrunner.SpecRunner
 42	failer              *failer.Failer
 43	running             bool
 44	expandTopLevelNodes bool
 45}
 46
 47func New(failer *failer.Failer) *Suite {
 48	topLevelContainer := containernode.New("[Top Level]", types.FlagTypeNone, types.CodeLocation{})
 49
 50	return &Suite{
 51		topLevelContainer:      topLevelContainer,
 52		currentContainer:       topLevelContainer,
 53		failer:                 failer,
 54		containerIndex:         1,
 55		deferredContainerNodes: []deferredContainerNode{},
 56	}
 57}
 58
 59func (suite *Suite) Run(t ginkgoTestingT, description string, reporters []reporters.Reporter, writer writer.WriterInterface, config config.GinkgoConfigType) (bool, bool) {
 60	if config.ParallelTotal < 1 {
 61		panic("ginkgo.parallel.total must be >= 1")
 62	}
 63
 64	if config.ParallelNode > config.ParallelTotal || config.ParallelNode < 1 {
 65		panic("ginkgo.parallel.node is one-indexed and must be <= ginkgo.parallel.total")
 66	}
 67
 68	suite.expandTopLevelNodes = true
 69	for _, deferredNode := range suite.deferredContainerNodes {
 70		suite.PushContainerNode(deferredNode.text, deferredNode.body, deferredNode.flag, deferredNode.codeLocation)
 71	}
 72
 73	r := rand.New(rand.NewSource(config.RandomSeed))
 74	suite.topLevelContainer.Shuffle(r)
 75	iterator, hasProgrammaticFocus := suite.generateSpecsIterator(description, config)
 76	suite.runner = specrunner.New(description, suite.beforeSuiteNode, iterator, suite.afterSuiteNode, reporters, writer, config)
 77
 78	suite.running = true
 79	success := suite.runner.Run()
 80	if !success {
 81		t.Fail()
 82	}
 83	return success, hasProgrammaticFocus
 84}
 85
 86func (suite *Suite) generateSpecsIterator(description string, config config.GinkgoConfigType) (spec_iterator.SpecIterator, bool) {
 87	specsSlice := []*spec.Spec{}
 88	suite.topLevelContainer.BackPropagateProgrammaticFocus()
 89	for _, collatedNodes := range suite.topLevelContainer.Collate() {
 90		specsSlice = append(specsSlice, spec.New(collatedNodes.Subject, collatedNodes.Containers, config.EmitSpecProgress))
 91	}
 92
 93	specs := spec.NewSpecs(specsSlice)
 94	specs.RegexScansFilePath = config.RegexScansFilePath
 95
 96	if config.RandomizeAllSpecs {
 97		specs.Shuffle(rand.New(rand.NewSource(config.RandomSeed)))
 98	}
 99
100	specs.ApplyFocus(description, config.FocusStrings, config.SkipStrings)
101
102	if config.SkipMeasurements {
103		specs.SkipMeasurements()
104	}
105
106	var iterator spec_iterator.SpecIterator
107
108	if config.ParallelTotal > 1 {
109		iterator = spec_iterator.NewParallelIterator(specs.Specs(), config.SyncHost)
110		resp, err := http.Get(config.SyncHost + "/has-counter")
111		if err != nil || resp.StatusCode != http.StatusOK {
112			iterator = spec_iterator.NewShardedParallelIterator(specs.Specs(), config.ParallelTotal, config.ParallelNode)
113		}
114	} else {
115		iterator = spec_iterator.NewSerialIterator(specs.Specs())
116	}
117
118	return iterator, specs.HasProgrammaticFocus()
119}
120
121func (suite *Suite) CurrentRunningSpecSummary() (*types.SpecSummary, bool) {
122	if !suite.running {
123		return nil, false
124	}
125	return suite.runner.CurrentSpecSummary()
126}
127
128func (suite *Suite) SetBeforeSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
129	if suite.beforeSuiteNode != nil {
130		panic("You may only call BeforeSuite once!")
131	}
132	suite.beforeSuiteNode = leafnodes.NewBeforeSuiteNode(body, codeLocation, timeout, suite.failer)
133}
134
135func (suite *Suite) SetAfterSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
136	if suite.afterSuiteNode != nil {
137		panic("You may only call AfterSuite once!")
138	}
139	suite.afterSuiteNode = leafnodes.NewAfterSuiteNode(body, codeLocation, timeout, suite.failer)
140}
141
142func (suite *Suite) SetSynchronizedBeforeSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
143	if suite.beforeSuiteNode != nil {
144		panic("You may only call BeforeSuite once!")
145	}
146	suite.beforeSuiteNode = leafnodes.NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer)
147}
148
149func (suite *Suite) SetSynchronizedAfterSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
150	if suite.afterSuiteNode != nil {
151		panic("You may only call AfterSuite once!")
152	}
153	suite.afterSuiteNode = leafnodes.NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer)
154}
155
156func (suite *Suite) PushContainerNode(text string, body func(), flag types.FlagType, codeLocation types.CodeLocation) {
157	/*
158		We defer walking the container nodes (which immediately evaluates the `body` function)
159		until `RunSpecs` is called.  We do this by storing off the deferred container nodes.  Then, when
160		`RunSpecs` is called we actually go through and add the container nodes to the test structure.
161
162		This allows us to defer calling all the `body` functions until _after_ the top level functions
163		have been walked, _after_ func init()s have been called, and _after_ `go test` has called `flag.Parse()`.
164
165		This allows users to load up configuration information in the `TestX` go test hook just before `RunSpecs`
166		is invoked and solves issues like #693 and makes the lifecycle easier to reason about.
167
168	*/
169	if !suite.expandTopLevelNodes {
170		suite.deferredContainerNodes = append(suite.deferredContainerNodes, deferredContainerNode{text, body, flag, codeLocation})
171		return
172	}
173
174	container := containernode.New(text, flag, codeLocation)
175	suite.currentContainer.PushContainerNode(container)
176
177	previousContainer := suite.currentContainer
178	suite.currentContainer = container
179	suite.containerIndex++
180
181	body()
182
183	suite.containerIndex--
184	suite.currentContainer = previousContainer
185}
186
187func (suite *Suite) PushItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration) {
188	if suite.running {
189		suite.failer.Fail("You may only call It from within a Describe, Context or When", codeLocation)
190	}
191	suite.currentContainer.PushSubjectNode(leafnodes.NewItNode(text, body, flag, codeLocation, timeout, suite.failer, suite.containerIndex))
192}
193
194func (suite *Suite) PushMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int) {
195	if suite.running {
196		suite.failer.Fail("You may only call Measure from within a Describe, Context or When", codeLocation)
197	}
198	suite.currentContainer.PushSubjectNode(leafnodes.NewMeasureNode(text, body, flag, codeLocation, samples, suite.failer, suite.containerIndex))
199}
200
201func (suite *Suite) PushBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
202	if suite.running {
203		suite.failer.Fail("You may only call BeforeEach from within a Describe, Context or When", codeLocation)
204	}
205	suite.currentContainer.PushSetupNode(leafnodes.NewBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
206}
207
208func (suite *Suite) PushJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
209	if suite.running {
210		suite.failer.Fail("You may only call JustBeforeEach from within a Describe, Context or When", codeLocation)
211	}
212	suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
213}
214
215func (suite *Suite) PushJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
216	if suite.running {
217		suite.failer.Fail("You may only call JustAfterEach from within a Describe or Context", codeLocation)
218	}
219	suite.currentContainer.PushSetupNode(leafnodes.NewJustAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
220}
221
222func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
223	if suite.running {
224		suite.failer.Fail("You may only call AfterEach from within a Describe, Context or When", codeLocation)
225	}
226	suite.currentContainer.PushSetupNode(leafnodes.NewAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
227}