Skip to content

Commit bc50fcb

Browse files
authored
Simplify correlation of test prefix to test ID. (#2071)
1 parent ddaf2ca commit bc50fcb

1 file changed

Lines changed: 36 additions & 16 deletions

File tree

Sources/ContainerTestSupport/ContainerFixture.swift

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,38 +80,54 @@ public final class ContainerFixture: Sendable {
8080
public static func with<T>(_ body: (ContainerFixture) async throws -> T) async throws -> T {
8181
let testID = String(UUID().uuidString.prefix(8)).lowercased()
8282

83-
let scratchRoot =
84-
ProcessInfo.processInfo.environment["CLITEST_SCRATCH_ROOT"]
85-
.map { FilePath($0) }
86-
?? FilePath(FileManager.default.temporaryDirectory.path)
87-
8883
let testName =
8984
Test.current.map { $0.name.hasSuffix("()") ? String($0.name.dropLast(2)) : $0.name }
9085
?? testID
91-
let suiteName = Test.current.map { "\(type(of: $0))" } ?? "unknown"
92-
93-
// Name the scratch directory so it's immediately identifiable when browsing:
94-
// {sanitizedTestName}-{testID}
95-
let safeName = testName.replacingOccurrences(
96-
of: "[^a-zA-Z0-9]", with: "-", options: .regularExpression)
97-
let testDir = scratchRoot.appending("\(safeName)-\(testID)")
98-
try FileManager.default.createDirectory(
99-
atPath: testDir.string, withIntermediateDirectories: true, attributes: nil)
100-
86+
// Test.current is a value describing the running test, not an instance of the suite
87+
// type, so `type(of:)` always yields `Test` itself. Derive the suite from the test's
88+
// fully-qualified ID instead (e.g. "IntegrationTests.TestCLIStatus/explicitTableFormat()/...")
89+
// — the same identifier format used in the swift-testing event-stream JSON.
90+
let testIdentifier = Test.current.map { "\($0.id)" }
91+
let suiteName = testIdentifier?.split(separator: "/", maxSplits: 1).first.map(String.init) ?? "unknown"
92+
93+
// Swift Testing doesn't expose a stable per-case identifier or the case's arguments
94+
// publicly, only `isParameterized`. Parameterized tests share one `testName` across all
95+
// their concurrently-running cases, so fall back to the per-invocation `testID` to keep
96+
// each case's log file distinct.
97+
let isParameterized = Test.Case.current?.isParameterized ?? false
98+
let logFileName = isParameterized ? "\(testName)-\(testID).log" : "\(testName).log"
99+
100+
// Set up logging before any fixture work (scratch dir creation, etc.) so a "test start"
101+
// message is the first thing recorded — bookended by "test end" once `body` returns.
101102
var logger = Logger(label: "com.apple.container.test") { label in
102103
if let root = ProcessInfo.processInfo.environment["CLITEST_LOG_ROOT"], !root.isEmpty {
103104
let path =
104105
FilePath(root)
105106
.appending("clitests")
106107
.appending(suiteName)
107-
.appending(testName + ".log")
108+
.appending(logFileName)
108109
if let handler = try? FileLogHandler(label: label, category: "clitests", path: path) {
109110
return handler
110111
}
111112
}
112113
return StreamLogHandler.standardOutput(label: label)
113114
}
114115
logger[metadataKey: "testID"] = "\(testID)"
116+
logger[metadataKey: "test"] = "\(testIdentifier ?? testName)"
117+
logger.info("test start")
118+
119+
let scratchRoot =
120+
ProcessInfo.processInfo.environment["CLITEST_SCRATCH_ROOT"]
121+
.map { FilePath($0) }
122+
?? FilePath(FileManager.default.temporaryDirectory.path)
123+
124+
// Name the scratch directory so it's immediately identifiable when browsing:
125+
// {sanitizedTestName}-{testID}
126+
let safeName = testName.replacingOccurrences(
127+
of: "[^a-zA-Z0-9]", with: "-", options: .regularExpression)
128+
let testDir = scratchRoot.appending("\(safeName)-\(testID)")
129+
try FileManager.default.createDirectory(
130+
atPath: testDir.string, withIntermediateDirectories: true, attributes: nil)
115131

116132
let fixture = ContainerFixture(testID: testID, testDir: testDir, log: logger)
117133

@@ -123,10 +139,14 @@ public final class ContainerFixture: Sendable {
123139

124140
do {
125141
let result = try await body(fixture)
142+
logger.info("test end", metadata: ["result": "pass"])
126143
await fixture.runCleanup()
144+
logger.info("test cleaned up")
127145
return result
128146
} catch {
147+
logger.info("test end", metadata: ["result": "fail", "error": "\(error)"])
129148
await fixture.runCleanup()
149+
logger.info("test cleaned up")
130150
throw error
131151
}
132152
}

0 commit comments

Comments
 (0)