@@ -113,11 +113,13 @@ extension Runner {
113
113
///
114
114
/// - Parameters:
115
115
/// - sequence: The sequence to enumerate.
116
+ /// - stage: The stage at which the runner is operating.
116
117
/// - body: The function to invoke.
117
118
///
118
119
/// - Throws: Whatever is thrown by `body`.
119
120
private static func _forEach< E> (
120
121
in sequence: some Sequence < E > ,
122
+ stage: Plan . Stage ,
121
123
_ body: @Sendable @escaping ( E) async throws -> Void
122
124
) async throws where E: Sendable {
123
125
try await withThrowingTaskGroup ( of: Void . self) { taskGroup in
@@ -128,7 +130,7 @@ extension Runner {
128
130
}
129
131
130
132
// If not parallelizing, wait after each task.
131
- if !_configuration. isParallelizationEnabled {
133
+ if stage == . globallySerialized || !_configuration. isParallelizationEnabled {
132
134
try await taskGroup. waitForAll ( )
133
135
}
134
136
}
@@ -139,6 +141,7 @@ extension Runner {
139
141
///
140
142
/// - Parameters:
141
143
/// - stepGraph: The subgraph whose root value, a step, is to be run.
144
+ /// - stage: The stage at which the runner is operating.
142
145
///
143
146
/// - Throws: Whatever is thrown from the test body. Thrown errors are
144
147
/// normally reported as test failures.
@@ -153,63 +156,53 @@ extension Runner {
153
156
/// ## See Also
154
157
///
155
158
/// - ``Runner/run()``
156
- private static func _runStep( atRootOf stepGraph: Graph < String , Plan . Step ? > ) async throws {
159
+ private static func _runStep( atRootOf stepGraph: Graph < String , Plan . Step ? > , stage : Plan . Stage ) async throws {
157
160
// Exit early if the task has already been cancelled.
158
161
try Task . checkCancellation ( )
159
162
160
- // Whether to send a `.testEnded` event at the end of running this step.
161
- // Some steps' actions may not require a final event to be sent — for
162
- // example, a skip event only sends `.testSkipped`.
163
- let shouldSendTestEnded : Bool
164
-
165
163
let configuration = _configuration
166
164
167
165
// Determine what action to take for this step.
168
- if let step = stepGraph. value {
166
+ if let step = stepGraph. value, step . starts ( in : stage ) {
169
167
Event . post ( . planStepStarted( step) , for: ( step. test, nil ) , configuration: configuration)
170
168
171
169
// Determine what kind of event to send for this step based on its action.
172
170
switch step. action {
173
171
case . run:
174
172
Event . post ( . testStarted, for: ( step. test, nil ) , configuration: configuration)
175
- shouldSendTestEnded = true
176
173
case let . skip( skipInfo) :
177
174
Event . post ( . testSkipped( skipInfo) , for: ( step. test, nil ) , configuration: configuration)
178
- shouldSendTestEnded = false
179
175
case let . recordIssue( issue) :
180
176
Event . post ( . issueRecorded( issue) , for: ( step. test, nil ) , configuration: configuration)
181
- shouldSendTestEnded = false
182
177
}
183
- } else {
184
- shouldSendTestEnded = false
185
178
}
186
179
defer {
187
- if let step = stepGraph. value {
188
- if shouldSendTestEnded {
180
+ if let step = stepGraph. value, step . ends ( in : stage ) {
181
+ if case . run = step . action {
189
182
Event . post ( . testEnded, for: ( step. test, nil ) , configuration: configuration)
190
183
}
191
184
Event . post ( . planStepEnded( step) , for: ( step. test, nil ) , configuration: configuration)
192
185
}
193
186
}
194
187
195
- if let step = stepGraph. value, case . run = step. action {
188
+ if let step = stepGraph. value, case . run = step. action, step . stage == stage {
196
189
await Test . withCurrent ( step. test) {
197
190
_ = await Issue . withErrorRecording ( at: step. test. sourceLocation, configuration: configuration) {
198
191
try await _applyScopingTraits ( for: step. test, testCase: nil ) {
199
192
// Run the test function at this step (if one is present.)
200
193
if let testCases = step. test. testCases {
201
- try await _runTestCases ( testCases, within: step)
194
+ try await _runTestCases ( testCases, within: step, stage : stage )
202
195
}
203
196
204
197
// Run the children of this test (i.e. the tests in this suite.)
205
- try await _runChildren ( of: stepGraph)
198
+ try await _runChildren ( of: stepGraph, stage : stage )
206
199
}
207
200
}
208
201
}
209
202
} else {
210
203
// There is no test at this node in the graph, so just skip down to the
211
204
// child nodes.
212
- try await _runChildren ( of: stepGraph)
205
+ try await _runChildren ( of: stepGraph, stage : stage )
213
206
}
214
207
}
215
208
@@ -234,10 +227,11 @@ extension Runner {
234
227
/// - Parameters:
235
228
/// - stepGraph: The subgraph whose root value, a step, will be used to
236
229
/// find children to run.
230
+ /// - stage: The stage at which the runner is operating.
237
231
///
238
232
/// - Throws: Whatever is thrown from the test body. Thrown errors are
239
233
/// normally reported as test failures.
240
- private static func _runChildren( of stepGraph: Graph < String , Plan . Step ? > ) async throws {
234
+ private static func _runChildren( of stepGraph: Graph < String , Plan . Step ? > , stage : Plan . Stage ) async throws {
241
235
let childGraphs = if _configuration. isParallelizationEnabled {
242
236
// Explicitly shuffle the steps to help detect accidental dependencies
243
237
// between tests due to their ordering.
@@ -267,8 +261,8 @@ extension Runner {
267
261
}
268
262
269
263
// Run the child nodes.
270
- try await _forEach ( in: childGraphs) { _, childGraph in
271
- try await _runStep ( atRootOf: childGraph)
264
+ try await _forEach ( in: childGraphs, stage : stage ) { _, childGraph in
265
+ try await _runStep ( atRootOf: childGraph, stage : stage )
272
266
}
273
267
}
274
268
@@ -277,20 +271,21 @@ extension Runner {
277
271
/// - Parameters:
278
272
/// - testCases: The test cases to be run.
279
273
/// - step: The runner plan step associated with this test case.
274
+ /// - stage: The stage at which the runner is operating.
280
275
///
281
276
/// - Throws: Whatever is thrown from a test case's body. Thrown errors are
282
277
/// normally reported as test failures.
283
278
///
284
279
/// If parallelization is supported and enabled, the generated test cases will
285
280
/// be run in parallel using a task group.
286
- private static func _runTestCases( _ testCases: some Sequence < Test . Case > , within step: Plan . Step ) async throws {
281
+ private static func _runTestCases( _ testCases: some Sequence < Test . Case > , within step: Plan . Step , stage : Plan . Stage ) async throws {
287
282
// Apply the configuration's test case filter.
288
283
let testCaseFilter = _configuration. testCaseFilter
289
284
let testCases = testCases. lazy. filter { testCase in
290
285
testCaseFilter ( testCase, step. test)
291
286
}
292
287
293
- try await _forEach ( in: testCases) { testCase in
288
+ try await _forEach ( in: testCases, stage : stage ) { testCase in
294
289
try await _runTestCase ( testCase, within: step)
295
290
}
296
291
}
@@ -384,7 +379,9 @@ extension Runner {
384
379
385
380
await withTaskGroup ( of: Void . self) { [ runner] taskGroup in
386
381
_ = taskGroup. addTaskUnlessCancelled {
387
- try ? await _runStep ( atRootOf: runner. plan. stepGraph)
382
+ for stage in Plan . Stage. allCases {
383
+ try ? await _runStep ( atRootOf: runner. plan. stepGraph, stage: stage)
384
+ }
388
385
}
389
386
await taskGroup. waitForAll ( )
390
387
}
0 commit comments