From dbe656537dbb6ffc79d142272d39d090d670d7a2 Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Sun, 13 Sep 2026 20:51:16 -0300 Subject: [PATCH] test(core): wait out ETXTBSY before running the fake container CLI FakeCli writes a shell script and then executes it. Tests run on parallel threads, and a child forked by another test while fs::write had the script open inherits that write descriptor until it execs; executing the script in that window fails with 'Text file busy (os error 26)'. Seen as a CI failure of a_missing_image_fails_without_retrying. Run the script once right after writing it, retrying while it reports ExecutableFileBusy. Once that succeeds nothing can hold a writable descriptor to it again. --- crates/fakecloud-core/src/container_image.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/fakecloud-core/src/container_image.rs b/crates/fakecloud-core/src/container_image.rs index 21a24cd6d..5b2c91585 100644 --- a/crates/fakecloud-core/src/container_image.rs +++ b/crates/fakecloud-core/src/container_image.rs @@ -307,6 +307,26 @@ exit 2 let path = dir.path().join("cli"); std::fs::write(&path, script).unwrap(); std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755)).unwrap(); + // Executing a file that another process holds open for writing + // fails with ETXTBSY. Tests run in parallel threads, and a child + // forked by another test while `fs::write` above had the script + // open inherits that descriptor until it execs. Run the script + // once, retrying until nothing holds it; after that no process can + // gain a writable descriptor to it again. + let mut attempts = 0; + loop { + match std::process::Command::new(&path).arg("probe").output() { + Err(e) + if e.kind() == std::io::ErrorKind::ExecutableFileBusy && attempts < 200 => + { + attempts += 1; + std::thread::sleep(Duration::from_millis(5)); + } + Err(e) => panic!("fake CLI did not run: {e}"), + Ok(_) => break, + } + } + let _ = std::fs::remove_file(dir.path().join("calls.log")); Self { dir } }