...
1 package internal
2
3 import (
4 "math/rand"
5 "sort"
6
7 "github.com/onsi/ginkgo/v2/types"
8 )
9
10 type SortableSpecs struct {
11 Specs Specs
12 Indexes []int
13 }
14
15 func NewSortableSpecs(specs Specs) *SortableSpecs {
16 indexes := make([]int, len(specs))
17 for i := range specs {
18 indexes[i] = i
19 }
20 return &SortableSpecs{
21 Specs: specs,
22 Indexes: indexes,
23 }
24 }
25 func (s *SortableSpecs) Len() int { return len(s.Indexes) }
26 func (s *SortableSpecs) Swap(i, j int) { s.Indexes[i], s.Indexes[j] = s.Indexes[j], s.Indexes[i] }
27 func (s *SortableSpecs) Less(i, j int) bool {
28 a, b := s.Specs[s.Indexes[i]], s.Specs[s.Indexes[j]]
29
30 aNodes, bNodes := a.Nodes.WithType(types.NodeTypesForContainerAndIt), b.Nodes.WithType(types.NodeTypesForContainerAndIt)
31
32 firstOrderedAIdx, firstOrderedBIdx := aNodes.IndexOfFirstNodeMarkedOrdered(), bNodes.IndexOfFirstNodeMarkedOrdered()
33 if firstOrderedAIdx > -1 && firstOrderedBIdx > -1 && aNodes[firstOrderedAIdx].ID == bNodes[firstOrderedBIdx].ID {
34
35 return aNodes.FirstNodeWithType(types.NodeTypeIt).ID < bNodes.FirstNodeWithType(types.NodeTypeIt).ID
36 }
37
38
39 if firstOrderedAIdx > -1 {
40 aNodes = aNodes[:firstOrderedAIdx+1]
41 }
42 if firstOrderedBIdx > -1 {
43 bNodes = bNodes[:firstOrderedBIdx+1]
44 }
45
46 for i := 0; i < len(aNodes) && i < len(bNodes); i++ {
47 aCL, bCL := aNodes[i].CodeLocation, bNodes[i].CodeLocation
48 if aCL.FileName != bCL.FileName {
49 return aCL.FileName < bCL.FileName
50 }
51 if aCL.LineNumber != bCL.LineNumber {
52 return aCL.LineNumber < bCL.LineNumber
53 }
54 }
55
56 if len(aNodes) != len(bNodes) {
57 return len(aNodes) < len(bNodes)
58 }
59
60 for i := 0; i < len(aNodes); i++ {
61 if aNodes[i].Text != bNodes[i].Text {
62 return aNodes[i].Text < bNodes[i].Text
63 }
64 }
65
66 return aNodes[len(aNodes)-1].ID < bNodes[len(bNodes)-1].ID
67 }
68
69 type GroupedSpecIndices []SpecIndices
70 type SpecIndices []int
71
72 func OrderSpecs(specs Specs, suiteConfig types.SuiteConfig) (GroupedSpecIndices, GroupedSpecIndices) {
73
86
87
88 r := rand.New(rand.NewSource(suiteConfig.RandomSeed))
89
90
91 sortableSpecs := NewSortableSpecs(specs)
92 sort.Sort(sortableSpecs)
93
94
95
96
97 executionGroupIDs := []uint{}
98 executionGroups := map[uint]SpecIndices{}
99 for _, idx := range sortableSpecs.Indexes {
100 spec := specs[idx]
101 groupNode := spec.Nodes.FirstNodeMarkedOrdered()
102 if groupNode.IsZero() {
103 groupNode = spec.Nodes.FirstNodeWithType(types.NodeTypeIt)
104 }
105 executionGroups[groupNode.ID] = append(executionGroups[groupNode.ID], idx)
106 if len(executionGroups[groupNode.ID]) == 1 {
107 executionGroupIDs = append(executionGroupIDs, groupNode.ID)
108 }
109 }
110
111
112
113 shufflableGroupingIDs := []uint{}
114 shufflableGroupingIDToGroupIDs := map[uint][]uint{}
115
116
117
118 nodeTypesToShuffle := types.NodeTypesForContainerAndIt
119 if suiteConfig.RandomizeAllSpecs {
120 nodeTypesToShuffle = types.NodeTypeIt
121 }
122
123
124 for _, groupID := range executionGroupIDs {
125
126 representativeSpec := specs[executionGroups[groupID][0]]
127
128
129 shufflableGroupingNode := representativeSpec.Nodes.FirstNodeWithType(nodeTypesToShuffle)
130
131
132 shufflableGroupingIDToGroupIDs[shufflableGroupingNode.ID] = append(shufflableGroupingIDToGroupIDs[shufflableGroupingNode.ID], groupID)
133
134
135 if len(shufflableGroupingIDToGroupIDs[shufflableGroupingNode.ID]) == 1 {
136
137 shufflableGroupingIDs = append(shufflableGroupingIDs, shufflableGroupingNode.ID)
138 }
139 }
140
141
142 orderedGroups := GroupedSpecIndices{}
143 permutation := r.Perm(len(shufflableGroupingIDs))
144 for _, j := range permutation {
145
146 executionGroupIDsForJ := shufflableGroupingIDToGroupIDs[shufflableGroupingIDs[j]]
147
148 for _, executionGroupID := range executionGroupIDsForJ {
149 orderedGroups = append(orderedGroups, executionGroups[executionGroupID])
150 }
151 }
152
153
154 if suiteConfig.ParallelTotal == 1 {
155 return orderedGroups, GroupedSpecIndices{}
156 }
157
158
159
160
161 parallelizableGroups, serialGroups := GroupedSpecIndices{}, GroupedSpecIndices{}
162 for _, specIndices := range orderedGroups {
163 if specs[specIndices[0]].Nodes.HasNodeMarkedSerial() {
164 serialGroups = append(serialGroups, specIndices)
165 } else {
166 parallelizableGroups = append(parallelizableGroups, specIndices)
167 }
168 }
169
170 return parallelizableGroups, serialGroups
171 }
172
View as plain text