Skip to content

Commit 759174d

Browse files
authored
Avoid using temp_await in SwiftTestTool.swift (#7016)
Follow up to #7009, which provides the detailed motivation: we should avoid `temp_await` as it can lead to deadlocks when combined with Swift Concurrency.
1 parent 056f9f8 commit 759174d

File tree

4 files changed

+57
-31
lines changed

4 files changed

+57
-31
lines changed

Sources/Commands/SwiftTestTool.swift

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public enum TestOutput: String, ExpressibleByArgument {
185185
}
186186

187187
/// swift-test tool namespace
188-
public struct SwiftTestTool: SwiftCommand {
188+
public struct SwiftTestTool: AsyncSwiftCommand {
189189
public static var configuration = CommandConfiguration(
190190
commandName: "test",
191191
_superCommandName: "swift",
@@ -206,7 +206,7 @@ public struct SwiftTestTool: SwiftCommand {
206206

207207
// MARK: - XCTest
208208

209-
private func xctestRun(_ swiftTool: SwiftTool) throws {
209+
private func xctestRun(_ swiftTool: SwiftTool) async throws {
210210
// validate XCTest available on darwin based systems
211211
let toolchain = try swiftTool.getTargetToolchain()
212212
let isHostTestingAvailable = try swiftTool.getHostToolchain().swiftSDK.supportsTesting
@@ -224,7 +224,13 @@ public struct SwiftTestTool: SwiftCommand {
224224
let testProducts = try buildTestsIfNeeded(swiftTool: swiftTool, library: .xctest)
225225
if !self.options.shouldRunInParallel {
226226
let xctestArgs = try xctestArgs(for: testProducts, swiftTool: swiftTool)
227-
try runTestProducts(testProducts, additionalArguments: xctestArgs, buildParameters: buildParameters, swiftTool: swiftTool, library: .xctest)
227+
try await runTestProducts(
228+
testProducts,
229+
additionalArguments: xctestArgs,
230+
buildParameters: buildParameters,
231+
swiftTool: swiftTool,
232+
library: .xctest
233+
)
228234
} else {
229235
let testSuites = try TestingSupport.getTestSuites(
230236
in: testProducts,
@@ -269,7 +275,7 @@ public struct SwiftTestTool: SwiftCommand {
269275

270276
// process code Coverage if request
271277
if self.options.enableCodeCoverage, runner.ranSuccessfully {
272-
try processCodeCoverage(testProducts, swiftTool: swiftTool, library: .xctest)
278+
try await processCodeCoverage(testProducts, swiftTool: swiftTool, library: .xctest)
273279
}
274280

275281
if !runner.ranSuccessfully {
@@ -334,16 +340,22 @@ public struct SwiftTestTool: SwiftCommand {
334340

335341
// MARK: - swift-testing
336342

337-
private func swiftTestingRun(_ swiftTool: SwiftTool) throws {
343+
private func swiftTestingRun(_ swiftTool: SwiftTool) async throws {
338344
let buildParameters = try swiftTool.buildParametersForTest(options: self.options, library: .swiftTesting)
339345
let testProducts = try buildTestsIfNeeded(swiftTool: swiftTool, library: .swiftTesting)
340346
let additionalArguments = Array(CommandLine.arguments.dropFirst())
341-
try runTestProducts(testProducts, additionalArguments: additionalArguments, buildParameters: buildParameters, swiftTool: swiftTool, library: .swiftTesting)
347+
try await runTestProducts(
348+
testProducts,
349+
additionalArguments: additionalArguments,
350+
buildParameters: buildParameters,
351+
swiftTool: swiftTool,
352+
library: .swiftTesting
353+
)
342354
}
343355

344356
// MARK: - Common implementation
345357

346-
public func run(_ swiftTool: SwiftTool) throws {
358+
public func run(_ swiftTool: SwiftTool) async throws {
347359
do {
348360
// Validate commands arguments
349361
try self.validateArguments(observabilityScope: swiftTool.observabilityScope)
@@ -353,22 +365,28 @@ public struct SwiftTestTool: SwiftCommand {
353365
}
354366

355367
if self.options.shouldPrintCodeCovPath {
356-
try printCodeCovPath(swiftTool)
368+
try await printCodeCovPath(swiftTool)
357369
} else if self.options._deprecated_shouldListTests {
358370
// backward compatibility 6/2022 for deprecation of flag into a subcommand
359371
let command = try List.parse()
360372
try command.run(swiftTool)
361373
} else {
362374
if options.sharedOptions.enableSwiftTestingLibrarySupport {
363-
try swiftTestingRun(swiftTool)
375+
try await swiftTestingRun(swiftTool)
364376
}
365377
if options.sharedOptions.enableXCTestSupport {
366-
try xctestRun(swiftTool)
378+
try await xctestRun(swiftTool)
367379
}
368380
}
369381
}
370382

371-
private func runTestProducts(_ testProducts: [BuiltTestProduct], additionalArguments: [String], buildParameters: BuildParameters, swiftTool: SwiftTool, library: BuildParameters.Testing.Library) throws {
383+
private func runTestProducts(
384+
_ testProducts: [BuiltTestProduct],
385+
additionalArguments: [String],
386+
buildParameters: BuildParameters,
387+
swiftTool: SwiftTool,
388+
library: BuildParameters.Testing.Library
389+
) async throws {
372390
// Clean out the code coverage directory that may contain stale
373391
// profraw files from a previous run of the code coverage tool.
374392
if self.options.enableCodeCoverage {
@@ -403,7 +421,7 @@ public struct SwiftTestTool: SwiftCommand {
403421
}
404422

405423
if self.options.enableCodeCoverage, ranSuccessfully {
406-
try processCodeCoverage(testProducts, swiftTool: swiftTool, library: library)
424+
try await processCodeCoverage(testProducts, swiftTool: swiftTool, library: library)
407425
}
408426

409427
if self.options.enableExperimentalTestOutput, !ranSuccessfully {
@@ -443,16 +461,18 @@ public struct SwiftTestTool: SwiftCommand {
443461
}
444462

445463
/// Processes the code coverage data and emits a json.
446-
private func processCodeCoverage(_ testProducts: [BuiltTestProduct], swiftTool: SwiftTool, library: BuildParameters.Testing.Library) throws {
464+
private func processCodeCoverage(
465+
_ testProducts: [BuiltTestProduct],
466+
swiftTool: SwiftTool,
467+
library: BuildParameters.Testing.Library
468+
) async throws {
447469
let workspace = try swiftTool.getActiveWorkspace()
448470
let root = try swiftTool.getWorkspaceRoot()
449-
let rootManifests = try temp_await {
450-
workspace.loadRootManifests(
451-
packages: root.packages,
452-
observabilityScope: swiftTool.observabilityScope,
453-
completion: $0
454-
)
455-
}
471+
let rootManifests = try await workspace.loadRootManifests(
472+
packages: root.packages,
473+
observabilityScope: swiftTool.observabilityScope
474+
)
475+
456476
guard let rootManifest = rootManifests.values.first else {
457477
throw StringError("invalid manifests at \(root.packages)")
458478
}
@@ -548,16 +568,14 @@ public struct SwiftTestTool: SwiftCommand {
548568
}
549569

550570
extension SwiftTestTool {
551-
func printCodeCovPath(_ swiftTool: SwiftTool) throws {
571+
func printCodeCovPath(_ swiftTool: SwiftTool) async throws {
552572
let workspace = try swiftTool.getActiveWorkspace()
553573
let root = try swiftTool.getWorkspaceRoot()
554-
let rootManifests = try temp_await {
555-
workspace.loadRootManifests(
556-
packages: root.packages,
557-
observabilityScope: swiftTool.observabilityScope,
558-
completion: $0
559-
)
560-
}
574+
let rootManifests = try await workspace.loadRootManifests(
575+
packages: root.packages,
576+
observabilityScope: swiftTool.observabilityScope
577+
)
578+
561579
guard let rootManifest = rootManifests.values.first else {
562580
throw StringError("invalid manifests at \(root.packages)")
563581
}

Sources/swift-package-manager/SwiftPM.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct SwiftPM {
3131
case "swift-experimental-sdk":
3232
await SwiftSDKTool.main()
3333
case "swift-test":
34-
SwiftTestTool.main()
34+
await SwiftTestTool.main()
3535
case "swift-run":
3636
SwiftRunTool.main()
3737
case "swift-package-collection":

Sources/swift-test/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
add_executable(swift-test
10-
main.swift)
10+
Entrypoint.swift)
1111
target_link_libraries(swift-test PRIVATE
1212
Commands)
1313

14+
target_compile_options(swift-test PRIVATE
15+
-parse-as-library)
16+
1417
install(TARGETS swift-test
1518
RUNTIME DESTINATION bin)

Sources/swift-test/main.swift renamed to Sources/swift-test/Entrypoint.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@
1212

1313
import Commands
1414

15-
SwiftTestTool.main()
15+
@main
16+
struct Entrypoint {
17+
static func main() async {
18+
await SwiftTestTool.main()
19+
}
20+
}

0 commit comments

Comments
 (0)