From f268bd5333719e1e881ed353180341337b479a12 Mon Sep 17 00:00:00 2001 From: Andrew Hoos Date: Wed, 15 Nov 2023 17:49:42 -0800 Subject: [PATCH 1/3] Move BasicTests async support Make sure callback methods can't block the concurrency pool Add async alternatives for Archiver Add async alternatives for AuthorizationWriter Mark non-async methods noasync to encourage migration to async Removed a cancellation test that was not actually exercising production code Co-authored-by: Max Desiatov --- Sources/Basics/Archiver/Archiver.swift | 24 ++- Sources/Basics/AuthorizationProvider.swift | 26 +++ .../Concurrency/ConcurrencyHelpers.swift | 28 +++ Sources/SPMTestSupport/XCTAssertHelpers.swift | 37 ++++ .../Archiver/TarArchiverTests.swift | 46 ++--- .../Archiver/UniversalArchiverTests.swift | 54 +++--- .../Archiver/ZipArchiverTests.swift | 160 +++--------------- .../AuthorizationProviderTests.swift | 59 +++---- 8 files changed, 206 insertions(+), 228 deletions(-) diff --git a/Sources/Basics/Archiver/Archiver.swift b/Sources/Basics/Archiver/Archiver.swift index 64d6edc9717..9763ec60ce4 100644 --- a/Sources/Basics/Archiver/Archiver.swift +++ b/Sources/Basics/Archiver/Archiver.swift @@ -23,6 +23,7 @@ public protocol Archiver { /// - archivePath: The `AbsolutePath` to the archive to extract. /// - destinationPath: The `AbsolutePath` to the directory to extract to. /// - completion: The completion handler that will be called when the operation finishes to notify of its success. + @available(*, noasync, message: "Use the async alternative") func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath, @@ -35,6 +36,7 @@ public protocol Archiver { /// - directory: The `AbsolutePath` to the archive to extract. /// - destinationPath: The `AbsolutePath` to the directory to extract to. /// - completion: The completion handler that will be called when the operation finishes to notify of its success. + @available(*, noasync, message: "Use the async alternative") func compress( directory: AbsolutePath, to destinationPath: AbsolutePath, @@ -46,6 +48,7 @@ public protocol Archiver { /// - Parameters: /// - path: The `AbsolutePath` to the archive to validate. /// - completion: The completion handler that will be called when the operation finishes to notify of its success. + @available(*, noasync, message: "Use the async alternative") func validate( path: AbsolutePath, completion: @escaping (Result) -> Void @@ -57,8 +60,25 @@ extension Archiver { from archivePath: AbsolutePath, to destinationPath: AbsolutePath ) async throws { - try await withCheckedThrowingContinuation { - self.extract(from: archivePath, to: destinationPath, completion: $0.resume(with:)) + try await safe_async { + self.extract(from: archivePath, to: destinationPath, completion: $0) + } + } + + public func compress( + directory: AbsolutePath, + to: AbsolutePath + ) async throws { + try await safe_async { + self.compress(directory: directory, to: to, completion: $0) + } + } + + public func validate( + path: AbsolutePath + ) async throws -> Bool { + try await safe_async { + self.validate(path: path, completion: $0) } } } diff --git a/Sources/Basics/AuthorizationProvider.swift b/Sources/Basics/AuthorizationProvider.swift index 1724603f590..11e80cb79ed 100644 --- a/Sources/Basics/AuthorizationProvider.swift +++ b/Sources/Basics/AuthorizationProvider.swift @@ -23,6 +23,7 @@ public protocol AuthorizationProvider { } public protocol AuthorizationWriter { + @available(*, noasync, message: "Use the async alternative") func addOrUpdate( for url: URL, user: String, @@ -31,9 +32,34 @@ public protocol AuthorizationWriter { callback: @escaping (Result) -> Void ) + @available(*, noasync, message: "Use the async alternative") func remove(for url: URL, callback: @escaping (Result) -> Void) } +public extension AuthorizationWriter { + func addOrUpdate( + for url: URL, + user: String, + password: String, + persist: Bool = true + ) async throws { + try await safe_async { + self.addOrUpdate( + for: url, + user: user, + password: password, + persist: persist, + callback: $0) + } + } + + func remove(for url: URL) async throws { + try await safe_async { + self.remove(for: url, callback: $0) + } + } +} + public enum AuthorizationProviderError: Error { case invalidURLHost case notFound diff --git a/Sources/Basics/Concurrency/ConcurrencyHelpers.swift b/Sources/Basics/Concurrency/ConcurrencyHelpers.swift index 8c39a89f26a..8276f5e5d07 100644 --- a/Sources/Basics/Concurrency/ConcurrencyHelpers.swift +++ b/Sources/Basics/Concurrency/ConcurrencyHelpers.swift @@ -46,6 +46,34 @@ extension DispatchQueue { ) } +/// Bridges between potentially blocking methods that take a result completion closure and async/await +public func safe_async(_ body: @escaping (@escaping (Result) -> Void) -> Void) async throws -> T { + try await withCheckedThrowingContinuation { continuation in + // It is possible that body make block indefinitely on a lock, sempahore, + // or similar then synchrously call the completion handler. For full safety + // it is essential to move the execution off the swift concurrency pool + DispatchQueue.sharedConcurrent.async { + body { + continuation.resume(with: $0) + } + } + } +} + +/// Bridges between potentially blocking methods that take a result completion closure and async/await +public func safe_async(_ body: @escaping (@escaping (Result) -> Void) -> Void) async -> T { + await withCheckedContinuation { continuation in + // It is possible that body make block indefinitely on a lock, sempahore, + // or similar then synchrously call the completion handler. For full safety + // it is essential to move the execution off the swift concurrency pool + DispatchQueue.sharedConcurrent.async { + body { + continuation.resume(with: $0) + } + } + } +} + #if !canImport(Darwin) // As of Swift 5.7 and 5.8 swift-corelibs-foundation doesn't have `Sendable` annotations yet. extension URL: @unchecked Sendable {} diff --git a/Sources/SPMTestSupport/XCTAssertHelpers.swift b/Sources/SPMTestSupport/XCTAssertHelpers.swift index 5459b1c912e..a0fcf5e5360 100644 --- a/Sources/SPMTestSupport/XCTAssertHelpers.swift +++ b/Sources/SPMTestSupport/XCTAssertHelpers.swift @@ -49,6 +49,23 @@ public func XCTSkipIfCI(file: StaticString = #filePath, line: UInt = #line) thro } } +/// An `async`-friendly replacement for `XCTAssertThrowsError`. +public func XCTAssertAsyncThrowsError( + _ expression: @autoclosure () async throws -> T, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line, + _ errorHandler: (_ error: any Error) -> Void = { _ in } +) async { + do { + _ = try await expression() + XCTFail(message(), file: file, line: line) + } catch { + errorHandler(error) + } +} + + public func XCTAssertBuilds( _ path: AbsolutePath, configurations: Set = [.Debug, .Release], @@ -133,6 +150,26 @@ public func XCTAssertEqual( XCTAssertEqual(actual, expected, file: file, line: line) } +public func XCTAssertAsyncTrue( + _ expression: @autoclosure () async throws -> Bool, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line +) async rethrows { + let result = try await expression() + XCTAssertTrue(result, message(), file: file, line: line) +} + +public func XCTAssertAsyncFalse( + _ expression: @autoclosure () async throws -> Bool, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line +) async rethrows { + let result = try await expression() + XCTAssertFalse(result, message(), file: file, line: line) +} + public func XCTAssertThrowsCommandExecutionError( _ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", diff --git a/Tests/BasicsTests/Archiver/TarArchiverTests.swift b/Tests/BasicsTests/Archiver/TarArchiverTests.swift index 2efb0848171..d4c3ca748ca 100644 --- a/Tests/BasicsTests/Archiver/TarArchiverTests.swift +++ b/Tests/BasicsTests/Archiver/TarArchiverTests.swift @@ -19,51 +19,51 @@ import class TSCBasic.InMemoryFileSystem import struct TSCBasic.FileSystemError final class TarArchiverTests: XCTestCase { - func testSuccess() throws { - try testWithTemporaryDirectory { tmpdir in + func testSuccess() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = TarArchiver(fileSystem: localFileSystem) let inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "archive.tar.gz") - try archiver.extract(from: inputArchivePath, to: tmpdir) + try await archiver.extract(from: inputArchivePath, to: tmpdir) let content = tmpdir.appending("file") XCTAssert(localFileSystem.exists(content)) XCTAssertEqual((try? localFileSystem.readFileContents(content))?.cString, "Hello World!") } } - func testArchiveDoesntExist() { + func testArchiveDoesntExist() async { let fileSystem = InMemoryFileSystem() let archiver = TarArchiver(fileSystem: fileSystem) let archive = AbsolutePath("/archive.tar.gz") - XCTAssertThrowsError(try archiver.extract(from: archive, to: "/")) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: archive, to: "/")) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, archive)) } } - func testDestinationDoesntExist() throws { + func testDestinationDoesntExist() async throws { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.tar.gz") let archiver = TarArchiver(fileSystem: fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.tar.gz", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.tar.gz", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testDestinationIsFile() throws { + func testDestinationIsFile() async { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.tar.gz", "/destination") let archiver = TarArchiver(fileSystem: fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.tar.gz", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.tar.gz", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testInvalidArchive() throws { - try testWithTemporaryDirectory { tmpdir in + func testInvalidArchive() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = TarArchiver(fileSystem: localFileSystem) let inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.tar.gz") - XCTAssertThrowsError(try archiver.extract(from: inputArchivePath, to: tmpdir)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in #if os(Linux) XCTAssertMatch((error as? StringError)?.description, .contains("not in gzip format")) #else @@ -73,39 +73,39 @@ final class TarArchiverTests: XCTestCase { } } - func testValidation() throws { + func testValidation() async throws { // valid - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = TarArchiver(fileSystem: localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "archive.tar.gz") - XCTAssertTrue(try archiver.validate(path: path)) + try await XCTAssertAsyncTrue(try await archiver.validate(path: path)) } // invalid - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = TarArchiver(fileSystem: localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.tar.gz") - XCTAssertFalse(try archiver.validate(path: path)) + try await XCTAssertAsyncFalse(try await archiver.validate(path: path)) } // error - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = TarArchiver(fileSystem: localFileSystem) let path = AbsolutePath.root.appending("does_not_exist.tar.gz") - XCTAssertThrowsError(try archiver.validate(path: path)) { error in + await XCTAssertAsyncThrowsError(try await archiver.validate(path: path)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, path)) } } } - func testCompress() throws { + func testCompress() async throws { #if os(Linux) guard SPM_posix_spawn_file_actions_addchdir_np_supported() else { throw XCTSkip("working directory not supported on this platform") } #endif - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = TarArchiver(fileSystem: localFileSystem) let rootDir = tmpdir.appending(component: UUID().uuidString) @@ -122,12 +122,12 @@ final class TarArchiverTests: XCTestCase { try localFileSystem.writeFileContents(dir2.appending("file4.txt"), string: "Hello World 4!") let archivePath = tmpdir.appending(component: UUID().uuidString + ".tar.gz") - try archiver.compress(directory: rootDir, to: archivePath) + try await archiver.compress(directory: rootDir, to: archivePath) XCTAssertFileExists(archivePath) let extractRootDir = tmpdir.appending(component: UUID().uuidString) try localFileSystem.createDirectory(extractRootDir) - try archiver.extract(from: archivePath, to: extractRootDir) + try await archiver.extract(from: archivePath, to: extractRootDir) try localFileSystem.stripFirstLevel(of: extractRootDir) XCTAssertFileExists(extractRootDir.appending("file1.txt")) diff --git a/Tests/BasicsTests/Archiver/UniversalArchiverTests.swift b/Tests/BasicsTests/Archiver/UniversalArchiverTests.swift index 685d6e954ee..363b20f3537 100644 --- a/Tests/BasicsTests/Archiver/UniversalArchiverTests.swift +++ b/Tests/BasicsTests/Archiver/UniversalArchiverTests.swift @@ -19,60 +19,60 @@ import class TSCBasic.InMemoryFileSystem import struct TSCBasic.FileSystemError final class UniversalArchiverTests: XCTestCase { - func testSuccess() throws { - try testWithTemporaryDirectory { tmpdir in + func testSuccess() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = UniversalArchiver(localFileSystem) let inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "archive.tar.gz") let tarDestination = tmpdir.appending("tar") try localFileSystem.createDirectory(tarDestination) - try archiver.extract(from: inputArchivePath, to: tarDestination) + try await archiver.extract(from: inputArchivePath, to: tarDestination) let tarContent = tarDestination.appending("file") XCTAssert(localFileSystem.exists(tarContent)) XCTAssertEqual((try? localFileSystem.readFileContents(tarContent))?.cString, "Hello World!") let zipDestination = tmpdir.appending("zip") try localFileSystem.createDirectory(zipDestination) - try archiver.extract(from: inputArchivePath, to: zipDestination) + try await archiver.extract(from: inputArchivePath, to: zipDestination) let zipContent = zipDestination.appending("file") XCTAssert(localFileSystem.exists(zipContent)) XCTAssertEqual((try? localFileSystem.readFileContents(zipContent))?.cString, "Hello World!") } } - func testArchiveDoesntExist() { + func testArchiveDoesntExist() async { let fileSystem = InMemoryFileSystem() let archiver = UniversalArchiver(fileSystem) let archive = AbsolutePath("/archive.tar.gz") - XCTAssertThrowsError(try archiver.extract(from: archive, to: "/")) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: archive, to: "/")) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, archive)) } } - func testDestinationDoesntExist() throws { + func testDestinationDoesntExist() async throws { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.tar.gz") let archiver = UniversalArchiver(fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.tar.gz", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.tar.gz", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testDestinationIsFile() throws { + func testDestinationIsFile() async throws { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.tar.gz", "/destination") let archiver = UniversalArchiver(fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.tar.gz", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.tar.gz", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testInvalidArchive() throws { - try testWithTemporaryDirectory { tmpdir in + func testInvalidArchive() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = UniversalArchiver(localFileSystem) var inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.tar.gz") - XCTAssertThrowsError(try archiver.extract(from: inputArchivePath, to: tmpdir)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in #if os(Linux) XCTAssertMatch((error as? StringError)?.description, .contains("not in gzip format")) #else @@ -82,7 +82,7 @@ final class UniversalArchiverTests: XCTestCase { inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.zip") - XCTAssertThrowsError(try archiver.extract(from: inputArchivePath, to: tmpdir)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in #if os(Windows) XCTAssertMatch((error as? StringError)?.description, .contains("Unrecognized archive format")) #else @@ -92,39 +92,39 @@ final class UniversalArchiverTests: XCTestCase { } } - func testValidation() throws { + func testValidation() async throws { // valid - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = UniversalArchiver(localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "archive.tar.gz") - XCTAssertTrue(try archiver.validate(path: path)) + try await XCTAssertAsyncTrue(try await archiver.validate(path: path)) } // invalid - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = UniversalArchiver(localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.tar.gz") - XCTAssertFalse(try archiver.validate(path: path)) + try await XCTAssertAsyncFalse(try await archiver.validate(path: path)) } // error - try testWithTemporaryDirectory { _ in + try await testWithTemporaryDirectory { _ in let archiver = UniversalArchiver(localFileSystem) let path = AbsolutePath.root.appending("does_not_exist.tar.gz") - XCTAssertThrowsError(try archiver.validate(path: path)) { error in + await XCTAssertAsyncThrowsError(try await archiver.validate(path: path)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, path)) } } } - func testCompress() throws { + func testCompress() async throws { #if os(Linux) guard SPM_posix_spawn_file_actions_addchdir_np_supported() else { throw XCTSkip("working directory not supported on this platform") } #endif - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = UniversalArchiver(localFileSystem) let rootDir = tmpdir.appending(component: UUID().uuidString) @@ -141,12 +141,12 @@ final class UniversalArchiverTests: XCTestCase { try localFileSystem.writeFileContents(dir2.appending("file4.txt"), string: "Hello World 4!") var archivePath = tmpdir.appending(component: UUID().uuidString + ".tar.gz") - try archiver.compress(directory: rootDir, to: archivePath) + try await archiver.compress(directory: rootDir, to: archivePath) XCTAssertFileExists(archivePath) var extractRootDir = tmpdir.appending(component: UUID().uuidString) try localFileSystem.createDirectory(extractRootDir) - try archiver.extract(from: archivePath, to: extractRootDir) + try await archiver.extract(from: archivePath, to: extractRootDir) try localFileSystem.stripFirstLevel(of: extractRootDir) XCTAssertFileExists(extractRootDir.appending("file1.txt")) @@ -177,12 +177,12 @@ final class UniversalArchiverTests: XCTestCase { ) archivePath = tmpdir.appending(component: UUID().uuidString + ".zip") - try archiver.compress(directory: rootDir, to: archivePath) + try await archiver.compress(directory: rootDir, to: archivePath) XCTAssertFileExists(archivePath) extractRootDir = tmpdir.appending(component: UUID().uuidString) try localFileSystem.createDirectory(extractRootDir) - try archiver.extract(from: archivePath, to: extractRootDir) + try await archiver.extract(from: archivePath, to: extractRootDir) try localFileSystem.stripFirstLevel(of: extractRootDir) XCTAssertFileExists(extractRootDir.appending("file1.txt")) diff --git a/Tests/BasicsTests/Archiver/ZipArchiverTests.swift b/Tests/BasicsTests/Archiver/ZipArchiverTests.swift index 5883e7c42d6..d0441be4b56 100644 --- a/Tests/BasicsTests/Archiver/ZipArchiverTests.swift +++ b/Tests/BasicsTests/Archiver/ZipArchiverTests.swift @@ -19,50 +19,50 @@ import class TSCBasic.InMemoryFileSystem import struct TSCBasic.FileSystemError class ZipArchiverTests: XCTestCase { - func testZipArchiverSuccess() throws { - try testWithTemporaryDirectory { tmpdir in + func testZipArchiverSuccess() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let inputArchivePath = AbsolutePath(#file).parentDirectory.appending(components: "Inputs", "archive.zip") - try archiver.extract(from: inputArchivePath, to: tmpdir) + try await archiver.extract(from: inputArchivePath, to: tmpdir) let content = tmpdir.appending("file") XCTAssert(localFileSystem.exists(content)) XCTAssertEqual((try? localFileSystem.readFileContents(content))?.cString, "Hello World!") } } - func testZipArchiverArchiveDoesntExist() { + func testZipArchiverArchiveDoesntExist() async { let fileSystem = InMemoryFileSystem() let archiver = ZipArchiver(fileSystem: fileSystem) let archive = AbsolutePath("/archive.zip") - XCTAssertThrowsError(try archiver.extract(from: archive, to: "/")) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: archive, to: "/")) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, archive)) } } - func testZipArchiverDestinationDoesntExist() throws { + func testZipArchiverDestinationDoesntExist() async throws { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.zip") let archiver = ZipArchiver(fileSystem: fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.zip", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.zip", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testZipArchiverDestinationIsFile() throws { + func testZipArchiverDestinationIsFile() async throws { let fileSystem = InMemoryFileSystem(emptyFiles: "/archive.zip", "/destination") let archiver = ZipArchiver(fileSystem: fileSystem) let destination = AbsolutePath("/destination") - XCTAssertThrowsError(try archiver.extract(from: "/archive.zip", to: destination)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: "/archive.zip", to: destination)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.notDirectory, destination)) } } - func testZipArchiverInvalidArchive() throws { - try testWithTemporaryDirectory { tmpdir in + func testZipArchiverInvalidArchive() async throws { + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let inputArchivePath = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.zip") - XCTAssertThrowsError(try archiver.extract(from: inputArchivePath, to: tmpdir)) { error in + await XCTAssertAsyncThrowsError(try await archiver.extract(from: inputArchivePath, to: tmpdir)) { error in #if os(Windows) XCTAssertMatch((error as? StringError)?.description, .contains("Unrecognized archive format")) #else @@ -72,39 +72,39 @@ class ZipArchiverTests: XCTestCase { } } - func testValidation() throws { + func testValidation() async throws { // valid - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "archive.zip") - XCTAssertTrue(try archiver.validate(path: path)) + try await XCTAssertAsyncTrue(try await archiver.validate(path: path)) } // invalid - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let path = AbsolutePath(#file).parentDirectory .appending(components: "Inputs", "invalid_archive.zip") - XCTAssertFalse(try archiver.validate(path: path)) + try await XCTAssertAsyncFalse(try await archiver.validate(path: path)) } // error - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let path = AbsolutePath.root.appending("does_not_exist.zip") - XCTAssertThrowsError(try archiver.validate(path: path)) { error in + await XCTAssertAsyncThrowsError(try await archiver.validate(path: path)) { error in XCTAssertEqual(error as? FileSystemError, FileSystemError(.noEntry, path)) } } } - func testCompress() throws { + func testCompress() async throws { #if os(Linux) guard SPM_posix_spawn_file_actions_addchdir_np_supported() else { throw XCTSkip("working directory not supported on this platform") } #endif - try testWithTemporaryDirectory { tmpdir in + try await testWithTemporaryDirectory { tmpdir in let archiver = ZipArchiver(fileSystem: localFileSystem) let rootDir = tmpdir.appending(component: UUID().uuidString) @@ -121,12 +121,12 @@ class ZipArchiverTests: XCTestCase { try localFileSystem.writeFileContents(dir2.appending("file4.txt"), string: "Hello World 4!") let archivePath = tmpdir.appending(component: UUID().uuidString + ".zip") - try archiver.compress(directory: rootDir, to: archivePath) + try await archiver.compress(directory: rootDir, to: archivePath) XCTAssertFileExists(archivePath) let extractRootDir = tmpdir.appending(component: UUID().uuidString) try localFileSystem.createDirectory(extractRootDir) - try archiver.extract(from: archivePath, to: extractRootDir) + try await archiver.extract(from: archivePath, to: extractRootDir) try localFileSystem.stripFirstLevel(of: extractRootDir) XCTAssertFileExists(extractRootDir.appending("file1.txt")) @@ -158,117 +158,3 @@ class ZipArchiverTests: XCTestCase { } } } - -class ArchiverTests: XCTestCase { - func testCancel() throws { - struct MockArchiver: Archiver, Cancellable { - var supportedExtensions: Set = [] - - let cancelSemaphores = ThreadSafeArrayStore() - let startGroup = DispatchGroup() - let finishGroup = DispatchGroup() - - func extract(from archivePath: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping (Result) -> Void) { - let cancelSemaphore = DispatchSemaphore(value: 0) - self.cancelSemaphores.append(cancelSemaphore) - - self.startGroup.enter() - DispatchQueue.sharedConcurrent.async { - self.startGroup.leave() - self.finishGroup.enter() - defer { self.finishGroup.leave() } - switch cancelSemaphore.wait(timeout: .now() + .seconds(5)) { - case .success: - completion(.success(())) - case .timedOut: - completion(.failure(StringError("should be cancelled"))) - } - } - } - - func compress(directory: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping (Result) -> Void) { - let cancelSemaphore = DispatchSemaphore(value: 0) - self.cancelSemaphores.append(cancelSemaphore) - - self.startGroup.enter() - DispatchQueue.sharedConcurrent.async { - self.startGroup.leave() - self.finishGroup.enter() - defer { self.finishGroup.leave() } - switch cancelSemaphore.wait(timeout: .now() + .seconds(5)) { - case .success: - completion(.success(())) - case .timedOut: - completion(.failure(StringError("should be cancelled"))) - } - } - } - - func validate(path: AbsolutePath, completion: @escaping (Result) -> Void) { - let cancelSemaphore = DispatchSemaphore(value: 0) - self.cancelSemaphores.append(cancelSemaphore) - - self.startGroup.enter() - DispatchQueue.sharedConcurrent.async { - self.startGroup.leave() - self.finishGroup.enter() - defer { self.finishGroup.leave() } - switch cancelSemaphore.wait(timeout: .now() + .seconds(5)) { - case .success: - completion(.success(true)) - case .timedOut: - completion(.failure(StringError("should be cancelled"))) - } - } - } - - func cancel(deadline: DispatchTime) throws { - for semaphore in self.cancelSemaphores.get() { - semaphore.signal() - } - } - } - - let observability = ObservabilitySystem.makeForTesting() - let cancellator = Cancellator(observabilityScope: observability.topScope) - - let archiver = MockArchiver() - cancellator.register(name: "archiver", handler: archiver) - - archiver.extract(from: .root, to: .root) { result in - XCTAssertResultSuccess(result) - } - - archiver.compress(directory: .root, to: .root) { result in - XCTAssertResultSuccess(result) - } - - archiver.validate(path: .root) { result in - XCTAssertResultSuccess(result) - } - - XCTAssertEqual(.success, archiver.startGroup.wait(timeout: .now() + .seconds(5)), "timeout waiting for tasks to start") - - try cancellator.cancel(deadline: .now() + .seconds(5)) - - XCTAssertEqual(.success, archiver.finishGroup.wait(timeout: .now() + .seconds(5)), "timeout waiting for tasks to finish") - } -} - -extension Archiver { - func extract(from: AbsolutePath, to: AbsolutePath) throws { - try temp_await { - self.extract(from: from, to: to, completion: $0) - } - } - func compress(directory: AbsolutePath, to: AbsolutePath) throws { - try temp_await { - self.compress(directory: directory, to: to, completion: $0) - } - } - func validate(path: AbsolutePath) throws -> Bool { - try temp_await { - self.validate(path: path, completion: $0) - } - } -} diff --git a/Tests/BasicsTests/AuthorizationProviderTests.swift b/Tests/BasicsTests/AuthorizationProviderTests.swift index 43c2cbc054b..84560bccb98 100644 --- a/Tests/BasicsTests/AuthorizationProviderTests.swift +++ b/Tests/BasicsTests/AuthorizationProviderTests.swift @@ -24,8 +24,8 @@ final class AuthorizationProviderTests: XCTestCase { self.assertAuthentication(provider, for: url, expected: (user, password)) } - func testNetrc() throws { - try testWithTemporaryDirectory { tmpPath in + func testNetrc() async throws { + try await testWithTemporaryDirectory { tmpPath in let netrcPath = tmpPath.appending(".netrc") let provider = try NetrcAuthorizationProvider(path: netrcPath, fileSystem: localFileSystem) @@ -39,20 +39,14 @@ final class AuthorizationProviderTests: XCTestCase { let otherPassword = UUID().uuidString // Add - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: url, user: user, password: password, callback: callback) - }) - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: otherURL, user: user, password: otherPassword, callback: callback) - }) + try await provider.addOrUpdate(for: url, user: user, password: password) + try await provider.addOrUpdate(for: otherURL, user: user, password: otherPassword) self.assertAuthentication(provider, for: url, expected: (user, password)) // Update - the new password is appended to the end of file let newPassword = UUID().uuidString - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: url, user: user, password: newPassword, callback: callback) - }) + try await provider.addOrUpdate(for: url, user: user, password: newPassword) // .netrc file now contains two entries for `url`: one with `password` and the other with `newPassword`. // `NetrcAuthorizationProvider` returns the last entry it finds. @@ -140,36 +134,30 @@ final class AuthorizationProviderTests: XCTestCase { let httpsPassword = UUID().uuidString // Add - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: httpURL, user: user, password: httpPassword, callback: callback) - }) - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: httpsURL, user: user, password: httpsPassword, callback: callback) - }) + try await provider.addOrUpdate(for: httpURL, user: user, password: httpPassword) + try await provider.addOrUpdate(for: httpsURL, user: user, password: httpsPassword) self.assertAuthentication(provider, for: httpURL, expected: (user, httpPassword)) self.assertAuthentication(provider, for: httpsURL, expected: (user, httpsPassword)) // Update let newHTTPPassword = UUID().uuidString - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: httpURL, user: user, password: newHTTPPassword, callback: callback) - }) + try await provider.addOrUpdate(for: httpURL, user: user, password: newHTTPPassword) + let newHTTPSPassword = UUID().uuidString - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: httpsURL, user: user, password: newHTTPSPassword, callback: callback) - }) + try await provider.addOrUpdate(for: httpsURL, user: user, password: newHTTPSPassword) + // Existing password is updated self.assertAuthentication(provider, for: httpURL, expected: (user, newHTTPPassword)) self.assertAuthentication(provider, for: httpsURL, expected: (user, newHTTPSPassword)) // Delete - XCTAssertNoThrow(try temp_await { callback in provider.remove(for: httpURL, callback: callback) }) + try await provider.remove(for: httpURL) XCTAssertNil(provider.authentication(for: httpURL)) self.assertAuthentication(provider, for: httpsURL, expected: (user, newHTTPSPassword)) - XCTAssertNoThrow(try temp_await { callback in provider.remove(for: httpsURL, callback: callback) }) + try await provider.remove(for: httpsURL) XCTAssertNil(provider.authentication(for: httpsURL)) #endif } @@ -189,36 +177,29 @@ final class AuthorizationProviderTests: XCTestCase { let portPassword = UUID().uuidString // Add - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: noPortURL, user: user, password: noPortPassword, callback: callback) - }) - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: portURL, user: user, password: portPassword, callback: callback) - }) + try await provider.addOrUpdate(for: noPortURL, user: user, password: noPortPassword) + try await provider.addOrUpdate(for: portURL, user: user, password: portPassword) self.assertAuthentication(provider, for: noPortURL, expected: (user, noPortPassword)) self.assertAuthentication(provider, for: portURL, expected: (user, portPassword)) // Update let newPortPassword = UUID().uuidString - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: portURL, user: user, password: newPortPassword, callback: callback) - }) + try await provider.addOrUpdate(for: portURL, user: user, password: newPortPassword) + let newNoPortPassword = UUID().uuidString - XCTAssertNoThrow(try temp_await { callback in - provider.addOrUpdate(for: noPortURL, user: user, password: newNoPortPassword, callback: callback) - }) + try await provider.addOrUpdate(for: noPortURL, user: user, password: newNoPortPassword) // Existing password is updated self.assertAuthentication(provider, for: portURL, expected: (user, newPortPassword)) self.assertAuthentication(provider, for: noPortURL, expected: (user, newNoPortPassword)) // Delete - XCTAssertNoThrow(try temp_await { callback in provider.remove(for: noPortURL, callback: callback) }) + try await provider.remove(for: noPortURL) XCTAssertNil(provider.authentication(for: noPortURL)) self.assertAuthentication(provider, for: portURL, expected: (user, newPortPassword)) - XCTAssertNoThrow(try temp_await { callback in provider.remove(for: portURL, callback: callback) }) + try await provider.remove(for: portURL) XCTAssertNil(provider.authentication(for: portURL)) #endif } From abe24fa6bdb4d059b1d0ee05696a42ae31b9a262 Mon Sep 17 00:00:00 2001 From: Andrew Hoos Date: Mon, 27 Nov 2023 10:26:22 -0800 Subject: [PATCH 2/3] Remove all usage of temp_await from WorkspaceTests --- Sources/PackageGraph/PackageContainer.swift | 20 +++ Sources/PackageLoading/ManifestLoader.swift | 35 ++++- Sources/Workspace/Workspace.swift | 12 ++ .../ManifestSourceGenerationTests.swift | 122 +++++++++--------- .../RegistryPackageContainerTests.swift | 49 ++++--- .../SourceControlPackageContainerTests.swift | 50 +++---- Tests/WorkspaceTests/WorkspaceTests.swift | 67 ++++------ 7 files changed, 198 insertions(+), 157 deletions(-) diff --git a/Sources/PackageGraph/PackageContainer.swift b/Sources/PackageGraph/PackageContainer.swift index 091310acfc3..c40b56d43b7 100644 --- a/Sources/PackageGraph/PackageContainer.swift +++ b/Sources/PackageGraph/PackageContainer.swift @@ -164,6 +164,8 @@ extension PackageContainerConstraint: CustomStringConvertible { /// An interface for resolving package containers. public protocol PackageContainerProvider { /// Get the container for a particular identifier asynchronously. + + @available(*, noasync, message: "Use the async alternative") func getContainer( for package: PackageReference, updateStrategy: ContainerUpdateStrategy, @@ -173,6 +175,24 @@ public protocol PackageContainerProvider { ) } +public extension PackageContainerProvider { + func getContainer( + for package: PackageReference, + updateStrategy: ContainerUpdateStrategy, + observabilityScope: ObservabilityScope, + on queue: DispatchQueue + ) async throws -> PackageContainer { + try await safe_async { + self.getContainer( + for: package, + updateStrategy: updateStrategy, + observabilityScope: observabilityScope, + on: queue, + completion: $0) + } + } +} + /// Only used for source control containers and as such a mirror of RepositoryUpdateStrategy /// This duplication is unfortunate - ideally this is not a concern of the ContainerProvider at all /// but it is required give how PackageContainerProvider currently integrated into the resolver diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 73d509ae3dc..9630b8dc466 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -293,7 +293,40 @@ public final class ManifestLoader: ManifestLoaderProtocol { self.evaluationQueue.maxConcurrentOperationCount = Concurrency.maxOperations self.concurrencySemaphore = DispatchSemaphore(value: Concurrency.maxOperations) } - + + public func load( + manifestPath: AbsolutePath, + manifestToolsVersion: ToolsVersion, + packageIdentity: PackageIdentity, + packageKind: PackageReference.Kind, + packageLocation: String, + packageVersion: (version: Version?, revision: String?)?, + identityResolver: IdentityResolver, + dependencyMapper: DependencyMapper, + fileSystem: FileSystem, + observabilityScope: ObservabilityScope, + delegateQueue: DispatchQueue, + callbackQueue: DispatchQueue + ) async throws -> Manifest { + try await safe_async { + self.load( + manifestPath: manifestPath, + manifestToolsVersion: manifestToolsVersion, + packageIdentity: packageIdentity, + packageKind: packageKind, + packageLocation: packageLocation, + packageVersion: packageVersion, + identityResolver: identityResolver, + dependencyMapper: dependencyMapper, + fileSystem: fileSystem, + observabilityScope: observabilityScope, + delegateQueue: delegateQueue, + callbackQueue: callbackQueue, + completion: $0) + } + } + + @available(*, noasync, message: "Use the async alternative") public func load( manifestPath: AbsolutePath, manifestToolsVersion: ToolsVersion, diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index 48ad9351a7b..7a0f0715240 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -949,6 +949,7 @@ extension Workspace { } /// Loads and returns manifests at the given paths. + @available(*, noasync, message: "Use the async alternative") public func loadRootManifests( packages: [AbsolutePath], observabilityScope: ObservabilityScope, @@ -1122,9 +1123,20 @@ extension Workspace { } return importList } + + public func loadPackage( + with identity: PackageIdentity, + packageGraph: PackageGraph, + observabilityScope: ObservabilityScope + ) async throws -> Package { + try await safe_async { + self.loadPackage(with: identity, packageGraph: packageGraph, observabilityScope: observabilityScope, completion: $0) + } + } /// Loads a single package in the context of a previously loaded graph. This can be useful for incremental loading /// in a longer-lived program, like an IDE. + @available(*, noasync, message: "Use the async alternative") public func loadPackage( with identity: PackageIdentity, packageGraph: PackageGraph, diff --git a/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift b/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift index dbd50807b3b..88652873d23 100644 --- a/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift +++ b/Tests/WorkspaceTests/ManifestSourceGenerationTests.swift @@ -43,8 +43,8 @@ class ManifestSourceGenerationTests: XCTestCase { toolsVersionHeaderComment: String? = .none, additionalImportModuleNames: [String] = [], fs: FileSystem = localFileSystem - ) throws -> String { - try withTemporaryDirectory { packageDir in + ) async throws -> String { + try await withTemporaryDirectory { packageDir in let observability = ObservabilitySystem.makeForTesting() // Write the original manifest file contents, and load it. @@ -53,23 +53,20 @@ class ManifestSourceGenerationTests: XCTestCase { let manifestLoader = ManifestLoader(toolchain: try UserToolchain.default) let identityResolver = DefaultIdentityResolver() let dependencyMapper = DefaultDependencyMapper(identityResolver: identityResolver) - let manifest = try temp_await { - manifestLoader.load( - manifestPath: manifestPath, - manifestToolsVersion: toolsVersion, - packageIdentity: .plain("Root"), - packageKind: .root(packageDir), - packageLocation: packageDir.pathString, - packageVersion: nil, - identityResolver: identityResolver, - dependencyMapper: dependencyMapper, - fileSystem: fs, - observabilityScope: observability.topScope, - delegateQueue: .sharedConcurrent, - callbackQueue: .sharedConcurrent, - completion: $0 - ) - } + let manifest = try await manifestLoader.load( + manifestPath: manifestPath, + manifestToolsVersion: toolsVersion, + packageIdentity: .plain("Root"), + packageKind: .root(packageDir), + packageLocation: packageDir.pathString, + packageVersion: nil, + identityResolver: identityResolver, + dependencyMapper: dependencyMapper, + fileSystem: fs, + observabilityScope: observability.topScope, + delegateQueue: .sharedConcurrent, + callbackQueue: .sharedConcurrent + ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -85,23 +82,20 @@ class ManifestSourceGenerationTests: XCTestCase { // Write out the generated manifest to replace the old manifest file contents, and load it again. try fs.writeFileContents(manifestPath, string: newContents) - let newManifest = try temp_await { - manifestLoader.load( - manifestPath: manifestPath, - manifestToolsVersion: toolsVersion, - packageIdentity: .plain("Root"), - packageKind: .root(packageDir), - packageLocation: packageDir.pathString, - packageVersion: nil, - identityResolver: identityResolver, - dependencyMapper: dependencyMapper, - fileSystem: fs, - observabilityScope: observability.topScope, - delegateQueue: .sharedConcurrent, - callbackQueue: .sharedConcurrent, - completion: $0 - ) - } + let newManifest = try await manifestLoader.load( + manifestPath: manifestPath, + manifestToolsVersion: toolsVersion, + packageIdentity: .plain("Root"), + packageKind: .root(packageDir), + packageLocation: packageDir.pathString, + packageVersion: nil, + identityResolver: identityResolver, + dependencyMapper: dependencyMapper, + fileSystem: fs, + observabilityScope: observability.topScope, + delegateQueue: .sharedConcurrent, + callbackQueue: .sharedConcurrent + ) XCTAssertNoDiagnostics(observability.diagnostics) @@ -125,7 +119,7 @@ class ManifestSourceGenerationTests: XCTestCase { } } - func testBasics() throws { + func testBasics() async throws { let manifestContents = """ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -160,10 +154,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) } - func testCustomPlatform() throws { + func testCustomPlatform() async throws { let manifestContents = """ // swift-tools-version:5.6 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -197,10 +191,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_6) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_6) } - func testAdvancedFeatures() throws { + func testAdvancedFeatures() async throws { let manifestContents = """ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -246,10 +240,10 @@ class ManifestSourceGenerationTests: XCTestCase { cxxLanguageStandard: .cxx11 ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) } - func testPackageDependencyVariations() throws { + func testPackageDependencyVariations() async throws { let manifestContents = """ // swift-tools-version:5.4 import PackageDescription @@ -281,7 +275,7 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - let newContents = try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) + let newContents = try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) // Check some things about the contents of the manifest. XCTAssertTrue(newContents.contains("url: \"\("../MyPkg10".nativePathString(escaped: true))\""), newContents) @@ -289,7 +283,7 @@ class ManifestSourceGenerationTests: XCTestCase { XCTAssertTrue(newContents.contains("path: \"\("packages/path/to/MyPkg12".nativePathString(escaped: true))"), newContents) } - func testResources() throws { + func testResources() async throws { let manifestContents = """ // swift-tools-version:5.3 import PackageDescription @@ -320,10 +314,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) } - func testBuildSettings() throws { + func testBuildSettings() async throws { let manifestContents = """ // swift-tools-version:5.3 import PackageDescription @@ -356,10 +350,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_3) } - func testPluginTargets() throws { + func testPluginTargets() async throws { let manifestContents = """ // swift-tools-version:5.5 import PackageDescription @@ -378,10 +372,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5) } - func testCustomToolsVersionHeaderComment() throws { + func testCustomToolsVersionHeaderComment() async throws { let manifestContents = """ // swift-tools-version:5.5 import PackageDescription @@ -400,12 +394,12 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - let newContents = try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5, toolsVersionHeaderComment: "a comment") + let newContents = try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5, toolsVersionHeaderComment: "a comment") XCTAssertTrue(newContents.hasPrefix("// swift-tools-version: 5.5; a comment\n"), "contents: \(newContents)") } - func testAdditionalModuleImports() throws { + func testAdditionalModuleImports() async throws { let manifestContents = """ // swift-tools-version:5.5 import PackageDescription @@ -420,12 +414,12 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - let newContents = try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5, additionalImportModuleNames: ["Foundation"]) + let newContents = try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_5, additionalImportModuleNames: ["Foundation"]) XCTAssertTrue(newContents.contains("import Foundation\n"), "contents: \(newContents)") } - func testLatestPlatformVersions() throws { + func testLatestPlatformVersions() async throws { let manifestContents = """ // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -447,10 +441,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_9) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_9) } - func testTargetPlatformConditions() throws { + func testTargetPlatformConditions() async throws { let manifestContents = """ // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -475,7 +469,7 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_9) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_9) } func testCustomProductSourceGeneration() throws { @@ -517,7 +511,7 @@ class ManifestSourceGenerationTests: XCTestCase { XCTAssertTrue(contents.contains(".library(name: \"Foo\", targets: [\"Bar\"], type: .static)"), "contents: \(contents)") } - func testModuleAliasGeneration() throws { + func testModuleAliasGeneration() async throws { let manifest = Manifest.createRootManifest( displayName: "thisPkg", path: "/thisPkg", @@ -558,10 +552,10 @@ class ManifestSourceGenerationTests: XCTestCase { let isContained = trimmedParts.allSatisfy(trimmedContents.contains(_:)) XCTAssertTrue(isContained) - try testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v5_8) + try await testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v5_8) } - func testUpcomingAndExperimentalFeatures() throws { + func testUpcomingAndExperimentalFeatures() async throws { let manifestContents = """ // swift-tools-version:5.8 import PackageDescription @@ -580,10 +574,10 @@ class ManifestSourceGenerationTests: XCTestCase { ] ) """ - try testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_8) + try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_8) } - func testPluginNetworkingPermissionGeneration() throws { + func testPluginNetworkingPermissionGeneration() async throws { let manifest = Manifest.createRootManifest( displayName: "thisPkg", path: "/thisPkg", @@ -593,6 +587,6 @@ class ManifestSourceGenerationTests: XCTestCase { try TargetDescription(name: "MyPlugin", type: .plugin, pluginCapability: .command(intent: .custom(verb: "foo", description: "bar"), permissions: [.allowNetworkConnections(scope: .all(ports: [23, 42, 443, 8080]), reason: "internet good")])) ]) let contents = try manifest.generateManifestFileContents(packageDirectory: manifest.path.parentDirectory) - try testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v5_9) + try await testManifestWritingRoundTrip(manifestContents: contents, toolsVersion: .v5_9) } } diff --git a/Tests/WorkspaceTests/RegistryPackageContainerTests.swift b/Tests/WorkspaceTests/RegistryPackageContainerTests.swift index 034ba36e469..ea669b6cff5 100644 --- a/Tests/WorkspaceTests/RegistryPackageContainerTests.swift +++ b/Tests/WorkspaceTests/RegistryPackageContainerTests.swift @@ -26,7 +26,7 @@ import struct TSCUtility.Version class RegistryPackageContainerTests: XCTestCase { - func testToolsVersionCompatibleVersions() throws { + func testToolsVersionCompatibleVersions() async throws { let fs = InMemoryFileSystem() let packageIdentity = PackageIdentity.plain("org.foo") @@ -98,7 +98,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v4) let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.1"]) } @@ -106,7 +106,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v4_2) let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.2", "1.0.1"]) } @@ -114,13 +114,13 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_4) let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, ["1.0.3", "1.0.2", "1.0.1"]) } } - func testAlternateManifests() throws { + func testAlternateManifests() async throws { let fs = InMemoryFileSystem() let packageIdentity = PackageIdentity.plain("org.foo") @@ -163,7 +163,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_2) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_3) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, []) @@ -172,7 +172,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_3) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) @@ -181,7 +181,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_4) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_4) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) @@ -190,7 +190,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_5) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_5) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) @@ -199,14 +199,14 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_6) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) XCTAssertEqual(try container.toolsVersion(for: packageVersion), .v5_5) let versions = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(versions, [packageVersion]) } } - func testLoadManifest() throws { + func testLoadManifest() async throws { let fs = InMemoryFileSystem() let packageIdentity = PackageIdentity.plain("org.foo") @@ -286,7 +286,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) as! RegistryPackageContainer + let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer let manifest = try container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_3) } @@ -294,7 +294,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(v5_3_3) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) as! RegistryPackageContainer + let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer let manifest = try container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, v5_3_3) } @@ -302,7 +302,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_4) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) as! RegistryPackageContainer + let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer let manifest = try container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_4) } @@ -310,7 +310,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_5) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) as! RegistryPackageContainer + let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer let manifest = try container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_5) } @@ -318,7 +318,7 @@ class RegistryPackageContainerTests: XCTestCase { do { let provider = try createProvider(.v5_6) // the version of the alternate let ref = PackageReference.registry(identity: packageIdentity) - let container = try provider.getContainer(for: ref) as! RegistryPackageContainer + let container = try await provider.getContainer(for: ref) as! RegistryPackageContainer let manifest = try container.loadManifest(version: packageVersion) XCTAssertEqual(manifest.toolsVersion, .v5_5) } @@ -486,15 +486,12 @@ class RegistryPackageContainerTests: XCTestCase { } extension PackageContainerProvider { - fileprivate func getContainer(for package: PackageReference, updateStrategy: ContainerUpdateStrategy = .always) throws -> PackageContainer { - try temp_await { - self.getContainer( - for: package, - updateStrategy: updateStrategy, - observabilityScope: ObservabilitySystem.NOOP, - on: .global(), - completion: $0 - ) - } + fileprivate func getContainer(for package: PackageReference, updateStrategy: ContainerUpdateStrategy = .always) async throws -> PackageContainer { + try await self.getContainer( + for: package, + updateStrategy: updateStrategy, + observabilityScope: ObservabilitySystem.NOOP, + on: .global() + ) } } diff --git a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift index 4b406ed68d2..0fc65e50fbf 100644 --- a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift +++ b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift @@ -189,7 +189,7 @@ private let v2: Version = "2.0.0" private let v1Range: VersionSetSpecifier = .range("1.0.0" ..< "2.0.0") class SourceControlPackageContainerTests: XCTestCase { - func testVprefixVersions() throws { + func testVprefixVersions() async throws { let fs = InMemoryFileSystem() let repoPath = AbsolutePath.root @@ -226,12 +226,12 @@ class SourceControlPackageContainerTests: XCTestCase { ) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["2.0.3", "1.0.3", "1.0.2", "1.0.1", "1.0.0"]) } - func testVersions() throws { + func testVersions() async throws { let fs = InMemoryFileSystem() let repoPath = AbsolutePath.root @@ -283,7 +283,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { let provider = try createProvider(ToolsVersion(version: "4.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["1.0.1"]) } @@ -291,7 +291,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { let provider = try createProvider(ToolsVersion(version: "4.2.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) as! SourceControlPackageContainer + let container = try await provider.getContainer(for: ref) as! SourceControlPackageContainer XCTAssertTrue(container.validToolsVersionsCache.isEmpty) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(container.validToolsVersionsCache["1.0.0"], false) @@ -304,7 +304,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { let provider = try createProvider(ToolsVersion(version: "3.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, []) } @@ -313,7 +313,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { let provider = try createProvider(ToolsVersion(version: "4.0.0")) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) as! SourceControlPackageContainer + let container = try await provider.getContainer(for: ref) as! SourceControlPackageContainer let revision = try container.getRevision(forTag: "1.0.0") do { _ = try container.getDependencies(at: revision.identifier, productFilter: .nothing) @@ -324,7 +324,7 @@ class SourceControlPackageContainerTests: XCTestCase { } } - func testPreReleaseVersions() throws { + func testPreReleaseVersions() async throws { let fs = InMemoryFileSystem() let repoPath = AbsolutePath.root @@ -363,12 +363,12 @@ class SourceControlPackageContainerTests: XCTestCase { ) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["1.0.4-alpha", "1.0.2-dev.2", "1.0.2-dev", "1.0.1", "1.0.0", "1.0.0-beta.1", "1.0.0-alpha.1"]) } - func testSimultaneousVersions() throws { + func testSimultaneousVersions() async throws { let fs = InMemoryFileSystem() let repoPath = AbsolutePath.root @@ -411,7 +411,7 @@ class SourceControlPackageContainerTests: XCTestCase { customRepositoryManager: repositoryManager ) let ref = PackageReference.localSourceControl(identity: PackageIdentity(path: repoPath), path: repoPath) - let container = try provider.getContainer(for: ref) + let container = try await provider.getContainer(for: ref) let v = try container.toolsVersionsAppropriateVersionsDescending() XCTAssertEqual(v, ["2.0.1", "1.3.0", "1.2.0", "1.1.0", "1.0.4", "1.0.2", "1.0.1", "1.0.0"]) } @@ -551,8 +551,8 @@ class SourceControlPackageContainerTests: XCTestCase { } } - func testMissingBranchDiagnostics() throws { - try testWithTemporaryDirectory { tmpDir in + func testMissingBranchDiagnostics() async throws { + try await testWithTemporaryDirectory { tmpDir in // Create a repository. let packageDir = tmpDir.appending("SomePackage") try localFileSystem.createDirectory(packageDir) @@ -597,7 +597,7 @@ class SourceControlPackageContainerTests: XCTestCase { // Get a hold of the container for the test package. let packageRef = PackageReference.localSourceControl(identity: PackageIdentity(path: packageDir), path: packageDir) - let container = try containerProvider.getContainer(for: packageRef) as! SourceControlPackageContainer + let container = try await containerProvider.getContainer(for: packageRef) as! SourceControlPackageContainer // Simulate accessing a fictitious dependency on the `master` branch, and check that we get back the expected error. do { _ = try container.getDependencies(at: "master", productFilter: .everything) } @@ -619,8 +619,8 @@ class SourceControlPackageContainerTests: XCTestCase { } } - func testRepositoryContainerUpdateStrategy() throws { - try testWithTemporaryDirectory { temporaryDirectory in + func testRepositoryContainerUpdateStrategy() async throws { + try await testWithTemporaryDirectory { temporaryDirectory in let packageDirectory = temporaryDirectory.appending("MyPackage") let package = PackageReference.localSourceControl(identity: PackageIdentity(path: packageDirectory), path: packageDirectory) @@ -660,7 +660,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { repositoryManagerDelegate.reset() XCTAssertEqual(repositoryManagerDelegate.updated.count, 0) - _ = try containerProvider.getContainer( + _ = try await containerProvider.getContainer( for: package, updateStrategy: .never ) @@ -670,7 +670,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { repositoryManagerDelegate.reset() XCTAssertEqual(repositoryManagerDelegate.updated.count, 0) - _ = try containerProvider.getContainer( + _ = try await containerProvider.getContainer( for: package, updateStrategy: .always ) @@ -684,7 +684,7 @@ class SourceControlPackageContainerTests: XCTestCase { repositoryManagerDelegate.reset() XCTAssertEqual(repositoryManagerDelegate.updated.count, 0) - _ = try containerProvider.getContainer( + _ = try await containerProvider.getContainer( for: package, updateStrategy: .ifNeeded(revision: revision.identifier) ) @@ -694,7 +694,7 @@ class SourceControlPackageContainerTests: XCTestCase { do { repositoryManagerDelegate.reset() XCTAssertEqual(repositoryManagerDelegate.updated.count, 0) - _ = try containerProvider.getContainer( + _ = try await containerProvider.getContainer( for: package, updateStrategy: .ifNeeded(revision: UUID().uuidString) ) @@ -707,8 +707,8 @@ class SourceControlPackageContainerTests: XCTestCase { // RepositoryPackageContainer used to erroneously cache dependencies based only on version, // storing the result of the first product filter and then continually returning it for other filters too. // This lead to corrupt graph states. - func testRepositoryPackageContainerCache() throws { - try testWithTemporaryDirectory { temporaryDirectory in + func testRepositoryPackageContainerCache() async throws { + try await testWithTemporaryDirectory { temporaryDirectory in let packageDirectory = temporaryDirectory.appending("Package") try localFileSystem.createDirectory(packageDirectory) initGitRepo(packageDirectory) @@ -761,7 +761,7 @@ class SourceControlPackageContainerTests: XCTestCase { ) let packageReference = PackageReference.localSourceControl(identity: PackageIdentity(path: packageDirectory), path: packageDirectory) - let container = try containerProvider.getContainer(for: packageReference) + let container = try await containerProvider.getContainer(for: packageReference) let forNothing = try container.getDependencies(at: version, productFilter: .specific([])) let forProduct = try container.getDependencies(at: version, productFilter: .specific(["Product"])) @@ -777,8 +777,8 @@ extension PackageContainerProvider { fileprivate func getContainer( for package: PackageReference, updateStrategy: ContainerUpdateStrategy = .always - ) throws -> PackageContainer { - try temp_await { + ) async throws -> PackageContainer { + try await safe_async { self.getContainer( for: package, updateStrategy: updateStrategy, diff --git a/Tests/WorkspaceTests/WorkspaceTests.swift b/Tests/WorkspaceTests/WorkspaceTests.swift index 5613b08f715..f33d216c1b4 100644 --- a/Tests/WorkspaceTests/WorkspaceTests.swift +++ b/Tests/WorkspaceTests/WorkspaceTests.swift @@ -219,10 +219,10 @@ final class WorkspaceTests: XCTestCase { } } - func testManifestParseError() throws { + func testManifestParseError() async throws { let observability = ObservabilitySystem.makeForTesting() - try testWithTemporaryDirectory { path in + try await testWithTemporaryDirectory { path in let pkgDir = path.appending("MyPkg") try localFileSystem.createDirectory(pkgDir) try localFileSystem.writeFileContents( @@ -243,13 +243,10 @@ final class WorkspaceTests: XCTestCase { delegate: MockWorkspaceDelegate() ) let rootInput = PackageGraphRootInput(packages: [pkgDir], dependencies: []) - let rootManifests = try temp_await { - workspace.loadRootManifests( - packages: rootInput.packages, - observabilityScope: observability.topScope, - completion: $0 - ) - } + let rootManifests = try await workspace.loadRootManifests( + packages: rootInput.packages, + observabilityScope: observability.topScope + ) XCTAssert(rootManifests.count == 0, "\(rootManifests)") @@ -5265,8 +5262,8 @@ final class WorkspaceTests: XCTestCase { } // This verifies that the simplest possible loading APIs are available for package clients. - func testSimpleAPI() throws { - try testWithTemporaryDirectory { path in + func testSimpleAPI() async throws { + try await testWithTemporaryDirectory { path in // Create a temporary package as a test case. let packagePath = path.appending("MyPkg") let initPackage = try InitPackage( @@ -5285,23 +5282,17 @@ final class WorkspaceTests: XCTestCase { ) // From here the API should be simple and straightforward: - let manifest = try temp_await { - workspace.loadRootManifest( - at: packagePath, - observabilityScope: observability.topScope, - completion: $0 - ) - } + let manifest = try await workspace.loadRootManifest( + at: packagePath, + observabilityScope: observability.topScope + ) XCTAssertFalse(observability.hasWarningDiagnostics, observability.diagnostics.description) XCTAssertFalse(observability.hasErrorDiagnostics, observability.diagnostics.description) - let package = try temp_await { - workspace.loadRootPackage( - at: packagePath, - observabilityScope: observability.topScope, - completion: $0 - ) - } + let package = try await workspace.loadRootPackage( + at: packagePath, + observabilityScope: observability.topScope + ) XCTAssertFalse(observability.hasWarningDiagnostics, observability.diagnostics.description) XCTAssertFalse(observability.hasErrorDiagnostics, observability.diagnostics.description) @@ -5316,14 +5307,11 @@ final class WorkspaceTests: XCTestCase { XCTAssertEqual(package.identity, .plain(manifest.displayName)) XCTAssert(graph.reachableProducts.contains(where: { $0.name == "MyPkg" })) - let reloadedPackage = try temp_await { - workspace.loadPackage( - with: package.identity, - packageGraph: graph, - observabilityScope: observability.topScope, - completion: $0 - ) - } + let reloadedPackage = try await workspace.loadPackage( + with: package.identity, + packageGraph: graph, + observabilityScope: observability.topScope + ) XCTAssertEqual(package.identity, reloadedPackage.identity) XCTAssertEqual(package.manifest.displayName, reloadedPackage.manifest.displayName) @@ -8804,7 +8792,7 @@ final class WorkspaceTests: XCTestCase { } } - func testLoadRootPackageWithBinaryDependencies() throws { + func testLoadRootPackageWithBinaryDependencies() async throws { let sandbox = AbsolutePath("/tmp/ws/") let fs = InMemoryFileSystem() @@ -8841,13 +8829,10 @@ final class WorkspaceTests: XCTestCase { let observability = ObservabilitySystem.makeForTesting() let wks = try workspace.getOrCreateWorkspace() - XCTAssertNoThrow(try temp_await { - wks.loadRootPackage( - at: workspace.rootsDir.appending("Root"), - observabilityScope: observability.topScope, - completion: $0 - ) - }) + _ = try await wks.loadRootPackage( + at: workspace.rootsDir.appending("Root"), + observabilityScope: observability.topScope + ) XCTAssertNoDiagnostics(observability.diagnostics) } From 9af83ed84b7ae9f7ade9c3d410fd0838a3e46ed7 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 27 Nov 2023 23:10:11 +0000 Subject: [PATCH 3/3] Apply suggestions from code review --- Sources/PackageLoading/ManifestLoader.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 9630b8dc466..99bf6e161a2 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -322,7 +322,8 @@ public final class ManifestLoader: ManifestLoaderProtocol { observabilityScope: observabilityScope, delegateQueue: delegateQueue, callbackQueue: callbackQueue, - completion: $0) + completion: $0 + ) } }