@@ -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+
2052final class EndToEndTests : XCTestCase {
2153 private let testcases = [
2254 #"""
@@ -37,11 +69,40 @@ final class EndToEndTests: XCTestCase {
3769
3870 private let logger = Logger ( label: " swift-sdk-generator " )
3971
40- #if !os(macOS)
41- func testPackageInitExecutable( ) async throws {
42- throw XCTSkip ( " EndToEnd tests currently deadlock under `swift test`: https://github.com/swiftlang/swift-sdk-generator/issues/143 " )
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.
76+ func buildSDK( inDirectory packageDirectory: FilePath , scratchPath: String , withArguments runArguments: String ) async throws -> String {
77+ let generatorOutput = try await Shell . readStdout (
78+ " cd \( packageDirectory) && swift run --scratch-path \" \( scratchPath) \" swift-sdk-generator \( runArguments) "
79+ )
80+
81+ let installCommand = try XCTUnwrap ( generatorOutput. split ( separator: " \n " ) . first {
82+ $0. contains ( " swift experimental-sdk install " )
83+ } )
84+
85+ let bundleName = try XCTUnwrap (
86+ FilePath ( String ( XCTUnwrap ( installCommand. split ( separator: " " ) . last) ) ) . components. last
87+ ) . stem
88+
89+ let installedSDKs = try await Shell . readStdout ( " swift experimental-sdk list " ) . components ( separatedBy: " \n " )
90+
91+ // Make sure this bundle hasn't been installed already.
92+ if installedSDKs. contains ( bundleName) {
93+ try await Shell . run ( " swift experimental-sdk remove \( bundleName) " )
94+ }
95+
96+ let installOutput = try await Shell . readStdout ( String ( installCommand) )
97+ XCTAssertTrue ( installOutput. contains ( " successfully installed " ) )
98+
99+ return bundleName
100+ }
43101
44- let fm = FileManager . default
102+ func testPackageInitExecutable( ) async throws {
103+ if ProcessInfo . processInfo. environment. keys. contains ( " JENKINS_URL " ) {
104+ throw XCTSkip ( " EndToEnd tests cannot currently run in CI: https://github.com/swiftlang/swift-sdk-generator/issues/145 " )
105+ }
45106
46107 var packageDirectory = FilePath ( #filePath)
47108 packageDirectory. removeLastComponent ( )
@@ -58,55 +119,46 @@ final class EndToEndTests: XCTestCase {
58119 }
59120
60121 for runArguments in possibleArguments {
61- let generatorOutput = try await Shell . readStdout (
62- " cd \( packageDirectory) && swift run swift-sdk-generator \( runArguments) "
63- )
64-
65- let installCommand = try XCTUnwrap ( generatorOutput. split ( separator: " \n " ) . first {
66- $0. contains ( " swift experimental-sdk install " )
67- } )
68-
69- let bundleName = try XCTUnwrap (
70- FilePath ( String ( XCTUnwrap ( installCommand. split ( separator: " " ) . last) ) ) . components. last
71- ) . stem
72-
73- let installedSDKs = try await Shell . readStdout ( " swift experimental-sdk list " ) . components ( separatedBy: " \n " )
74-
75- // Make sure this bundle hasn't been installed already.
76- if installedSDKs. contains ( bundleName) {
77- try await Shell . run ( " swift experimental-sdk remove \( bundleName) " )
122+ if runArguments. contains ( " rhel " ) {
123+ // Temporarily skip the RHEL-based SDK. XCTSkip() is not suitable as it would skipping the entire test case
124+ logger. warning ( " RHEL-based SDKs currently do not work with Swift 6.0: https://github.com/swiftlang/swift-sdk-generator/issues/138 " )
125+ continue
78126 }
79127
80- let installOutput = try await Shell . readStdout ( String ( installCommand) )
81- XCTAssertTrue ( installOutput. contains ( " successfully installed " ) )
128+ let bundleName = try await FileManager . default. withTemporaryDirectory ( logger: logger) { tempDir in
129+ try await buildSDK ( inDirectory: packageDirectory, scratchPath: tempDir. path, withArguments: runArguments)
130+ }
82131
83132 for testcase in self . testcases {
84- let testPackageURL = FileManager . default. temporaryDirectory. appendingPathComponent ( " swift-sdk-generator-test " )
85- let testPackageDir = FilePath ( testPackageURL. path)
86- try ? fm. removeItem ( atPath: testPackageDir. string)
87- try fm. createDirectory ( atPath: testPackageDir. string, withIntermediateDirectories: true )
88-
89- try await Shell . run ( " swift package --package-path \( testPackageDir) init --type executable " )
90- let main_swift = testPackageURL. appendingPathComponent ( " Sources/main.swift " )
91- try testcase. write ( to: main_swift, atomically: true , encoding: . utf8)
92-
93- var buildOutput = try await Shell . readStdout (
94- " swift build --package-path \( testPackageDir) --experimental-swift-sdk \( bundleName) "
95- )
96- XCTAssertTrue ( buildOutput. contains ( " Build complete! " ) )
97- try await Shell . run ( " rm -rf \( testPackageDir. appending ( " .build " ) ) " )
98- buildOutput = try await Shell . readStdout (
99- " swift build --package-path \( testPackageDir) --experimental-swift-sdk \( bundleName) --static-swift-stdlib "
100- )
101- XCTAssertTrue ( buildOutput. contains ( " Build complete! " ) )
133+ try await FileManager . default. withTemporaryDirectory ( logger: logger) { tempDir in
134+ let testPackageURL = tempDir. appendingPathComponent ( " swift-sdk-generator-test " )
135+ let testPackageDir = FilePath ( testPackageURL. path)
136+ try FileManager . default. createDirectory ( atPath: testPackageDir. string, withIntermediateDirectories: true )
137+
138+ try await Shell . run ( " swift package --package-path \( testPackageDir) init --type executable " )
139+ let main_swift = testPackageURL. appendingPathComponent ( " Sources/main.swift " )
140+ try testcase. write ( to: main_swift, atomically: true , encoding: . utf8)
141+
142+ var buildOutput = try await Shell . readStdout (
143+ " swift build --package-path \( testPackageDir) --experimental-swift-sdk \( bundleName) "
144+ )
145+ XCTAssertTrue ( buildOutput. contains ( " Build complete! " ) )
146+
147+ try await Shell . run ( " rm -rf \( testPackageDir. appending ( " .build " ) ) " )
148+
149+ buildOutput = try await Shell . readStdout (
150+ " swift build --package-path \( testPackageDir) --experimental-swift-sdk \( bundleName) --static-swift-stdlib "
151+ )
152+ XCTAssertTrue ( buildOutput. contains ( " Build complete! " ) )
153+ }
102154 }
103155 }
104156 }
105157
106158 func testRepeatedSDKBuilds( ) async throws {
107- throw XCTSkip ( " EndToEnd tests currently deadlock under `swift test`: https://github.com/swiftlang/swift-sdk-generator/issues/143 " )
108-
109- let fm = FileManager . default
159+ if ProcessInfo . processInfo . environment . keys . contains ( " JENKINS_URL " ) {
160+ throw XCTSkip ( " EndToEnd tests cannot currently run in CI: https://github.com/swiftlang/swift-sdk-generator/issues/145 " )
161+ }
110162
111163 var packageDirectory = FilePath ( #filePath)
112164 packageDirectory. removeLastComponent ( )
@@ -123,22 +175,16 @@ final class EndToEndTests: XCTestCase {
123175 }
124176
125177 for runArguments in possibleArguments {
126- let testPackageURL = FileManager . default. temporaryDirectory. appendingPathComponent ( " swift-sdk-generator-test " )
127- let testPackageDir = FilePath ( testPackageURL. path)
128- try ? fm. removeItem ( atPath: testPackageDir. string)
129- try fm. createDirectory ( atPath: testPackageDir. string, withIntermediateDirectories: true )
130- defer { try ? fm. removeItem ( atPath: testPackageDir. string) }
131-
132- let firstGeneratorOutput = try await Shell . readStdout (
133- " cd \( packageDirectory) && swift run swift-sdk-generator \( runArguments) "
134- )
135- XCTAssert ( firstGeneratorOutput. contains ( " swift experimental-sdk install " ) )
136-
137- let repeatGeneratorOutput = try await Shell . readStdout (
138- " cd \( packageDirectory) && swift run swift-sdk-generator \( runArguments) "
139- )
140- XCTAssert ( repeatGeneratorOutput. contains ( " swift experimental-sdk install " ) )
178+ if runArguments. contains ( " rhel " ) {
179+ // Temporarily skip the RHEL-based SDK. XCTSkip() is not suitable as it would skipping the entire test case
180+ logger. warning ( " RHEL-based SDKs currently do not work with Swift 6.0: https://github.com/swiftlang/swift-sdk-generator/issues/138 " )
181+ continue
182+ }
183+
184+ try await FileManager . default. withTemporaryDirectory ( logger: logger) { tempDir in
185+ let _ = try await buildSDK ( inDirectory: packageDirectory, scratchPath: tempDir. path, withArguments: runArguments)
186+ let _ = try await buildSDK ( inDirectory: packageDirectory, scratchPath: tempDir. path, withArguments: runArguments)
187+ }
141188 }
142189 }
143- #endif
144190}
0 commit comments