Files
steipete--codexbar/TestsLinux/FakeExecutableSupport.swift
Urda 823fa91aa3 Fix ETXTBSY race in claude-swap CLI card test (#2644)
* 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.
2026-08-04 19:35:30 -07:00

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)",
])
}
}