Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust-clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
- name: Rust workspace tests
env:
FRESHELL_SERVER_BIN: ${{ github.workspace }}/target/debug/freshell-server
run: cargo test --workspace --locked
run: cargo test --workspace --locked --no-fail-fast

# Dedicated Tauri smoke with --nocapture so the CI log visibly shows
# "using server binary:" (confirming the test exercised the real binary,
Expand Down
14 changes: 14 additions & 0 deletions crates/freshell-ws/tests/pane_ledger_triggers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1787,3 +1787,17 @@ async fn a_kill_whose_row_projection_fails_still_ends_the_terminal_and_converges
registry.kill(&terminal_id);
std::fs::remove_dir_all(&dir).ok();
}

/// Regression test for the shared `common::sleeper_cli_spec` uniqueness fix:
/// two calls with the same name must not share a script path, or parallel
/// tests race ETXTBSY ("Text file busy") when one writes while another execves.
#[test]
fn shared_sleeper_cli_spec_paths_are_unique_per_call() {
let first = sleeper_cli_spec("claude");
let second = sleeper_cli_spec("claude");
assert_ne!(
first.default_cmd, second.default_cmd,
"same-name specs from common::sleeper_cli_spec must not share a script path -- \
a shared path lets a later write race an earlier spawn's execve (ETXTBSY)"
);
}
9 changes: 8 additions & 1 deletion crates/freshell-ws/tests/restore_spawn_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ fn test_settings_value() -> serde_json::Value {
/// A minimal always-present CLI spec (`/bin/sh` sleeper script) so non-shell
/// creates genuinely spawn — the same recording-script convention as
/// `session_identity_frames.rs` (these tests assert on wire frames, not argv).
///
/// Each call writes a **unique** script path (PID + atomic counter) so parallel
/// tests in the same binary never collide with ETXTBSY ("Text file busy") when
/// one test writes the script while another is executing a prior copy.
static SLEEPER_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);

fn sleeper_cli_spec(name: &str) -> freshell_platform::CliCommandSpec {
let seq = SLEEPER_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let script_path = std::env::temp_dir().join(format!(
"freshell-restore-gate-sleeper-{name}-{}.sh",
"freshell-restore-gate-sleeper-{name}-{}-{seq}.sh",
std::process::id()
));
std::fs::write(&script_path, "#!/bin/sh\nexec sleep 30\n").expect("write sleeper script");
Expand Down
Loading