Skip to content

Commit 1d0be84

Browse files
authored
Remove uses of temp_await from SwiftTestCommand (#7382)
This prevents possible deadlocks that can be caused by blocking Swift Concurrency threads with semaphores.
1 parent 68b6236 commit 1d0be84

File tree

7 files changed

+39
-24
lines changed

7 files changed

+39
-24
lines changed

Sources/Commands/SwiftTestCommand.swift

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ package enum TestOutput: String, ExpressibleByArgument {
179179
}
180180

181181
/// swift-test tool namespace
182-
package struct SwiftTestCommand: SwiftCommand {
182+
package struct SwiftTestCommand: AsyncSwiftCommand {
183183
package static var configuration = CommandConfiguration(
184184
commandName: "test",
185185
_superCommandName: "swift",
@@ -200,7 +200,7 @@ package struct SwiftTestCommand: SwiftCommand {
200200

201201
// MARK: - XCTest
202202

203-
private func xctestRun(_ swiftCommandState: SwiftCommandState) throws {
203+
private func xctestRun(_ swiftCommandState: SwiftCommandState) async throws {
204204
// validate XCTest available on darwin based systems
205205
let toolchain = try swiftCommandState.getTargetToolchain()
206206
let isHostTestingAvailable = try swiftCommandState.getHostToolchain().swiftSDK.supportsTesting
@@ -218,7 +218,7 @@ package struct SwiftTestCommand: SwiftCommand {
218218
let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .xctest)
219219
if !self.options.shouldRunInParallel {
220220
let xctestArgs = try xctestArgs(for: testProducts, swiftCommandState: swiftCommandState)
221-
try runTestProducts(
221+
try await runTestProducts(
222222
testProducts,
223223
additionalArguments: xctestArgs,
224224
buildParameters: buildParameters,
@@ -269,7 +269,7 @@ package struct SwiftTestCommand: SwiftCommand {
269269

270270
// process code Coverage if request
271271
if self.options.enableCodeCoverage, runner.ranSuccessfully {
272-
try processCodeCoverage(testProducts, swiftCommandState: swiftCommandState, library: .xctest)
272+
try await processCodeCoverage(testProducts, swiftCommandState: swiftCommandState, library: .xctest)
273273
}
274274

275275
if !runner.ranSuccessfully {
@@ -337,11 +337,11 @@ package struct SwiftTestCommand: SwiftCommand {
337337

338338
// MARK: - swift-testing
339339

340-
private func swiftTestingRun(_ swiftCommandState: SwiftCommandState) throws {
340+
private func swiftTestingRun(_ swiftCommandState: SwiftCommandState) async throws {
341341
let buildParameters = try swiftCommandState.buildParametersForTest(options: self.options, library: .swiftTesting)
342342
let testProducts = try buildTestsIfNeeded(swiftCommandState: swiftCommandState, library: .swiftTesting)
343343
let additionalArguments = Array(CommandLine.arguments.dropFirst())
344-
try runTestProducts(
344+
try await runTestProducts(
345345
testProducts,
346346
additionalArguments: additionalArguments,
347347
buildParameters: buildParameters,
@@ -352,7 +352,7 @@ package struct SwiftTestCommand: SwiftCommand {
352352

353353
// MARK: - Common implementation
354354

355-
package func run(_ swiftCommandState: SwiftCommandState) throws {
355+
package func run(_ swiftCommandState: SwiftCommandState) async throws {
356356
do {
357357
// Validate commands arguments
358358
try self.validateArguments(observabilityScope: swiftCommandState.observabilityScope)
@@ -369,10 +369,10 @@ package struct SwiftTestCommand: SwiftCommand {
369369
try command.run(swiftCommandState)
370370
} else {
371371
if try options.testLibraryOptions.enableSwiftTestingLibrarySupport(swiftCommandState: swiftCommandState) {
372-
try swiftTestingRun(swiftCommandState)
372+
try await swiftTestingRun(swiftCommandState)
373373
}
374374
if options.testLibraryOptions.enableXCTestSupport {
375-
try xctestRun(swiftCommandState)
375+
try await xctestRun(swiftCommandState)
376376
}
377377
}
378378
}
@@ -383,7 +383,7 @@ package struct SwiftTestCommand: SwiftCommand {
383383
buildParameters: BuildParameters,
384384
swiftCommandState: SwiftCommandState,
385385
library: BuildParameters.Testing.Library
386-
) throws {
386+
) async throws {
387387
// Clean out the code coverage directory that may contain stale
388388
// profraw files from a previous run of the code coverage tool.
389389
if self.options.enableCodeCoverage {
@@ -418,7 +418,7 @@ package struct SwiftTestCommand: SwiftCommand {
418418
}
419419

420420
if self.options.enableCodeCoverage, ranSuccessfully {
421-
try processCodeCoverage(testProducts, swiftCommandState: swiftCommandState, library: library)
421+
try await processCodeCoverage(testProducts, swiftCommandState: swiftCommandState, library: library)
422422
}
423423

424424
if self.options.enableExperimentalTestOutput, !ranSuccessfully {
@@ -462,16 +462,13 @@ package struct SwiftTestCommand: SwiftCommand {
462462
_ testProducts: [BuiltTestProduct],
463463
swiftCommandState: SwiftCommandState,
464464
library: BuildParameters.Testing.Library
465-
) throws {
465+
) async throws {
466466
let workspace = try swiftCommandState.getActiveWorkspace()
467467
let root = try swiftCommandState.getWorkspaceRoot()
468-
let rootManifests = try temp_await {
469-
workspace.loadRootManifests(
470-
packages: root.packages,
471-
observabilityScope: swiftCommandState.observabilityScope,
472-
completion: $0
473-
)
474-
}
468+
let rootManifests = try await workspace.loadRootManifests(
469+
packages: root.packages,
470+
observabilityScope: swiftCommandState.observabilityScope
471+
)
475472
guard let rootManifest = rootManifests.values.first else {
476473
throw StringError("invalid manifests at \(root.packages)")
477474
}

Sources/SPMTestSupport/XCTAssertHelpers.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ package func XCTAssertAsyncFalse(
170170
XCTAssertFalse(result, message(), file: file, line: line)
171171
}
172172

173+
package func XCTAssertAsyncNil(
174+
_ expression: @autoclosure () async throws -> Any?,
175+
_ message: @autoclosure () -> String = "",
176+
file: StaticString = #filePath,
177+
line: UInt = #line
178+
) async rethrows {
179+
let result = try await expression()
180+
XCTAssertNil(result, message(), file: file, line: line)
181+
}
182+
173183
package func XCTAssertThrowsCommandExecutionError<T>(
174184
_ expression: @autoclosure () throws -> T,
175185
_ message: @autoclosure () -> String = "",

Sources/swift-package-manager/SwiftPM.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct SwiftPM {
4444
case "swift-experimental-sdk":
4545
await SwiftSDKCommand.main()
4646
case "swift-test":
47-
SwiftTestCommand.main()
47+
await SwiftTestCommand.main()
4848
case "swift-run":
4949
await SwiftRunCommand.main()
5050
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-
SwiftTestCommand.main()
15+
@main
16+
struct Entrypoint {
17+
static func main() async {
18+
await SwiftTestCommand.main()
19+
}
20+
}

Tests/BuildTests/PluginsBuildPlanTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import PackageModel
1919
final class PluginsBuildPlanTests: XCTestCase {
2020
func testBuildToolsDatabasePath() throws {
2121
try fixture(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in
22-
let (stdout, stderr) = try executeSwiftBuild(fixturePath)
22+
let (stdout, _) = try executeSwiftBuild(fixturePath)
2323
XCTAssertMatch(stdout, .contains("Build complete!"))
2424
XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/plugins/tools/build.db"))))
2525
}

Tests/PackageGraphPerformanceTests/PackageGraphPerfTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ final class PackageGraphPerfTests: XCTestCasePerf {
151151
measure {
152152
do {
153153
for _ in 0..<N {
154-
_ = try loadPackageGraph(
154+
_ = try loadModulesGraph(
155155
fileSystem: fs,
156156
manifests: [root] + packageSequence,
157157
observabilityScope: observability.topScope

0 commit comments

Comments
 (0)