aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/client_mode.rs47
-rw-r--r--tests/live_handoff.rs25
2 files changed, 65 insertions, 7 deletions
diff --git a/tests/client_mode.rs b/tests/client_mode.rs
index a946af7c..71d3ff8d 100644
--- a/tests/client_mode.rs
+++ b/tests/client_mode.rs
@@ -716,6 +716,39 @@ fn output_len(output: &SharedOutput) -> usize {
output.lock().unwrap_or_else(|p| p.into_inner()).text.len()
}
+fn sidebar_row_click(screen: &str, label: &str) -> Vec<u8> {
+ let sidebar_width = screen
+ .lines()
+ .find_map(|line| line.chars().position(|character| character == '│'))
+ .expect("visible sidebar boundary");
+ let row = screen
+ .lines()
+ .position(|line| {
+ line.chars()
+ .take(sidebar_width)
+ .collect::<String>()
+ .contains(label)
+ })
+ .unwrap_or_else(|| panic!("sidebar row {label:?} is not visible: {screen}"))
+ + 1;
+ format!("\x1b[<0;7;{row}M\x1b[<0;7;{row}m").into_bytes()
+}
+
+#[test]
+fn sidebar_row_click_tracks_restored_workspace_count() {
+ for restored in [false, true] {
+ let screen = format!(
+ " machines │\n │\n ▾ Local │local-returned in pane output\n{} · local-returned └─────────────────\n",
+ if restored { " · restored │\n" } else { "" }
+ );
+ let row = if restored { 5 } else { 4 };
+ assert_eq!(
+ sidebar_row_click(&screen, "local-returned"),
+ format!("\x1b[<0;7;{row}M\x1b[<0;7;{row}m").into_bytes()
+ );
+ }
+}
+
/// Spawns a server + real thin client under a PTY and waits until the client
/// has attached and rendered a frame. Returns the pieces plus a shared buffer
/// that keeps accumulating PTY output (including teardown) on a background
@@ -1074,20 +1107,22 @@ fn federated_client_starts_without_local_and_survives_its_restart() {
local_pane,
"printf 'LOCAL_RECOVERED_SURFACE\\n'",
);
- let watermark = output_len(&output);
// Select the fresh workspace below Local's restored workspace.
- input.write_all(b"\x1b[<0;7;5M\x1b[<0;7;5m").unwrap();
+ // A fast shutdown may leave no saved workspace, so locate the actual row.
+ input
+ .write_all(&sidebar_row_click(&screen_text(), "local-returned"))
+ .unwrap();
assert!(
wait_until(Duration::from_secs(10), Duration::from_millis(20), || {
- read_output(&output)[watermark..].contains("LOCAL_RECOVERED_SURFACE")
+ screen_text().contains("LOCAL_RECOVERED_SURFACE")
}),
"recovered Local must be selectable: {}",
- read_output(&output)
+ screen_text()
);
// A coherent frame precedes the final host-effects fence; input stays gated until then.
assert!(
wait_until(Duration::from_secs(8), Duration::from_millis(100), || {
- if read_output(&output)[watermark..].contains("LOCAL_INPUT_RECOVERED") {
+ if screen_text().contains("LOCAL_INPUT_RECOVERED") {
return true;
}
input
@@ -1096,7 +1131,7 @@ fn federated_client_starts_without_local_and_survives_its_restart() {
false
}),
"recovered Local must accept input: {}",
- read_output(&output)
+ screen_text()
);
drop(input);
drop(client);
diff --git a/tests/live_handoff.rs b/tests/live_handoff.rs
index e40f8268..ea4b84df 100644
--- a/tests/live_handoff.rs
+++ b/tests/live_handoff.rs
@@ -1581,9 +1581,13 @@ fn live_handoff_keeps_agent_started_pane_after_agent_exits() {
let api_socket = runtime_dir.join("herdr.sock");
let started_marker = base.join("agent-started");
let exited_marker = base.join("agent-exited");
+ let ready_marker = base.join("shell-ready");
let shell_marker = base.join("shell-after-agent");
let bin = base.join("bin");
fs::create_dir_all(&bin).unwrap();
+ let delayed_shell = bin.join("delayed-shell");
+ fs::write(&delayed_shell, "#!/bin/sh\n/bin/sleep 0.4\nexec /bin/sh\n").unwrap();
+ fs::set_permissions(&delayed_shell, fs::Permissions::from_mode(0o755)).unwrap();
let fake_pi = bin.join("pi");
fs::write(
&fake_pi,
@@ -1601,7 +1605,10 @@ fn live_handoff_keeps_agent_started_pane_after_agent_exits() {
&config_home,
&runtime_dir,
&api_socket,
- &[("PATH", path.as_str())],
+ &[
+ ("PATH", path.as_str()),
+ ("SHELL", delayed_shell.to_str().unwrap()),
+ ],
);
wait_for_socket(&api_socket, Duration::from_secs(10));
register_runtime_dir(&runtime_dir);
@@ -1619,6 +1626,22 @@ fn live_handoff_keeps_agent_started_pane_after_agent_exits() {
.unwrap()
.to_string();
+ assert_ok(request(
+ &api_socket,
+ serde_json::json!({
+ "id": "test:shell-ready",
+ "method": "pane.send_input",
+ "params": {
+ "pane_id": pane_id,
+ "text": format!("printf ready > {}", ready_marker.display()),
+ "keys": ["Enter"]
+ }
+ }),
+ ));
+ // Creation acknowledges the PTY, not an idle interactive shell. A real
+ // shell command must execute before this raw agent.start request.
+ support::wait_for_file(&ready_marker, Duration::from_secs(5));
+
let started = request(
&api_socket,
serde_json::json!({