diff options
| author | Eric Yue <jiacheng.yue@foxmail.com> | 2026-09-23 22:44:56 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-23 16:44:56 +0200 |
| commit | c958833fa81333bf07a255f7d1325e6892daca1e (patch) | |
| tree | 6d1f073d936f4a4c3d3fdc20b6b9857716e8967c | |
| parent | 9903007e5c4407ded451cac0b8164e3d69deb891 (diff) | |
test: wait for complete handoff pid markers (#4538)
* test: wait for complete handoff pid markers
* test: wait for complete handoff pid markers
| -rw-r--r-- | tests/live_handoff.rs | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/tests/live_handoff.rs b/tests/live_handoff.rs index ea4b84df..3420940c 100644 --- a/tests/live_handoff.rs +++ b/tests/live_handoff.rs @@ -410,6 +410,50 @@ fn wait_for_file_contains(path: &Path, needle: &str, timeout: Duration) -> Strin ); } +fn wait_for_pid_marker(path: &Path, timeout: Duration) -> u32 { + // Shell redirection creates the file before echo writes the PID. Wait for + // the newline too, so a partially written PID cannot be accepted. + let text = wait_for_file_contains(path, "\n", timeout); + text.lines() + .next() + .and_then(|line| line.split_whitespace().last()) + .and_then(|pid| pid.parse().ok()) + .filter(|pid| *pid > 0) + .unwrap_or_else(|| panic!("invalid PID marker at {}: {text:?}", path.display())) +} + +#[test] +fn pid_marker_waits_for_complete_line() { + let base = unique_test_dir(); + fs::create_dir_all(&base).unwrap(); + let marker = base.join("child.pid"); + // Keep each incomplete marker unchanged throughout the wait. In particular, + // READY 12 must time out rather than return a truncated but parseable PID. + for partial in ["", "READY ", "READY 12"] { + fs::write(&marker, partial).unwrap(); + let timeout = Duration::from_millis(100); + let started = Instant::now(); + let panic = std::panic::catch_unwind(|| wait_for_pid_marker(&marker, timeout)) + .expect_err("incomplete marker should time out"); + assert!( + started.elapsed() >= timeout, + "marker {partial:?} failed early" + ); + let message = panic.downcast_ref::<String>().expect("timeout diagnostic"); + assert_eq!( + message, + &format!( + "{} did not contain {:?}; last text was {partial:?}", + marker.display(), + "\n" + ) + ); + } + fs::write(&marker, "READY 1234\n").unwrap(); + assert_eq!(wait_for_pid_marker(&marker, Duration::from_secs(1)), 1234); + fs::remove_dir_all(base).unwrap(); +} + #[cfg(target_os = "linux")] fn server_ptmx_fd_count(pid: u32) -> usize { let Ok(entries) = fs::read_dir(format!("/proc/{pid}/fd")) else { @@ -1014,17 +1058,8 @@ fn live_handoff_preserves_pane_process_io() { "params": {"pane_id": second_pane_id, "text": second_command, "keys": ["Enter"]} }), )); - support::wait_for_file(&marker, Duration::from_secs(5)); - support::wait_for_file(&second_marker, Duration::from_secs(5)); - let pid_text = fs::read_to_string(&marker).unwrap(); - let child_pid: u32 = pid_text.split_whitespace().last().unwrap().parse().unwrap(); - let second_pid_text = fs::read_to_string(&second_marker).unwrap(); - let second_child_pid: u32 = second_pid_text - .split_whitespace() - .last() - .unwrap() - .parse() - .unwrap(); + let child_pid = wait_for_pid_marker(&marker, Duration::from_secs(5)); + let second_child_pid = wait_for_pid_marker(&second_marker, Duration::from_secs(5)); assert_eq!(unsafe { libc::kill(child_pid as libc::pid_t, 0) }, 0); assert_eq!(unsafe { libc::kill(second_child_pid as libc::pid_t, 0) }, 0); @@ -1955,9 +1990,7 @@ fn live_handoff_bad_expected_protocol_rolls_back_old_server() { "params": {"pane_id": pane_id, "text": command, "keys": ["Enter"]} }), )); - support::wait_for_file(&marker, Duration::from_secs(5)); - let pid_text = fs::read_to_string(&marker).unwrap(); - let child_pid: u32 = pid_text.split_whitespace().last().unwrap().parse().unwrap(); + let child_pid = wait_for_pid_marker(&marker, Duration::from_secs(5)); let failed = request( &api_socket, @@ -2041,9 +2074,7 @@ fn live_handoff_import_failure_rolls_back_old_server_at(failure_point: &str) { "params": {"pane_id": pane_id, "text": command, "keys": ["Enter"]} }), )); - support::wait_for_file(&marker, Duration::from_secs(5)); - let pid_text = fs::read_to_string(&marker).unwrap(); - let child_pid: u32 = pid_text.split_whitespace().last().unwrap().parse().unwrap(); + let child_pid = wait_for_pid_marker(&marker, Duration::from_secs(5)); let failed = request( &api_socket, |
