dependencies: update ginkgo to v2.7.0
The new ginkgo release adds sorting of specs. This was triggered by the observation that parallel test execution of Kubernetes E2E tests sometimes ran the same spec twice and (presumably) other specs not at all because spec order was random due to iteration over a map. Sorting should avoid that problem.
This commit is contained in:
77
vendor/github.com/onsi/ginkgo/v2/internal/ordering.go
generated
vendored
77
vendor/github.com/onsi/ginkgo/v2/internal/ordering.go
generated
vendored
@@ -7,6 +7,58 @@ import (
|
||||
"github.com/onsi/ginkgo/v2/types"
|
||||
)
|
||||
|
||||
type SortableSpecs struct {
|
||||
Specs Specs
|
||||
Indexes []int
|
||||
}
|
||||
|
||||
func NewSortableSpecs(specs Specs) *SortableSpecs {
|
||||
indexes := make([]int, len(specs))
|
||||
for i := range specs {
|
||||
indexes[i] = i
|
||||
}
|
||||
return &SortableSpecs{
|
||||
Specs: specs,
|
||||
Indexes: indexes,
|
||||
}
|
||||
}
|
||||
func (s *SortableSpecs) Len() int { return len(s.Indexes) }
|
||||
func (s *SortableSpecs) Swap(i, j int) { s.Indexes[i], s.Indexes[j] = s.Indexes[j], s.Indexes[i] }
|
||||
func (s *SortableSpecs) Less(i, j int) bool {
|
||||
a, b := s.Specs[s.Indexes[i]], s.Specs[s.Indexes[j]]
|
||||
|
||||
firstOrderedA := a.Nodes.FirstNodeMarkedOrdered()
|
||||
firstOrderedB := b.Nodes.FirstNodeMarkedOrdered()
|
||||
if firstOrderedA.ID == firstOrderedB.ID && !firstOrderedA.IsZero() {
|
||||
// strictly preserve order in ordered containers. ID will track this as IDs are generated monotonically
|
||||
return a.FirstNodeWithType(types.NodeTypeIt).ID < b.FirstNodeWithType(types.NodeTypeIt).ID
|
||||
}
|
||||
|
||||
aCLs := a.Nodes.WithType(types.NodeTypesForContainerAndIt).CodeLocations()
|
||||
bCLs := b.Nodes.WithType(types.NodeTypesForContainerAndIt).CodeLocations()
|
||||
for i := 0; i < len(aCLs) && i < len(bCLs); i++ {
|
||||
aCL, bCL := aCLs[i], bCLs[i]
|
||||
if aCL.FileName < bCL.FileName {
|
||||
return true
|
||||
} else if aCL.FileName > bCL.FileName {
|
||||
return false
|
||||
}
|
||||
if aCL.LineNumber < bCL.LineNumber {
|
||||
return true
|
||||
} else if aCL.LineNumber > bCL.LineNumber {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// either everything is equal or we have different lengths of CLs
|
||||
if len(aCLs) < len(bCLs) {
|
||||
return true
|
||||
} else if len(aCLs) > len(bCLs) {
|
||||
return false
|
||||
}
|
||||
// ok, now we are sure everything was equal. so we use the spec text to break ties
|
||||
return a.Text() < b.Text()
|
||||
}
|
||||
|
||||
type GroupedSpecIndices []SpecIndices
|
||||
type SpecIndices []int
|
||||
|
||||
@@ -28,12 +80,17 @@ func OrderSpecs(specs Specs, suiteConfig types.SuiteConfig) (GroupedSpecIndices,
|
||||
// Seed a new random source based on thee configured random seed.
|
||||
r := rand.New(rand.NewSource(suiteConfig.RandomSeed))
|
||||
|
||||
// first break things into execution groups
|
||||
// first, we sort the entire suite to ensure a deterministic order. the sort is performed by filename, then line number, and then spec text. this ensures every parallel process has the exact same spec order and is only necessary to cover the edge case where the user iterates over a map to generate specs.
|
||||
sortableSpecs := NewSortableSpecs(specs)
|
||||
sort.Sort(sortableSpecs)
|
||||
|
||||
// then we break things into execution groups
|
||||
// a group represents a single unit of execution and is a collection of SpecIndices
|
||||
// usually a group is just a single spec, however ordered containers must be preserved as a single group
|
||||
executionGroupIDs := []uint{}
|
||||
executionGroups := map[uint]SpecIndices{}
|
||||
for idx, spec := range specs {
|
||||
for _, idx := range sortableSpecs.Indexes {
|
||||
spec := specs[idx]
|
||||
groupNode := spec.Nodes.FirstNodeMarkedOrdered()
|
||||
if groupNode.IsZero() {
|
||||
groupNode = spec.Nodes.FirstNodeWithType(types.NodeTypeIt)
|
||||
@@ -48,7 +105,6 @@ func OrderSpecs(specs Specs, suiteConfig types.SuiteConfig) (GroupedSpecIndices,
|
||||
// we shuffle outermost containers. so we need to form shufflable groupings of GroupIDs
|
||||
shufflableGroupingIDs := []uint{}
|
||||
shufflableGroupingIDToGroupIDs := map[uint][]uint{}
|
||||
shufflableGroupingsIDToSortKeys := map[uint]string{}
|
||||
|
||||
// for each execution group we're going to have to pick a node to represent how the
|
||||
// execution group is grouped for shuffling:
|
||||
@@ -57,7 +113,7 @@ func OrderSpecs(specs Specs, suiteConfig types.SuiteConfig) (GroupedSpecIndices,
|
||||
nodeTypesToShuffle = types.NodeTypeIt
|
||||
}
|
||||
|
||||
//so, fo reach execution group:
|
||||
//so, for each execution group:
|
||||
for _, groupID := range executionGroupIDs {
|
||||
// pick out a representative spec
|
||||
representativeSpec := specs[executionGroups[groupID][0]]
|
||||
@@ -72,22 +128,9 @@ func OrderSpecs(specs Specs, suiteConfig types.SuiteConfig) (GroupedSpecIndices,
|
||||
if len(shufflableGroupingIDToGroupIDs[shufflableGroupingNode.ID]) == 1 {
|
||||
// record the shuffleable group ID
|
||||
shufflableGroupingIDs = append(shufflableGroupingIDs, shufflableGroupingNode.ID)
|
||||
// and record the sort key to use
|
||||
shufflableGroupingsIDToSortKeys[shufflableGroupingNode.ID] = shufflableGroupingNode.CodeLocation.String()
|
||||
}
|
||||
}
|
||||
|
||||
// now we sort the shufflable groups by the sort key. We use the shufflable group nodes code location and break ties using its node id
|
||||
sort.SliceStable(shufflableGroupingIDs, func(i, j int) bool {
|
||||
keyA := shufflableGroupingsIDToSortKeys[shufflableGroupingIDs[i]]
|
||||
keyB := shufflableGroupingsIDToSortKeys[shufflableGroupingIDs[j]]
|
||||
if keyA == keyB {
|
||||
return shufflableGroupingIDs[i] < shufflableGroupingIDs[j]
|
||||
} else {
|
||||
return keyA < keyB
|
||||
}
|
||||
})
|
||||
|
||||
// now we permute the sorted shufflable grouping IDs and build the ordered Groups
|
||||
orderedGroups := GroupedSpecIndices{}
|
||||
permutation := r.Perm(len(shufflableGroupingIDs))
|
||||
|
||||
Reference in New Issue
Block a user