| package suite | 
 |  | 
 | import ( | 
 | 	"math/rand" | 
 | 	"net/http" | 
 | 	"time" | 
 |  | 
 | 	"github.com/onsi/ginkgo/internal/spec_iterator" | 
 |  | 
 | 	"github.com/onsi/ginkgo/config" | 
 | 	"github.com/onsi/ginkgo/internal/containernode" | 
 | 	"github.com/onsi/ginkgo/internal/failer" | 
 | 	"github.com/onsi/ginkgo/internal/leafnodes" | 
 | 	"github.com/onsi/ginkgo/internal/spec" | 
 | 	"github.com/onsi/ginkgo/internal/specrunner" | 
 | 	"github.com/onsi/ginkgo/internal/writer" | 
 | 	"github.com/onsi/ginkgo/reporters" | 
 | 	"github.com/onsi/ginkgo/types" | 
 | ) | 
 |  | 
 | type ginkgoTestingT interface { | 
 | 	Fail() | 
 | } | 
 |  | 
 | type Suite struct { | 
 | 	topLevelContainer *containernode.ContainerNode | 
 | 	currentContainer  *containernode.ContainerNode | 
 | 	containerIndex    int | 
 | 	beforeSuiteNode   leafnodes.SuiteNode | 
 | 	afterSuiteNode    leafnodes.SuiteNode | 
 | 	runner            *specrunner.SpecRunner | 
 | 	failer            *failer.Failer | 
 | 	running           bool | 
 | } | 
 |  | 
 | func New(failer *failer.Failer) *Suite { | 
 | 	topLevelContainer := containernode.New("[Top Level]", types.FlagTypeNone, types.CodeLocation{}) | 
 |  | 
 | 	return &Suite{ | 
 | 		topLevelContainer: topLevelContainer, | 
 | 		currentContainer:  topLevelContainer, | 
 | 		failer:            failer, | 
 | 		containerIndex:    1, | 
 | 	} | 
 | } | 
 |  | 
 | func (suite *Suite) Run(t ginkgoTestingT, description string, reporters []reporters.Reporter, writer writer.WriterInterface, config config.GinkgoConfigType) (bool, bool) { | 
 | 	if config.ParallelTotal < 1 { | 
 | 		panic("ginkgo.parallel.total must be >= 1") | 
 | 	} | 
 |  | 
 | 	if config.ParallelNode > config.ParallelTotal || config.ParallelNode < 1 { | 
 | 		panic("ginkgo.parallel.node is one-indexed and must be <= ginkgo.parallel.total") | 
 | 	} | 
 |  | 
 | 	r := rand.New(rand.NewSource(config.RandomSeed)) | 
 | 	suite.topLevelContainer.Shuffle(r) | 
 | 	iterator, hasProgrammaticFocus := suite.generateSpecsIterator(description, config) | 
 | 	suite.runner = specrunner.New(description, suite.beforeSuiteNode, iterator, suite.afterSuiteNode, reporters, writer, config) | 
 |  | 
 | 	suite.running = true | 
 | 	success := suite.runner.Run() | 
 | 	if !success { | 
 | 		t.Fail() | 
 | 	} | 
 | 	return success, hasProgrammaticFocus | 
 | } | 
 |  | 
 | func (suite *Suite) generateSpecsIterator(description string, config config.GinkgoConfigType) (spec_iterator.SpecIterator, bool) { | 
 | 	specsSlice := []*spec.Spec{} | 
 | 	suite.topLevelContainer.BackPropagateProgrammaticFocus() | 
 | 	for _, collatedNodes := range suite.topLevelContainer.Collate() { | 
 | 		specsSlice = append(specsSlice, spec.New(collatedNodes.Subject, collatedNodes.Containers, config.EmitSpecProgress)) | 
 | 	} | 
 |  | 
 | 	specs := spec.NewSpecs(specsSlice) | 
 | 	specs.RegexScansFilePath = config.RegexScansFilePath | 
 |  | 
 | 	if config.RandomizeAllSpecs { | 
 | 		specs.Shuffle(rand.New(rand.NewSource(config.RandomSeed))) | 
 | 	} | 
 |  | 
 | 	specs.ApplyFocus(description, config.FocusString, config.SkipString) | 
 |  | 
 | 	if config.SkipMeasurements { | 
 | 		specs.SkipMeasurements() | 
 | 	} | 
 |  | 
 | 	var iterator spec_iterator.SpecIterator | 
 |  | 
 | 	if config.ParallelTotal > 1 { | 
 | 		iterator = spec_iterator.NewParallelIterator(specs.Specs(), config.SyncHost) | 
 | 		resp, err := http.Get(config.SyncHost + "/has-counter") | 
 | 		if err != nil || resp.StatusCode != http.StatusOK { | 
 | 			iterator = spec_iterator.NewShardedParallelIterator(specs.Specs(), config.ParallelTotal, config.ParallelNode) | 
 | 		} | 
 | 	} else { | 
 | 		iterator = spec_iterator.NewSerialIterator(specs.Specs()) | 
 | 	} | 
 |  | 
 | 	return iterator, specs.HasProgrammaticFocus() | 
 | } | 
 |  | 
 | func (suite *Suite) CurrentRunningSpecSummary() (*types.SpecSummary, bool) { | 
 | 	return suite.runner.CurrentSpecSummary() | 
 | } | 
 |  | 
 | func (suite *Suite) SetBeforeSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.beforeSuiteNode != nil { | 
 | 		panic("You may only call BeforeSuite once!") | 
 | 	} | 
 | 	suite.beforeSuiteNode = leafnodes.NewBeforeSuiteNode(body, codeLocation, timeout, suite.failer) | 
 | } | 
 |  | 
 | func (suite *Suite) SetAfterSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.afterSuiteNode != nil { | 
 | 		panic("You may only call AfterSuite once!") | 
 | 	} | 
 | 	suite.afterSuiteNode = leafnodes.NewAfterSuiteNode(body, codeLocation, timeout, suite.failer) | 
 | } | 
 |  | 
 | func (suite *Suite) SetSynchronizedBeforeSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.beforeSuiteNode != nil { | 
 | 		panic("You may only call BeforeSuite once!") | 
 | 	} | 
 | 	suite.beforeSuiteNode = leafnodes.NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer) | 
 | } | 
 |  | 
 | func (suite *Suite) SetSynchronizedAfterSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.afterSuiteNode != nil { | 
 | 		panic("You may only call AfterSuite once!") | 
 | 	} | 
 | 	suite.afterSuiteNode = leafnodes.NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer) | 
 | } | 
 |  | 
 | func (suite *Suite) PushContainerNode(text string, body func(), flag types.FlagType, codeLocation types.CodeLocation) { | 
 | 	container := containernode.New(text, flag, codeLocation) | 
 | 	suite.currentContainer.PushContainerNode(container) | 
 |  | 
 | 	previousContainer := suite.currentContainer | 
 | 	suite.currentContainer = container | 
 | 	suite.containerIndex++ | 
 |  | 
 | 	body() | 
 |  | 
 | 	suite.containerIndex-- | 
 | 	suite.currentContainer = previousContainer | 
 | } | 
 |  | 
 | func (suite *Suite) PushItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.running { | 
 | 		suite.failer.Fail("You may only call It from within a Describe or Context", codeLocation) | 
 | 	} | 
 | 	suite.currentContainer.PushSubjectNode(leafnodes.NewItNode(text, body, flag, codeLocation, timeout, suite.failer, suite.containerIndex)) | 
 | } | 
 |  | 
 | func (suite *Suite) PushMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int) { | 
 | 	if suite.running { | 
 | 		suite.failer.Fail("You may only call Measure from within a Describe or Context", codeLocation) | 
 | 	} | 
 | 	suite.currentContainer.PushSubjectNode(leafnodes.NewMeasureNode(text, body, flag, codeLocation, samples, suite.failer, suite.containerIndex)) | 
 | } | 
 |  | 
 | func (suite *Suite) PushBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.running { | 
 | 		suite.failer.Fail("You may only call BeforeEach from within a Describe or Context", codeLocation) | 
 | 	} | 
 | 	suite.currentContainer.PushSetupNode(leafnodes.NewBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) | 
 | } | 
 |  | 
 | func (suite *Suite) PushJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.running { | 
 | 		suite.failer.Fail("You may only call JustBeforeEach from within a Describe or Context", codeLocation) | 
 | 	} | 
 | 	suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) | 
 | } | 
 |  | 
 | func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { | 
 | 	if suite.running { | 
 | 		suite.failer.Fail("You may only call AfterEach from within a Describe or Context", codeLocation) | 
 | 	} | 
 | 	suite.currentContainer.PushSetupNode(leafnodes.NewAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) | 
 | } |