823fa91aa3
* Fix ETXTBSY race in claude-swap CLI card test The test wrote a shell script, set mode 0755, and executed it immediately. Under swift test --parallel a concurrent fork inherits the still-open write descriptor, so execve fails with ETXTBSY and the launch reports Cocoa 256. Write the script body as data and execute a checked-in trampoline that reads it, so execve only ever touches a file no test process has written. Measured in swift:6.3.3-noble on arm64: 112 failures in 600 attempts with the old shape, 0 in 600 with the trampoline. * Apply ETXTBSY fix to the Linux test target The first commit only touched Tests/CodexBarTests, which Package.swift builds on macOS alone. The Linux job compiles CodexBarLinuxTests from TestsLinux, so the race remained in the target that actually flaked. Convert all three TestsLinux sites through a shared FakeExecutable helper, and keep the macOS mirror in step. Verified on Linux arm64 in swift:6.3.3-noble: 355 tests in 53 suites pass.
34 lines
1.5 KiB
Swift
34 lines
1.5 KiB
Swift
import Foundation
|
|
|
|
/// Installs a fake CLI on disk for tests that need to launch one.
|
|
///
|
|
/// Executing a file the test process just wrote races with every other test that
|
|
/// spawns a child: the fork inherits the still-open write descriptor and execve
|
|
/// fails with `ETXTBSY`. Swift Testing runs the suite concurrently inside one
|
|
/// process, so that window is wide, and Linux Foundation has no
|
|
/// `POSIX_SPAWN_CLOEXEC_DEFAULT` to close it.
|
|
///
|
|
/// Writing the body as data and executing a checked-in trampoline keeps execve
|
|
/// away from every file this process wrote.
|
|
enum FakeExecutable {
|
|
/// Writes `body` beside `url` and links `url` to the checked-in trampoline.
|
|
static func install(_ body: String, at url: URL) throws {
|
|
try Data(body.utf8).write(to: url.appendingPathExtension("sh"))
|
|
try FileManager.default.createSymbolicLink(at: url, withDestinationURL: self.trampoline())
|
|
}
|
|
|
|
private static func trampoline() throws -> URL {
|
|
var directory = URL(filePath: #filePath).deletingLastPathComponent()
|
|
for _ in 0..<12 {
|
|
let candidate = directory.appending(path: "Tests/CodexBarTests/Fixtures/Scripts/exec-trampoline.sh")
|
|
if FileManager.default.fileExists(atPath: candidate.path(percentEncoded: false)) {
|
|
return candidate
|
|
}
|
|
directory.deleteLastPathComponent()
|
|
}
|
|
throw NSError(domain: "FakeExecutable", code: 1, userInfo: [
|
|
NSLocalizedDescriptionKey: "Could not locate exec-trampoline.sh from \(#filePath)",
|
|
])
|
|
}
|
|
}
|