@@ -17,6 +17,38 @@ import XCTest
17
17
18
18
@testable import SwiftSDKGenerator
19
19
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
+
20
52
final class EndToEndTests : XCTestCase {
21
53
private let testcases = [
22
54
#"""
@@ -37,11 +69,40 @@ final class EndToEndTests: XCTestCase {
37
69
38
70
private let logger = Logger ( label: " swift-sdk-generator " )
39
71
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
+ }
43
101
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
+ }
45
106
46
107
var packageDirectory = FilePath ( #filePath)
47
108
packageDirectory. removeLastComponent ( )
@@ -58,55 +119,46 @@ final class EndToEndTests: XCTestCase {
58
119
}
59
120
60
121
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
78
126
}
79
127
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
+ }
82
131
83
132
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
+ }
102
154
}
103
155
}
104
156
}
105
157
106
158
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
+ }
110
162
111
163
var packageDirectory = FilePath ( #filePath)
112
164
packageDirectory. removeLastComponent ( )
@@ -123,22 +175,16 @@ final class EndToEndTests: XCTestCase {
123
175
}
124
176
125
177
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
+ }
141
188
}
142
189
}
143
- #endif
144
190
}
0 commit comments