summaryrefslogtreecommitdiff
path: root/vendor/github.com/onsi/ginkgo/internal/leafnodes
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/onsi/ginkgo/internal/leafnodes')
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go103
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/interfaces.go19
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go47
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go22
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go13
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go62
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go155
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go117
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go48
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go48
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go353
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go55
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go230
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go90
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go199
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go181
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go446
17 files changed, 2188 insertions, 0 deletions
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go
new file mode 100644
index 000000000..d6d54234c
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/benchmarker.go
@@ -0,0 +1,103 @@
+package leafnodes
+
+import (
+ "math"
+ "time"
+
+ "sync"
+
+ "github.com/onsi/ginkgo/types"
+)
+
+type benchmarker struct {
+ mu sync.Mutex
+ measurements map[string]*types.SpecMeasurement
+ orderCounter int
+}
+
+func newBenchmarker() *benchmarker {
+ return &benchmarker{
+ measurements: make(map[string]*types.SpecMeasurement, 0),
+ }
+}
+
+func (b *benchmarker) Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration) {
+ t := time.Now()
+ body()
+ elapsedTime = time.Since(t)
+
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ measurement := b.getMeasurement(name, "Fastest Time", "Slowest Time", "Average Time", "s", 3, info...)
+ measurement.Results = append(measurement.Results, elapsedTime.Seconds())
+
+ return
+}
+
+func (b *benchmarker) RecordValue(name string, value float64, info ...interface{}) {
+ b.mu.Lock()
+ measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", 3, info...)
+ defer b.mu.Unlock()
+ measurement.Results = append(measurement.Results, value)
+}
+
+func (b *benchmarker) RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{}) {
+ b.mu.Lock()
+ measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", units, precision, info...)
+ defer b.mu.Unlock()
+ measurement.Results = append(measurement.Results, value)
+}
+
+func (b *benchmarker) getMeasurement(name string, smallestLabel string, largestLabel string, averageLabel string, units string, precision int, info ...interface{}) *types.SpecMeasurement {
+ measurement, ok := b.measurements[name]
+ if !ok {
+ var computedInfo interface{}
+ computedInfo = nil
+ if len(info) > 0 {
+ computedInfo = info[0]
+ }
+ measurement = &types.SpecMeasurement{
+ Name: name,
+ Info: computedInfo,
+ Order: b.orderCounter,
+ SmallestLabel: smallestLabel,
+ LargestLabel: largestLabel,
+ AverageLabel: averageLabel,
+ Units: units,
+ Precision: precision,
+ Results: make([]float64, 0),
+ }
+ b.measurements[name] = measurement
+ b.orderCounter++
+ }
+
+ return measurement
+}
+
+func (b *benchmarker) measurementsReport() map[string]*types.SpecMeasurement {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ for _, measurement := range b.measurements {
+ measurement.Smallest = math.MaxFloat64
+ measurement.Largest = -math.MaxFloat64
+ sum := float64(0)
+ sumOfSquares := float64(0)
+
+ for _, result := range measurement.Results {
+ if result > measurement.Largest {
+ measurement.Largest = result
+ }
+ if result < measurement.Smallest {
+ measurement.Smallest = result
+ }
+ sum += result
+ sumOfSquares += result * result
+ }
+
+ n := float64(len(measurement.Results))
+ measurement.Average = sum / n
+ measurement.StdDeviation = math.Sqrt(sumOfSquares/n - (sum/n)*(sum/n))
+ }
+
+ return b.measurements
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/interfaces.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/interfaces.go
new file mode 100644
index 000000000..8c3902d60
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/interfaces.go
@@ -0,0 +1,19 @@
+package leafnodes
+
+import (
+ "github.com/onsi/ginkgo/types"
+)
+
+type BasicNode interface {
+ Type() types.SpecComponentType
+ Run() (types.SpecState, types.SpecFailure)
+ CodeLocation() types.CodeLocation
+}
+
+type SubjectNode interface {
+ BasicNode
+
+ Text() string
+ Flag() types.FlagType
+ Samples() int
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go
new file mode 100644
index 000000000..6eded7b76
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node.go
@@ -0,0 +1,47 @@
+package leafnodes
+
+import (
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type ItNode struct {
+ runner *runner
+
+ flag types.FlagType
+ text string
+}
+
+func NewItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *ItNode {
+ return &ItNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeIt, componentIndex),
+ flag: flag,
+ text: text,
+ }
+}
+
+func (node *ItNode) Run() (outcome types.SpecState, failure types.SpecFailure) {
+ return node.runner.run()
+}
+
+func (node *ItNode) Type() types.SpecComponentType {
+ return types.SpecComponentTypeIt
+}
+
+func (node *ItNode) Text() string {
+ return node.text
+}
+
+func (node *ItNode) Flag() types.FlagType {
+ return node.flag
+}
+
+func (node *ItNode) CodeLocation() types.CodeLocation {
+ return node.runner.codeLocation
+}
+
+func (node *ItNode) Samples() int {
+ return 1
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go
new file mode 100644
index 000000000..29fa0c6e2
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go
@@ -0,0 +1,22 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+ . "github.com/onsi/gomega"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ "github.com/onsi/ginkgo/types"
+)
+
+var _ = Describe("It Nodes", func() {
+ It("should report the correct type, text, flag, and code location", func() {
+ codeLocation := codelocation.New(0)
+ it := NewItNode("my it node", func() {}, types.FlagTypeFocused, codeLocation, 0, nil, 3)
+ Ω(it.Type()).Should(Equal(types.SpecComponentTypeIt))
+ Ω(it.Flag()).Should(Equal(types.FlagTypeFocused))
+ Ω(it.Text()).Should(Equal("my it node"))
+ Ω(it.CodeLocation()).Should(Equal(codeLocation))
+ Ω(it.Samples()).Should(Equal(1))
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go
new file mode 100644
index 000000000..a7ba9e006
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go
@@ -0,0 +1,13 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestLeafNode(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "LeafNode Suite")
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go
new file mode 100644
index 000000000..3ab9a6d55
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node.go
@@ -0,0 +1,62 @@
+package leafnodes
+
+import (
+ "reflect"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type MeasureNode struct {
+ runner *runner
+
+ text string
+ flag types.FlagType
+ samples int
+ benchmarker *benchmarker
+}
+
+func NewMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int, failer *failer.Failer, componentIndex int) *MeasureNode {
+ benchmarker := newBenchmarker()
+
+ wrappedBody := func() {
+ reflect.ValueOf(body).Call([]reflect.Value{reflect.ValueOf(benchmarker)})
+ }
+
+ return &MeasureNode{
+ runner: newRunner(wrappedBody, codeLocation, 0, failer, types.SpecComponentTypeMeasure, componentIndex),
+
+ text: text,
+ flag: flag,
+ samples: samples,
+ benchmarker: benchmarker,
+ }
+}
+
+func (node *MeasureNode) Run() (outcome types.SpecState, failure types.SpecFailure) {
+ return node.runner.run()
+}
+
+func (node *MeasureNode) MeasurementsReport() map[string]*types.SpecMeasurement {
+ return node.benchmarker.measurementsReport()
+}
+
+func (node *MeasureNode) Type() types.SpecComponentType {
+ return types.SpecComponentTypeMeasure
+}
+
+func (node *MeasureNode) Text() string {
+ return node.text
+}
+
+func (node *MeasureNode) Flag() types.FlagType {
+ return node.flag
+}
+
+func (node *MeasureNode) CodeLocation() types.CodeLocation {
+ return node.runner.codeLocation
+}
+
+func (node *MeasureNode) Samples() int {
+ return node.samples
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go
new file mode 100644
index 000000000..1cd13336a
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go
@@ -0,0 +1,155 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+ . "github.com/onsi/gomega"
+
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ Failer "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+var _ = Describe("Measure Nodes", func() {
+ It("should report the correct type, text, flag, and code location", func() {
+ codeLocation := codelocation.New(0)
+ measure := NewMeasureNode("my measure node", func(b Benchmarker) {}, types.FlagTypeFocused, codeLocation, 10, nil, 3)
+ Ω(measure.Type()).Should(Equal(types.SpecComponentTypeMeasure))
+ Ω(measure.Flag()).Should(Equal(types.FlagTypeFocused))
+ Ω(measure.Text()).Should(Equal("my measure node"))
+ Ω(measure.CodeLocation()).Should(Equal(codeLocation))
+ Ω(measure.Samples()).Should(Equal(10))
+ })
+
+ Describe("benchmarking", func() {
+ var measure *MeasureNode
+
+ Describe("Value", func() {
+ BeforeEach(func() {
+ measure = NewMeasureNode("the measurement", func(b Benchmarker) {
+ b.RecordValue("foo", 7, "info!")
+ b.RecordValue("foo", 2)
+ b.RecordValue("foo", 3)
+ b.RecordValue("bar", 0.3)
+ b.RecordValue("bar", 0.1)
+ b.RecordValue("bar", 0.5)
+ b.RecordValue("bar", 0.7)
+ }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3)
+ Ω(measure.Run()).Should(Equal(types.SpecStatePassed))
+ })
+
+ It("records passed in values and reports on them", func() {
+ report := measure.MeasurementsReport()
+ Ω(report).Should(HaveLen(2))
+ Ω(report["foo"].Name).Should(Equal("foo"))
+ Ω(report["foo"].Info).Should(Equal("info!"))
+ Ω(report["foo"].Order).Should(Equal(0))
+ Ω(report["foo"].SmallestLabel).Should(Equal("Smallest"))
+ Ω(report["foo"].LargestLabel).Should(Equal(" Largest"))
+ Ω(report["foo"].AverageLabel).Should(Equal(" Average"))
+ Ω(report["foo"].Units).Should(Equal(""))
+ Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3}))
+ Ω(report["foo"].Smallest).Should(BeNumerically("==", 2))
+ Ω(report["foo"].Largest).Should(BeNumerically("==", 7))
+ Ω(report["foo"].Average).Should(BeNumerically("==", 4))
+ Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01))
+
+ Ω(report["bar"].Name).Should(Equal("bar"))
+ Ω(report["bar"].Info).Should(BeNil())
+ Ω(report["bar"].SmallestLabel).Should(Equal("Smallest"))
+ Ω(report["bar"].Order).Should(Equal(1))
+ Ω(report["bar"].LargestLabel).Should(Equal(" Largest"))
+ Ω(report["bar"].AverageLabel).Should(Equal(" Average"))
+ Ω(report["bar"].Units).Should(Equal(""))
+ Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7}))
+ Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1))
+ Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7))
+ Ω(report["bar"].Average).Should(BeNumerically("==", 0.4))
+ Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01))
+ })
+ })
+
+ Describe("Value with precision", func() {
+ BeforeEach(func() {
+ measure = NewMeasureNode("the measurement", func(b Benchmarker) {
+ b.RecordValueWithPrecision("foo", 7, "ms", 7, "info!")
+ b.RecordValueWithPrecision("foo", 2, "ms", 6)
+ b.RecordValueWithPrecision("foo", 3, "ms", 5)
+ b.RecordValueWithPrecision("bar", 0.3, "ns", 4)
+ b.RecordValueWithPrecision("bar", 0.1, "ns", 3)
+ b.RecordValueWithPrecision("bar", 0.5, "ns", 2)
+ b.RecordValueWithPrecision("bar", 0.7, "ns", 1)
+ }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3)
+ Ω(measure.Run()).Should(Equal(types.SpecStatePassed))
+ })
+
+ It("records passed in values and reports on them", func() {
+ report := measure.MeasurementsReport()
+ Ω(report).Should(HaveLen(2))
+ Ω(report["foo"].Name).Should(Equal("foo"))
+ Ω(report["foo"].Info).Should(Equal("info!"))
+ Ω(report["foo"].Order).Should(Equal(0))
+ Ω(report["foo"].SmallestLabel).Should(Equal("Smallest"))
+ Ω(report["foo"].LargestLabel).Should(Equal(" Largest"))
+ Ω(report["foo"].AverageLabel).Should(Equal(" Average"))
+ Ω(report["foo"].Units).Should(Equal("ms"))
+ Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3}))
+ Ω(report["foo"].Smallest).Should(BeNumerically("==", 2))
+ Ω(report["foo"].Largest).Should(BeNumerically("==", 7))
+ Ω(report["foo"].Average).Should(BeNumerically("==", 4))
+ Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01))
+
+ Ω(report["bar"].Name).Should(Equal("bar"))
+ Ω(report["bar"].Info).Should(BeNil())
+ Ω(report["bar"].SmallestLabel).Should(Equal("Smallest"))
+ Ω(report["bar"].Order).Should(Equal(1))
+ Ω(report["bar"].LargestLabel).Should(Equal(" Largest"))
+ Ω(report["bar"].AverageLabel).Should(Equal(" Average"))
+ Ω(report["bar"].Units).Should(Equal("ns"))
+ Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7}))
+ Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1))
+ Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7))
+ Ω(report["bar"].Average).Should(BeNumerically("==", 0.4))
+ Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01))
+ })
+ })
+
+ Describe("Time", func() {
+ BeforeEach(func() {
+ measure = NewMeasureNode("the measurement", func(b Benchmarker) {
+ b.Time("foo", func() {
+ time.Sleep(200 * time.Millisecond)
+ }, "info!")
+ b.Time("foo", func() {
+ time.Sleep(300 * time.Millisecond)
+ })
+ b.Time("foo", func() {
+ time.Sleep(250 * time.Millisecond)
+ })
+ }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3)
+ Ω(measure.Run()).Should(Equal(types.SpecStatePassed))
+ })
+
+ It("records passed in values and reports on them", func() {
+ report := measure.MeasurementsReport()
+ Ω(report).Should(HaveLen(1))
+ Ω(report["foo"].Name).Should(Equal("foo"))
+ Ω(report["foo"].Info).Should(Equal("info!"))
+ Ω(report["foo"].SmallestLabel).Should(Equal("Fastest Time"))
+ Ω(report["foo"].LargestLabel).Should(Equal("Slowest Time"))
+ Ω(report["foo"].AverageLabel).Should(Equal("Average Time"))
+ Ω(report["foo"].Units).Should(Equal("s"))
+ Ω(report["foo"].Results).Should(HaveLen(3))
+ Ω(report["foo"].Results[0]).Should(BeNumerically("~", 0.2, 0.06))
+ Ω(report["foo"].Results[1]).Should(BeNumerically("~", 0.3, 0.06))
+ Ω(report["foo"].Results[2]).Should(BeNumerically("~", 0.25, 0.06))
+ Ω(report["foo"].Smallest).Should(BeNumerically("~", 0.2, 0.06))
+ Ω(report["foo"].Largest).Should(BeNumerically("~", 0.3, 0.06))
+ Ω(report["foo"].Average).Should(BeNumerically("~", 0.25, 0.06))
+ Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 0.07, 0.04))
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go
new file mode 100644
index 000000000..16cb66c3e
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/runner.go
@@ -0,0 +1,117 @@
+package leafnodes
+
+import (
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type runner struct {
+ isAsync bool
+ asyncFunc func(chan<- interface{})
+ syncFunc func()
+ codeLocation types.CodeLocation
+ timeoutThreshold time.Duration
+ nodeType types.SpecComponentType
+ componentIndex int
+ failer *failer.Failer
+}
+
+func newRunner(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, nodeType types.SpecComponentType, componentIndex int) *runner {
+ bodyType := reflect.TypeOf(body)
+ if bodyType.Kind() != reflect.Func {
+ panic(fmt.Sprintf("Expected a function but got something else at %v", codeLocation))
+ }
+
+ runner := &runner{
+ codeLocation: codeLocation,
+ timeoutThreshold: timeout,
+ failer: failer,
+ nodeType: nodeType,
+ componentIndex: componentIndex,
+ }
+
+ switch bodyType.NumIn() {
+ case 0:
+ runner.syncFunc = body.(func())
+ return runner
+ case 1:
+ if !(bodyType.In(0).Kind() == reflect.Chan && bodyType.In(0).Elem().Kind() == reflect.Interface) {
+ panic(fmt.Sprintf("Must pass a Done channel to function at %v", codeLocation))
+ }
+
+ wrappedBody := func(done chan<- interface{}) {
+ bodyValue := reflect.ValueOf(body)
+ bodyValue.Call([]reflect.Value{reflect.ValueOf(done)})
+ }
+
+ runner.isAsync = true
+ runner.asyncFunc = wrappedBody
+ return runner
+ }
+
+ panic(fmt.Sprintf("Too many arguments to function at %v", codeLocation))
+}
+
+func (r *runner) run() (outcome types.SpecState, failure types.SpecFailure) {
+ if r.isAsync {
+ return r.runAsync()
+ } else {
+ return r.runSync()
+ }
+}
+
+func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure) {
+ done := make(chan interface{}, 1)
+
+ go func() {
+ finished := false
+
+ defer func() {
+ if e := recover(); e != nil || !finished {
+ r.failer.Panic(codelocation.New(2), e)
+ select {
+ case <-done:
+ break
+ default:
+ close(done)
+ }
+ }
+ }()
+
+ r.asyncFunc(done)
+ finished = true
+ }()
+
+ // If this goroutine gets no CPU time before the select block,
+ // the <-done case may complete even if the test took longer than the timeoutThreshold.
+ // This can cause flaky behaviour, but we haven't seen it in the wild.
+ select {
+ case <-done:
+ case <-time.After(r.timeoutThreshold):
+ r.failer.Timeout(r.codeLocation)
+ }
+
+ failure, outcome = r.failer.Drain(r.nodeType, r.componentIndex, r.codeLocation)
+ return
+}
+func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure) {
+ finished := false
+
+ defer func() {
+ if e := recover(); e != nil || !finished {
+ r.failer.Panic(codelocation.New(2), e)
+ }
+
+ failure, outcome = r.failer.Drain(r.nodeType, r.componentIndex, r.codeLocation)
+ }()
+
+ r.syncFunc()
+ finished = true
+
+ return
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go
new file mode 100644
index 000000000..e3e9cb7c5
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes.go
@@ -0,0 +1,48 @@
+package leafnodes
+
+import (
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type SetupNode struct {
+ runner *runner
+}
+
+func (node *SetupNode) Run() (outcome types.SpecState, failure types.SpecFailure) {
+ return node.runner.run()
+}
+
+func (node *SetupNode) Type() types.SpecComponentType {
+ return node.runner.nodeType
+}
+
+func (node *SetupNode) CodeLocation() types.CodeLocation {
+ return node.runner.codeLocation
+}
+
+func NewBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode {
+ return &SetupNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeBeforeEach, componentIndex),
+ }
+}
+
+func NewAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode {
+ return &SetupNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeAfterEach, componentIndex),
+ }
+}
+
+func NewJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode {
+ return &SetupNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustBeforeEach, componentIndex),
+ }
+}
+
+func NewJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode {
+ return &SetupNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustAfterEach, componentIndex),
+ }
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go
new file mode 100644
index 000000000..9810688cb
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go
@@ -0,0 +1,48 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ "github.com/onsi/ginkgo/types"
+ . "github.com/onsi/gomega"
+
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+)
+
+var _ = Describe("Setup Nodes", func() {
+ Describe("BeforeEachNodes", func() {
+ It("should report the correct type and code location", func() {
+ codeLocation := codelocation.New(0)
+ beforeEach := NewBeforeEachNode(func() {}, codeLocation, 0, nil, 3)
+ Ω(beforeEach.Type()).Should(Equal(types.SpecComponentTypeBeforeEach))
+ Ω(beforeEach.CodeLocation()).Should(Equal(codeLocation))
+ })
+ })
+
+ Describe("AfterEachNodes", func() {
+ It("should report the correct type and code location", func() {
+ codeLocation := codelocation.New(0)
+ afterEach := NewAfterEachNode(func() {}, codeLocation, 0, nil, 3)
+ Ω(afterEach.Type()).Should(Equal(types.SpecComponentTypeAfterEach))
+ Ω(afterEach.CodeLocation()).Should(Equal(codeLocation))
+ })
+ })
+
+ Describe("JustBeforeEachNodes", func() {
+ It("should report the correct type and code location", func() {
+ codeLocation := codelocation.New(0)
+ justBeforeEach := NewJustBeforeEachNode(func() {}, codeLocation, 0, nil, 3)
+ Ω(justBeforeEach.Type()).Should(Equal(types.SpecComponentTypeJustBeforeEach))
+ Ω(justBeforeEach.CodeLocation()).Should(Equal(codeLocation))
+ })
+ })
+ Describe("JustAfterEachNodes", func() {
+ It("should report the correct type and code location", func() {
+ codeLocation := codelocation.New(0)
+ justAfterEach := NewJustAfterEachNode(func() {}, codeLocation, 0, nil, 3)
+ Ω(justAfterEach.Type()).Should(Equal(types.SpecComponentTypeJustAfterEach))
+ Ω(justAfterEach.CodeLocation()).Should(Equal(codeLocation))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go
new file mode 100644
index 000000000..0897836cb
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go
@@ -0,0 +1,353 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+ . "github.com/onsi/gomega"
+
+ "reflect"
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ Failer "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type runnable interface {
+ Run() (outcome types.SpecState, failure types.SpecFailure)
+ CodeLocation() types.CodeLocation
+}
+
+func SynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) {
+ var (
+ outcome types.SpecState
+ failure types.SpecFailure
+
+ failer *Failer.Failer
+
+ componentCodeLocation types.CodeLocation
+ innerCodeLocation types.CodeLocation
+
+ didRun bool
+ )
+
+ BeforeEach(func() {
+ failer = Failer.New()
+ componentCodeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+
+ didRun = false
+ })
+
+ Describe("synchronous functions", func() {
+ Context("when the function passes", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func() {
+ didRun = true
+ }, 0, failer, componentCodeLocation).Run()
+ })
+
+ It("should have a succesful outcome", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStatePassed))
+ Ω(failure).Should(BeZero())
+ })
+ })
+
+ Context("when a failure occurs", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func() {
+ didRun = true
+ failer.Fail("bam", innerCodeLocation)
+ panic("should not matter")
+ }, 0, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the failure", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStateFailed))
+ Ω(failure).Should(Equal(types.SpecFailure{
+ Message: "bam",
+ Location: innerCodeLocation,
+ ForwardedPanic: "",
+ ComponentIndex: componentIndex,
+ ComponentType: componentType,
+ ComponentCodeLocation: componentCodeLocation,
+ }))
+ })
+ })
+
+ Context("when a panic occurs", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func() {
+ didRun = true
+ innerCodeLocation = codelocation.New(0)
+ panic("ack!")
+ }, 0, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the panic", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStatePanicked))
+ Ω(failure.ForwardedPanic).Should(Equal("ack!"))
+ })
+ })
+
+ Context("when a panic occurs with a nil value", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func() {
+ didRun = true
+ innerCodeLocation = codelocation.New(0)
+ panic(nil)
+ }, 0, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the nil-valued panic", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStatePanicked))
+ Ω(failure.ForwardedPanic).Should(Equal("<nil>"))
+ })
+ })
+
+ })
+}
+
+func AsynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) {
+ var (
+ outcome types.SpecState
+ failure types.SpecFailure
+
+ failer *Failer.Failer
+
+ componentCodeLocation types.CodeLocation
+ innerCodeLocation types.CodeLocation
+
+ didRun bool
+ )
+
+ BeforeEach(func() {
+ failer = Failer.New()
+ componentCodeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+
+ didRun = false
+ })
+
+ Describe("asynchronous functions", func() {
+ var timeoutDuration time.Duration
+
+ BeforeEach(func() {
+ timeoutDuration = time.Duration(1 * float64(time.Second))
+ })
+
+ Context("when running", func() {
+ It("should run the function as a goroutine, and block until it's done", func() {
+ proveAsync := make(chan bool)
+
+ build(func(done Done) {
+ didRun = true
+ proveAsync <- true
+ close(done)
+ }, timeoutDuration, failer, componentCodeLocation).Run()
+
+ Eventually(proveAsync).Should(Receive(Equal(true)))
+ })
+ })
+
+ Context("when the function passes", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func(done Done) {
+ didRun = true
+ close(done)
+ }, timeoutDuration, failer, componentCodeLocation).Run()
+ })
+
+ It("should have a succesful outcome", func() {
+ Ω(didRun).Should(BeTrue())
+ Ω(outcome).Should(Equal(types.SpecStatePassed))
+ Ω(failure).Should(BeZero())
+ })
+ })
+
+ Context("when the function fails", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func(done Done) {
+ didRun = true
+ failer.Fail("bam", innerCodeLocation)
+ time.Sleep(20 * time.Millisecond)
+ defer close(done)
+ panic("doesn't matter")
+ }, 10*time.Millisecond, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the failure", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStateFailed))
+ Ω(failure).Should(Equal(types.SpecFailure{
+ Message: "bam",
+ Location: innerCodeLocation,
+ ForwardedPanic: "",
+ ComponentIndex: componentIndex,
+ ComponentType: componentType,
+ ComponentCodeLocation: componentCodeLocation,
+ }))
+ })
+ })
+
+ Context("when the function doesn't close the done channel in time", func() {
+ var guard chan struct{}
+
+ BeforeEach(func() {
+ guard = make(chan struct{})
+ outcome, failure = build(func(done Done) {
+ didRun = true
+ close(guard)
+ }, 10*time.Millisecond, failer, componentCodeLocation).Run()
+ })
+
+ It("should return a timeout", func() {
+ <-guard
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStateTimedOut))
+ Ω(failure).Should(Equal(types.SpecFailure{
+ Message: "Timed out",
+ Location: componentCodeLocation,
+ ForwardedPanic: "",
+ ComponentIndex: componentIndex,
+ ComponentType: componentType,
+ ComponentCodeLocation: componentCodeLocation,
+ }))
+ })
+ })
+
+ Context("when the function panics", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func(done Done) {
+ didRun = true
+ innerCodeLocation = codelocation.New(0)
+ panic("ack!")
+ }, 100*time.Millisecond, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the panic", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStatePanicked))
+ Ω(failure.ForwardedPanic).Should(Equal("ack!"))
+ })
+ })
+
+ Context("when the function panics with a nil value", func() {
+ BeforeEach(func() {
+ outcome, failure = build(func(done Done) {
+ didRun = true
+ innerCodeLocation = codelocation.New(0)
+ panic(nil)
+ }, 100*time.Millisecond, failer, componentCodeLocation).Run()
+ })
+
+ It("should return the nil-valued panic", func() {
+ Ω(didRun).Should(BeTrue())
+
+ Ω(outcome).Should(Equal(types.SpecStatePanicked))
+ Ω(failure.ForwardedPanic).Should(Equal("<nil>"))
+ })
+ })
+ })
+}
+
+func InvalidSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType) {
+ var (
+ failer *Failer.Failer
+ componentCodeLocation types.CodeLocation
+ )
+
+ BeforeEach(func() {
+ failer = Failer.New()
+ componentCodeLocation = codelocation.New(0)
+ })
+
+ Describe("invalid functions", func() {
+ Context("when passed something that's not a function", func() {
+ It("should panic", func() {
+ Ω(func() {
+ build("not a function", 0, failer, componentCodeLocation)
+ }).Should(Panic())
+ })
+ })
+
+ Context("when the function takes the wrong kind of argument", func() {
+ It("should panic", func() {
+ Ω(func() {
+ build(func(oops string) {}, 0, failer, componentCodeLocation)
+ }).Should(Panic())
+ })
+ })
+
+ Context("when the function takes more than one argument", func() {
+ It("should panic", func() {
+ Ω(func() {
+ build(func(done Done, oops string) {}, 0, failer, componentCodeLocation)
+ }).Should(Panic())
+ })
+ })
+ })
+}
+
+var _ = Describe("Shared RunnableNode behavior", func() {
+ Describe("It Nodes", func() {
+ build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable {
+ return NewItNode("", body, types.FlagTypeFocused, componentCodeLocation, timeout, failer, 3)
+ }
+
+ SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3)
+ AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3)
+ InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeIt)
+ })
+
+ Describe("Measure Nodes", func() {
+ build := func(body interface{}, _ time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable {
+ return NewMeasureNode("", func(Benchmarker) {
+ reflect.ValueOf(body).Call([]reflect.Value{})
+ }, types.FlagTypeFocused, componentCodeLocation, 10, failer, 3)
+ }
+
+ SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeMeasure, 3)
+ })
+
+ Describe("BeforeEach Nodes", func() {
+ build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable {
+ return NewBeforeEachNode(body, componentCodeLocation, timeout, failer, 3)
+ }
+
+ SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3)
+ AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3)
+ InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach)
+ })
+
+ Describe("AfterEach Nodes", func() {
+ build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable {
+ return NewAfterEachNode(body, componentCodeLocation, timeout, failer, 3)
+ }
+
+ SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3)
+ AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3)
+ InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach)
+ })
+
+ Describe("JustBeforeEach Nodes", func() {
+ build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable {
+ return NewJustBeforeEachNode(body, componentCodeLocation, timeout, failer, 3)
+ }
+
+ SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3)
+ AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3)
+ InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach)
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go
new file mode 100644
index 000000000..80f16ed78
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes.go
@@ -0,0 +1,55 @@
+package leafnodes
+
+import (
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type SuiteNode interface {
+ Run(parallelNode int, parallelTotal int, syncHost string) bool
+ Passed() bool
+ Summary() *types.SetupSummary
+}
+
+type simpleSuiteNode struct {
+ runner *runner
+ outcome types.SpecState
+ failure types.SpecFailure
+ runTime time.Duration
+}
+
+func (node *simpleSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool {
+ t := time.Now()
+ node.outcome, node.failure = node.runner.run()
+ node.runTime = time.Since(t)
+
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *simpleSuiteNode) Passed() bool {
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *simpleSuiteNode) Summary() *types.SetupSummary {
+ return &types.SetupSummary{
+ ComponentType: node.runner.nodeType,
+ CodeLocation: node.runner.codeLocation,
+ State: node.outcome,
+ RunTime: node.runTime,
+ Failure: node.failure,
+ }
+}
+
+func NewBeforeSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode {
+ return &simpleSuiteNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0),
+ }
+}
+
+func NewAfterSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode {
+ return &simpleSuiteNode{
+ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0),
+ }
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go
new file mode 100644
index 000000000..246b329fe
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go
@@ -0,0 +1,230 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ Failer "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+var _ = Describe("SuiteNodes", func() {
+ Describe("BeforeSuite nodes", func() {
+ var befSuite SuiteNode
+ var failer *Failer.Failer
+ var codeLocation types.CodeLocation
+ var innerCodeLocation types.CodeLocation
+ var outcome bool
+
+ BeforeEach(func() {
+ failer = Failer.New()
+ codeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+ })
+
+ Context("when the body passes", func() {
+ BeforeEach(func() {
+ befSuite = NewBeforeSuiteNode(func() {
+ time.Sleep(10 * time.Millisecond)
+ }, codeLocation, 0, failer)
+ outcome = befSuite.Run(0, 0, "")
+ })
+
+ It("should return true when run and report as passed", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(befSuite.Passed()).Should(BeTrue())
+ })
+
+ It("should have the correct summary", func() {
+ summary := befSuite.Summary()
+ Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.CodeLocation).Should(Equal(codeLocation))
+ Ω(summary.State).Should(Equal(types.SpecStatePassed))
+ Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond))
+ Ω(summary.Failure).Should(BeZero())
+ })
+ })
+
+ Context("when the body fails", func() {
+ BeforeEach(func() {
+ befSuite = NewBeforeSuiteNode(func() {
+ failer.Fail("oops", innerCodeLocation)
+ }, codeLocation, 0, failer)
+ outcome = befSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(befSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := befSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateFailed))
+ Ω(summary.Failure.Message).Should(Equal("oops"))
+ Ω(summary.Failure.Location).Should(Equal(innerCodeLocation))
+ Ω(summary.Failure.ForwardedPanic).Should(BeEmpty())
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+
+ Context("when the body times out", func() {
+ BeforeEach(func() {
+ befSuite = NewBeforeSuiteNode(func(done Done) {
+ }, codeLocation, time.Millisecond, failer)
+ outcome = befSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(befSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := befSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateTimedOut))
+ Ω(summary.Failure.ForwardedPanic).Should(BeEmpty())
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+
+ Context("when the body panics", func() {
+ BeforeEach(func() {
+ befSuite = NewBeforeSuiteNode(func() {
+ panic("bam")
+ }, codeLocation, 0, failer)
+ outcome = befSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(befSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := befSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStatePanicked))
+ Ω(summary.Failure.ForwardedPanic).Should(Equal("bam"))
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+ })
+
+ Describe("AfterSuite nodes", func() {
+ var aftSuite SuiteNode
+ var failer *Failer.Failer
+ var codeLocation types.CodeLocation
+ var innerCodeLocation types.CodeLocation
+ var outcome bool
+
+ BeforeEach(func() {
+ failer = Failer.New()
+ codeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+ })
+
+ Context("when the body passes", func() {
+ BeforeEach(func() {
+ aftSuite = NewAfterSuiteNode(func() {
+ time.Sleep(10 * time.Millisecond)
+ }, codeLocation, 0, failer)
+ outcome = aftSuite.Run(0, 0, "")
+ })
+
+ It("should return true when run and report as passed", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(aftSuite.Passed()).Should(BeTrue())
+ })
+
+ It("should have the correct summary", func() {
+ summary := aftSuite.Summary()
+ Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite))
+ Ω(summary.CodeLocation).Should(Equal(codeLocation))
+ Ω(summary.State).Should(Equal(types.SpecStatePassed))
+ Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond))
+ Ω(summary.Failure).Should(BeZero())
+ })
+ })
+
+ Context("when the body fails", func() {
+ BeforeEach(func() {
+ aftSuite = NewAfterSuiteNode(func() {
+ failer.Fail("oops", innerCodeLocation)
+ }, codeLocation, 0, failer)
+ outcome = aftSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(aftSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := aftSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateFailed))
+ Ω(summary.Failure.Message).Should(Equal("oops"))
+ Ω(summary.Failure.Location).Should(Equal(innerCodeLocation))
+ Ω(summary.Failure.ForwardedPanic).Should(BeEmpty())
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+
+ Context("when the body times out", func() {
+ BeforeEach(func() {
+ aftSuite = NewAfterSuiteNode(func(done Done) {
+ }, codeLocation, time.Millisecond, failer)
+ outcome = aftSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(aftSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := aftSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateTimedOut))
+ Ω(summary.Failure.ForwardedPanic).Should(BeEmpty())
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+
+ Context("when the body panics", func() {
+ BeforeEach(func() {
+ aftSuite = NewAfterSuiteNode(func() {
+ panic("bam")
+ }, codeLocation, 0, failer)
+ outcome = aftSuite.Run(0, 0, "")
+ })
+
+ It("should return false when run and report as failed", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(aftSuite.Passed()).Should(BeFalse())
+ })
+
+ It("should have the correct summary", func() {
+ summary := aftSuite.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStatePanicked))
+ Ω(summary.Failure.ForwardedPanic).Should(Equal("bam"))
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go
new file mode 100644
index 000000000..a721d0cf7
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node.go
@@ -0,0 +1,90 @@
+package leafnodes
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type synchronizedAfterSuiteNode struct {
+ runnerA *runner
+ runnerB *runner
+
+ outcome types.SpecState
+ failure types.SpecFailure
+ runTime time.Duration
+}
+
+func NewSynchronizedAfterSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode {
+ return &synchronizedAfterSuiteNode{
+ runnerA: newRunner(bodyA, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0),
+ runnerB: newRunner(bodyB, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0),
+ }
+}
+
+func (node *synchronizedAfterSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool {
+ node.outcome, node.failure = node.runnerA.run()
+
+ if parallelNode == 1 {
+ if parallelTotal > 1 {
+ node.waitUntilOtherNodesAreDone(syncHost)
+ }
+
+ outcome, failure := node.runnerB.run()
+
+ if node.outcome == types.SpecStatePassed {
+ node.outcome, node.failure = outcome, failure
+ }
+ }
+
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *synchronizedAfterSuiteNode) Passed() bool {
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *synchronizedAfterSuiteNode) Summary() *types.SetupSummary {
+ return &types.SetupSummary{
+ ComponentType: node.runnerA.nodeType,
+ CodeLocation: node.runnerA.codeLocation,
+ State: node.outcome,
+ RunTime: node.runTime,
+ Failure: node.failure,
+ }
+}
+
+func (node *synchronizedAfterSuiteNode) waitUntilOtherNodesAreDone(syncHost string) {
+ for {
+ if node.canRun(syncHost) {
+ return
+ }
+
+ time.Sleep(50 * time.Millisecond)
+ }
+}
+
+func (node *synchronizedAfterSuiteNode) canRun(syncHost string) bool {
+ resp, err := http.Get(syncHost + "/RemoteAfterSuiteData")
+ if err != nil || resp.StatusCode != http.StatusOK {
+ return false
+ }
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return false
+ }
+ resp.Body.Close()
+
+ afterSuiteData := types.RemoteAfterSuiteData{}
+ err = json.Unmarshal(body, &afterSuiteData)
+ if err != nil {
+ return false
+ }
+
+ return afterSuiteData.CanRun
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go
new file mode 100644
index 000000000..edbdf6ae5
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go
@@ -0,0 +1,199 @@
+package leafnodes_test
+
+import (
+ "sync"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+ "github.com/onsi/ginkgo/types"
+ . "github.com/onsi/gomega"
+
+ "net/http"
+
+ "github.com/onsi/gomega/ghttp"
+
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ Failer "github.com/onsi/ginkgo/internal/failer"
+)
+
+var _ = Describe("SynchronizedAfterSuiteNode", func() {
+ var failer *Failer.Failer
+ var node SuiteNode
+ var codeLocation types.CodeLocation
+ var innerCodeLocation types.CodeLocation
+ var outcome bool
+ var server *ghttp.Server
+ var things []string
+ var lock *sync.Mutex
+
+ BeforeEach(func() {
+ things = []string{}
+ server = ghttp.NewServer()
+ codeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+ failer = Failer.New()
+ lock = &sync.Mutex{}
+ })
+
+ AfterEach(func() {
+ server.Close()
+ })
+
+ newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode {
+ return NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer)
+ }
+
+ ranThing := func(thing string) {
+ lock.Lock()
+ defer lock.Unlock()
+ things = append(things, thing)
+ }
+
+ thingsThatRan := func() []string {
+ lock.Lock()
+ defer lock.Unlock()
+ return things
+ }
+
+ Context("when not running in parallel", func() {
+ Context("when all is well", func() {
+ BeforeEach(func() {
+ node = newNode(func() {
+ ranThing("A")
+ }, func() {
+ ranThing("B")
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should run A, then B", func() {
+ Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
+ })
+
+ It("should report success", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(node.Passed()).Should(BeTrue())
+ Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
+ })
+ })
+
+ Context("when A fails", func() {
+ BeforeEach(func() {
+ node = newNode(func() {
+ ranThing("A")
+ failer.Fail("bam", innerCodeLocation)
+ }, func() {
+ ranThing("B")
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should still run B", func() {
+ Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
+ })
+ })
+
+ Context("when B fails", func() {
+ BeforeEach(func() {
+ node = newNode(func() {
+ ranThing("A")
+ }, func() {
+ ranThing("B")
+ failer.Fail("bam", innerCodeLocation)
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should run all the things", func() {
+ Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
+ })
+ })
+ })
+
+ Context("when running in parallel", func() {
+ Context("as the first node", func() {
+ BeforeEach(func() {
+ server.AppendHandlers(ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
+ func(writer http.ResponseWriter, request *http.Request) {
+ ranThing("Request1")
+ },
+ ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}),
+ ), ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
+ func(writer http.ResponseWriter, request *http.Request) {
+ ranThing("Request2")
+ },
+ ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}),
+ ), ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
+ func(writer http.ResponseWriter, request *http.Request) {
+ ranThing("Request3")
+ },
+ ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: true}),
+ ))
+
+ node = newNode(func() {
+ ranThing("A")
+ }, func() {
+ ranThing("B")
+ })
+
+ outcome = node.Run(1, 3, server.URL())
+ })
+
+ It("should run A and, when the server says its time, run B", func() {
+ Ω(thingsThatRan()).Should(Equal([]string{"A", "Request1", "Request2", "Request3", "B"}))
+ })
+
+ It("should report success", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(node.Passed()).Should(BeTrue())
+ Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
+ })
+ })
+
+ Context("as any other node", func() {
+ BeforeEach(func() {
+ node = newNode(func() {
+ ranThing("A")
+ }, func() {
+ ranThing("B")
+ })
+
+ outcome = node.Run(2, 3, server.URL())
+ })
+
+ It("should run A, and not run B", func() {
+ Ω(thingsThatRan()).Should(Equal([]string{"A"}))
+ })
+
+ It("should not talk to the server", func() {
+ Ω(server.ReceivedRequests()).Should(BeEmpty())
+ })
+
+ It("should report success", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(node.Passed()).Should(BeTrue())
+ Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go
new file mode 100644
index 000000000..d5c889319
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node.go
@@ -0,0 +1,181 @@
+package leafnodes
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+ "reflect"
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+type synchronizedBeforeSuiteNode struct {
+ runnerA *runner
+ runnerB *runner
+
+ data []byte
+
+ outcome types.SpecState
+ failure types.SpecFailure
+ runTime time.Duration
+}
+
+func NewSynchronizedBeforeSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode {
+ node := &synchronizedBeforeSuiteNode{}
+
+ node.runnerA = newRunner(node.wrapA(bodyA), codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0)
+ node.runnerB = newRunner(node.wrapB(bodyB), codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0)
+
+ return node
+}
+
+func (node *synchronizedBeforeSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool {
+ t := time.Now()
+ defer func() {
+ node.runTime = time.Since(t)
+ }()
+
+ if parallelNode == 1 {
+ node.outcome, node.failure = node.runA(parallelTotal, syncHost)
+ } else {
+ node.outcome, node.failure = node.waitForA(syncHost)
+ }
+
+ if node.outcome != types.SpecStatePassed {
+ return false
+ }
+ node.outcome, node.failure = node.runnerB.run()
+
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *synchronizedBeforeSuiteNode) runA(parallelTotal int, syncHost string) (types.SpecState, types.SpecFailure) {
+ outcome, failure := node.runnerA.run()
+
+ if parallelTotal > 1 {
+ state := types.RemoteBeforeSuiteStatePassed
+ if outcome != types.SpecStatePassed {
+ state = types.RemoteBeforeSuiteStateFailed
+ }
+ json := (types.RemoteBeforeSuiteData{
+ Data: node.data,
+ State: state,
+ }).ToJSON()
+ http.Post(syncHost+"/BeforeSuiteState", "application/json", bytes.NewBuffer(json))
+ }
+
+ return outcome, failure
+}
+
+func (node *synchronizedBeforeSuiteNode) waitForA(syncHost string) (types.SpecState, types.SpecFailure) {
+ failure := func(message string) types.SpecFailure {
+ return types.SpecFailure{
+ Message: message,
+ Location: node.runnerA.codeLocation,
+ ComponentType: node.runnerA.nodeType,
+ ComponentIndex: node.runnerA.componentIndex,
+ ComponentCodeLocation: node.runnerA.codeLocation,
+ }
+ }
+ for {
+ resp, err := http.Get(syncHost + "/BeforeSuiteState")
+ if err != nil || resp.StatusCode != http.StatusOK {
+ return types.SpecStateFailed, failure("Failed to fetch BeforeSuite state")
+ }
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return types.SpecStateFailed, failure("Failed to read BeforeSuite state")
+ }
+ resp.Body.Close()
+
+ beforeSuiteData := types.RemoteBeforeSuiteData{}
+ err = json.Unmarshal(body, &beforeSuiteData)
+ if err != nil {
+ return types.SpecStateFailed, failure("Failed to decode BeforeSuite state")
+ }
+
+ switch beforeSuiteData.State {
+ case types.RemoteBeforeSuiteStatePassed:
+ node.data = beforeSuiteData.Data
+ return types.SpecStatePassed, types.SpecFailure{}
+ case types.RemoteBeforeSuiteStateFailed:
+ return types.SpecStateFailed, failure("BeforeSuite on Node 1 failed")
+ case types.RemoteBeforeSuiteStateDisappeared:
+ return types.SpecStateFailed, failure("Node 1 disappeared before completing BeforeSuite")
+ }
+
+ time.Sleep(50 * time.Millisecond)
+ }
+}
+
+func (node *synchronizedBeforeSuiteNode) Passed() bool {
+ return node.outcome == types.SpecStatePassed
+}
+
+func (node *synchronizedBeforeSuiteNode) Summary() *types.SetupSummary {
+ return &types.SetupSummary{
+ ComponentType: node.runnerA.nodeType,
+ CodeLocation: node.runnerA.codeLocation,
+ State: node.outcome,
+ RunTime: node.runTime,
+ Failure: node.failure,
+ }
+}
+
+func (node *synchronizedBeforeSuiteNode) wrapA(bodyA interface{}) interface{} {
+ typeA := reflect.TypeOf(bodyA)
+ if typeA.Kind() != reflect.Func {
+ panic("SynchronizedBeforeSuite expects a function as its first argument")
+ }
+
+ takesNothing := typeA.NumIn() == 0
+ takesADoneChannel := typeA.NumIn() == 1 && typeA.In(0).Kind() == reflect.Chan && typeA.In(0).Elem().Kind() == reflect.Interface
+ returnsBytes := typeA.NumOut() == 1 && typeA.Out(0).Kind() == reflect.Slice && typeA.Out(0).Elem().Kind() == reflect.Uint8
+
+ if !((takesNothing || takesADoneChannel) && returnsBytes) {
+ panic("SynchronizedBeforeSuite's first argument should be a function that returns []byte and either takes no arguments or takes a Done channel.")
+ }
+
+ if takesADoneChannel {
+ return func(done chan<- interface{}) {
+ out := reflect.ValueOf(bodyA).Call([]reflect.Value{reflect.ValueOf(done)})
+ node.data = out[0].Interface().([]byte)
+ }
+ }
+
+ return func() {
+ out := reflect.ValueOf(bodyA).Call([]reflect.Value{})
+ node.data = out[0].Interface().([]byte)
+ }
+}
+
+func (node *synchronizedBeforeSuiteNode) wrapB(bodyB interface{}) interface{} {
+ typeB := reflect.TypeOf(bodyB)
+ if typeB.Kind() != reflect.Func {
+ panic("SynchronizedBeforeSuite expects a function as its second argument")
+ }
+
+ returnsNothing := typeB.NumOut() == 0
+ takesBytesOnly := typeB.NumIn() == 1 && typeB.In(0).Kind() == reflect.Slice && typeB.In(0).Elem().Kind() == reflect.Uint8
+ takesBytesAndDone := typeB.NumIn() == 2 &&
+ typeB.In(0).Kind() == reflect.Slice && typeB.In(0).Elem().Kind() == reflect.Uint8 &&
+ typeB.In(1).Kind() == reflect.Chan && typeB.In(1).Elem().Kind() == reflect.Interface
+
+ if !((takesBytesOnly || takesBytesAndDone) && returnsNothing) {
+ panic("SynchronizedBeforeSuite's second argument should be a function that returns nothing and either takes []byte or ([]byte, Done)")
+ }
+
+ if takesBytesAndDone {
+ return func(done chan<- interface{}) {
+ reflect.ValueOf(bodyB).Call([]reflect.Value{reflect.ValueOf(node.data), reflect.ValueOf(done)})
+ }
+ }
+
+ return func() {
+ reflect.ValueOf(bodyB).Call([]reflect.Value{reflect.ValueOf(node.data)})
+ }
+}
diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go
new file mode 100644
index 000000000..46c3e276b
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go
@@ -0,0 +1,446 @@
+package leafnodes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/internal/leafnodes"
+ . "github.com/onsi/gomega"
+
+ "net/http"
+
+ "github.com/onsi/gomega/ghttp"
+
+ "time"
+
+ "github.com/onsi/ginkgo/internal/codelocation"
+ Failer "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/types"
+)
+
+var _ = Describe("SynchronizedBeforeSuiteNode", func() {
+ var failer *Failer.Failer
+ var node SuiteNode
+ var codeLocation types.CodeLocation
+ var innerCodeLocation types.CodeLocation
+ var outcome bool
+ var server *ghttp.Server
+
+ BeforeEach(func() {
+ server = ghttp.NewServer()
+ codeLocation = codelocation.New(0)
+ innerCodeLocation = codelocation.New(0)
+ failer = Failer.New()
+ })
+
+ AfterEach(func() {
+ server.Close()
+ })
+
+ newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode {
+ return NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer)
+ }
+
+ Describe("when not running in parallel", func() {
+ Context("when all is well", func() {
+ var data []byte
+ BeforeEach(func() {
+ data = nil
+
+ node = newNode(func() []byte {
+ return []byte("my data")
+ }, func(d []byte) {
+ data = d
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should run A, then B passing the output from A to B", func() {
+ Ω(data).Should(Equal([]byte("my data")))
+ })
+
+ It("should report success", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(node.Passed()).Should(BeTrue())
+ Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
+ })
+ })
+
+ Context("when A fails", func() {
+ var ranB bool
+ BeforeEach(func() {
+ ranB = false
+ node = newNode(func() []byte {
+ failer.Fail("boom", innerCodeLocation)
+ return nil
+ }, func([]byte) {
+ ranB = true
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should not run B", func() {
+ Ω(ranB).Should(BeFalse())
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
+ })
+ })
+
+ Context("when B fails", func() {
+ BeforeEach(func() {
+ node = newNode(func() []byte {
+ return nil
+ }, func([]byte) {
+ failer.Fail("boom", innerCodeLocation)
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
+ })
+ })
+
+ Context("when A times out", func() {
+ var ranB bool
+ BeforeEach(func() {
+ ranB = false
+ node = newNode(func(Done) []byte {
+ time.Sleep(time.Second)
+ return nil
+ }, func([]byte) {
+ ranB = true
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should not run B", func() {
+ Ω(ranB).Should(BeFalse())
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut))
+ })
+ })
+
+ Context("when B times out", func() {
+ BeforeEach(func() {
+ node = newNode(func() []byte {
+ return nil
+ }, func([]byte, Done) {
+ time.Sleep(time.Second)
+ })
+
+ outcome = node.Run(1, 1, server.URL())
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+ Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut))
+ })
+ })
+ })
+
+ Describe("when running in parallel", func() {
+ var ranB bool
+ var parallelNode, parallelTotal int
+ BeforeEach(func() {
+ ranB = false
+ parallelNode, parallelTotal = 1, 3
+ })
+
+ Context("as the first node, it runs A", func() {
+ var expectedState types.RemoteBeforeSuiteData
+
+ BeforeEach(func() {
+ parallelNode, parallelTotal = 1, 3
+ })
+
+ JustBeforeEach(func() {
+ server.AppendHandlers(ghttp.CombineHandlers(
+ ghttp.VerifyRequest("POST", "/BeforeSuiteState"),
+ ghttp.VerifyJSONRepresenting(expectedState),
+ ))
+
+ outcome = node.Run(parallelNode, parallelTotal, server.URL())
+ })
+
+ Context("when A succeeds", func() {
+ BeforeEach(func() {
+ expectedState = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed}
+
+ node = newNode(func() []byte {
+ return []byte("my data")
+ }, func([]byte) {
+ ranB = true
+ })
+ })
+
+ It("should post about A succeeding", func() {
+ Ω(server.ReceivedRequests()).Should(HaveLen(1))
+ })
+
+ It("should run B", func() {
+ Ω(ranB).Should(BeTrue())
+ })
+
+ It("should report success", func() {
+ Ω(outcome).Should(BeTrue())
+ })
+ })
+
+ Context("when A fails", func() {
+ BeforeEach(func() {
+ expectedState = types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateFailed}
+
+ node = newNode(func() []byte {
+ panic("BAM")
+ }, func([]byte) {
+ ranB = true
+ })
+ })
+
+ It("should post about A failing", func() {
+ Ω(server.ReceivedRequests()).Should(HaveLen(1))
+ })
+
+ It("should not run B", func() {
+ Ω(ranB).Should(BeFalse())
+ })
+
+ It("should report failure", func() {
+ Ω(outcome).Should(BeFalse())
+ })
+ })
+ })
+
+ Context("as the Nth node", func() {
+ var statusCode int
+ var response interface{}
+ var ranA bool
+ var bData []byte
+
+ BeforeEach(func() {
+ ranA = false
+ bData = nil
+
+ statusCode = http.StatusOK
+
+ server.AppendHandlers(ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/BeforeSuiteState"),
+ ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())),
+ ), ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/BeforeSuiteState"),
+ ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())),
+ ), ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/BeforeSuiteState"),
+ ghttp.RespondWithJSONEncodedPtr(&statusCode, &response),
+ ))
+
+ node = newNode(func() []byte {
+ ranA = true
+ return nil
+ }, func(data []byte) {
+ bData = data
+ })
+
+ parallelNode, parallelTotal = 2, 3
+ })
+
+ Context("when A on node1 succeeds", func() {
+ BeforeEach(func() {
+ response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed}
+ outcome = node.Run(parallelNode, parallelTotal, server.URL())
+ })
+
+ It("should not run A", func() {
+ Ω(ranA).Should(BeFalse())
+ })
+
+ It("should poll for A", func() {
+ Ω(server.ReceivedRequests()).Should(HaveLen(3))
+ })
+
+ It("should run B when the polling succeeds", func() {
+ Ω(bData).Should(Equal([]byte("my data")))
+ })
+
+ It("should succeed", func() {
+ Ω(outcome).Should(BeTrue())
+ Ω(node.Passed()).Should(BeTrue())
+ })
+ })
+
+ Context("when A on node1 fails", func() {
+ BeforeEach(func() {
+ response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateFailed}
+ outcome = node.Run(parallelNode, parallelTotal, server.URL())
+ })
+
+ It("should not run A", func() {
+ Ω(ranA).Should(BeFalse())
+ })
+
+ It("should poll for A", func() {
+ Ω(server.ReceivedRequests()).Should(HaveLen(3))
+ })
+
+ It("should not run B", func() {
+ Ω(bData).Should(BeNil())
+ })
+
+ It("should fail", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+
+ summary := node.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateFailed))
+ Ω(summary.Failure.Message).Should(Equal("BeforeSuite on Node 1 failed"))
+ Ω(summary.Failure.Location).Should(Equal(codeLocation))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+
+ Context("when node1 disappears", func() {
+ BeforeEach(func() {
+ response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateDisappeared}
+ outcome = node.Run(parallelNode, parallelTotal, server.URL())
+ })
+
+ It("should not run A", func() {
+ Ω(ranA).Should(BeFalse())
+ })
+
+ It("should poll for A", func() {
+ Ω(server.ReceivedRequests()).Should(HaveLen(3))
+ })
+
+ It("should not run B", func() {
+ Ω(bData).Should(BeNil())
+ })
+
+ It("should fail", func() {
+ Ω(outcome).Should(BeFalse())
+ Ω(node.Passed()).Should(BeFalse())
+
+ summary := node.Summary()
+ Ω(summary.State).Should(Equal(types.SpecStateFailed))
+ Ω(summary.Failure.Message).Should(Equal("Node 1 disappeared before completing BeforeSuite"))
+ Ω(summary.Failure.Location).Should(Equal(codeLocation))
+ Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite))
+ Ω(summary.Failure.ComponentIndex).Should(Equal(0))
+ Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation))
+ })
+ })
+ })
+ })
+
+ Describe("construction", func() {
+ Describe("the first function", func() {
+ Context("when the first function returns a byte array", func() {
+ Context("and takes nothing", func() {
+ It("should be fine", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func([]byte) {})
+ }).ShouldNot(Panic())
+ })
+ })
+
+ Context("and takes a done function", func() {
+ It("should be fine", func() {
+ Ω(func() {
+ newNode(func(Done) []byte { return nil }, func([]byte) {})
+ }).ShouldNot(Panic())
+ })
+ })
+
+ Context("and takes more than one thing", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func(Done, Done) []byte { return nil }, func([]byte) {})
+ }).Should(Panic())
+ })
+ })
+
+ Context("and takes something else", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func(bool) []byte { return nil }, func([]byte) {})
+ }).Should(Panic())
+ })
+ })
+ })
+
+ Context("when the first function does not return a byte array", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func() {}, func([]byte) {})
+ }).Should(Panic())
+
+ Ω(func() {
+ newNode(func() []int { return nil }, func([]byte) {})
+ }).Should(Panic())
+ })
+ })
+ })
+
+ Describe("the second function", func() {
+ Context("when the second function takes a byte array", func() {
+ It("should be fine", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func([]byte) {})
+ }).ShouldNot(Panic())
+ })
+ })
+
+ Context("when it also takes a done channel", func() {
+ It("should be fine", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func([]byte, Done) {})
+ }).ShouldNot(Panic())
+ })
+ })
+
+ Context("if it takes anything else", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func([]byte, chan bool) {})
+ }).Should(Panic())
+
+ Ω(func() {
+ newNode(func() []byte { return nil }, func(string) {})
+ }).Should(Panic())
+ })
+ })
+
+ Context("if it takes nothing at all", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func() {})
+ }).Should(Panic())
+ })
+ })
+
+ Context("if it returns something", func() {
+ It("should panic", func() {
+ Ω(func() {
+ newNode(func() []byte { return nil }, func([]byte) []byte { return nil })
+ }).Should(Panic())
+ })
+ })
+ })
+ })
+})