Skip to content

Commit 881b9c7

Browse files
committed
tests: Use a temporary scratch directory when building an SDK
Building an SDK requires running the sdk-generator with `swift run swift-sdk-generator`. This takes a lock on `.build`, but if the tests are being run by `swift test` the outer Swift Package Manager instance will already hold this lock, causing the test to deadlock. We can work around this by giving the `swift run swift-sdk-generator` instance its own scratch directory.
1 parent d2512a1 commit 881b9c7

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

Tests/SwiftSDKGeneratorTests/EndToEndTests.swift

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@ import XCTest
1717

1818
@testable import SwiftSDKGenerator
1919

20+
extension FileManager {
21+
func withTemporaryDirectory<T>(logger: Logger, cleanup: Bool = true, body: (URL) async throws -> T) async throws -> T {
22+
// Create a temporary directory using a UUID. Throws if the directory already exists.
23+
// The docs suggest using FileManager.url(for: .itemReplacementDirectory, ...) to create a temporary directory,
24+
// but on Linux the directory name contains spaces, which means we need to be careful to quote it everywhere:
25+
//
26+
// `(A Document Being Saved By \(name))`
27+
//
28+
// https://github.com/swiftlang/swift-corelibs-foundation/blob/21b3196b33a64d53a0989881fc9a486227b4a316/Sources/Foundation/FileManager.swift#L152
29+
var logger = logger
30+
31+
let temporaryDirectory = self.temporaryDirectory.appendingPathComponent(UUID().uuidString)
32+
logger[metadataKey: "temporaryDirectory"] = "\(temporaryDirectory.path)"
33+
34+
try createDirectory(at: temporaryDirectory, withIntermediateDirectories: false)
35+
defer {
36+
// Best effort cleanup.
37+
do {
38+
if cleanup {
39+
try removeItem(at: temporaryDirectory)
40+
logger.info("Removed temporary directory")
41+
} else {
42+
logger.info("Keeping temporary directory")
43+
}
44+
} catch {}
45+
}
46+
47+
logger.info("Created temporary directory")
48+
return try await body(temporaryDirectory)
49+
}
50+
}
51+
2052
final class EndToEndTests: XCTestCase {
2153
private let testcases = [
2254
#"""
@@ -37,10 +69,14 @@ final class EndToEndTests: XCTestCase {
3769

3870
private let logger = Logger(label: "swift-sdk-generator")
3971

72+
// Building an SDK requires running the sdk-generator with `swift run swift-sdk-generator`.
73+
// This takes a lock on `.build`, but if the tests are being run by `swift test` the outer Swift Package Manager
74+
// instance will already hold this lock, causing the test to deadlock. We can work around this by giving
75+
// the `swift run swift-sdk-generator` instance its own scratch directory.
4076
#if !os(macOS)
41-
func buildSDK(inDirectory packageDirectory: FilePath, withArguments runArguments: String) async throws -> String {
77+
func buildSDK(inDirectory packageDirectory: FilePath, scratchPath: String, withArguments runArguments: String) async throws -> String {
4278
let generatorOutput = try await Shell.readStdout(
43-
"cd \(packageDirectory) && swift run swift-sdk-generator \(runArguments)"
79+
"cd \(packageDirectory) && swift run --scratch-path \"\(scratchPath)\" swift-sdk-generator \(runArguments)"
4480
)
4581

4682
let installCommand = try XCTUnwrap(generatorOutput.split(separator: "\n").first {
@@ -84,10 +120,9 @@ final class EndToEndTests: XCTestCase {
84120
}
85121

86122
for runArguments in possibleArguments {
87-
let bundleName = try await buildSDK(inDirectory: packageDirectory, withArguments: runArguments)
88-
89-
let installOutput = try await Shell.readStdout(String(installCommand))
90-
XCTAssertTrue(installOutput.contains("successfully installed"))
123+
let bundleName = try await FileManager.default.withTemporaryDirectory(logger: logger) { tempDir in
124+
try await buildSDK(inDirectory: packageDirectory, scratchPath: tempDir.path, withArguments: runArguments)
125+
}
91126

92127
for testcase in self.testcases {
93128
let testPackageURL = FileManager.default.temporaryDirectory.appendingPathComponent("swift-sdk-generator-test")
@@ -130,8 +165,10 @@ final class EndToEndTests: XCTestCase {
130165
}
131166

132167
for runArguments in possibleArguments {
133-
let _ = try await buildSDK(inDirectory: packageDirectory, withArguments: runArguments)
134-
let _ = try await buildSDK(inDirectory: packageDirectory, withArguments: runArguments)
168+
try await FileManager.default.withTemporaryDirectory(logger: logger) { tempDir in
169+
let _ = try await buildSDK(inDirectory: packageDirectory, scratchPath: tempDir.path, withArguments: runArguments)
170+
let _ = try await buildSDK(inDirectory: packageDirectory, scratchPath: tempDir.path, withArguments: runArguments)
171+
}
135172
}
136173
}
137174
#endif

0 commit comments

Comments
 (0)