aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-23 15:11:48 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-23 15:19:36 +0300
commit9817820af1f0468402934122538f658299ff71de (patch)
tree1bf668cf866213d10eec30a85401aedc54fb714f /tests
parented11779fcaebea7cc3223c4e221ea43674057891 (diff)
feat: add worktree cli and socket api
Diffstat (limited to 'tests')
-rw-r--r--tests/api_ping.rs20
-rw-r--r--tests/cli_wrapper.rs343
-rw-r--r--tests/client_mode.rs36
-rw-r--r--tests/cross_area.rs16
-rw-r--r--tests/detach_reattach.rs44
-rw-r--r--tests/multi_client.rs2
-rw-r--r--tests/server_headless.rs14
7 files changed, 410 insertions, 65 deletions
diff --git a/tests/api_ping.rs b/tests/api_ping.rs
index a8012ea6..b1468ae4 100644
--- a/tests/api_ping.rs
+++ b/tests/api_ping.rs
@@ -227,7 +227,7 @@ fn ping_over_socket_returns_version() {
assert_eq!(value["result"]["version"], env!("CARGO_PKG_VERSION"));
// Intentionally hardcoded so wire protocol bumps require updating this test.
// Changing this value means old clients/servers are no longer compatible.
- assert_eq!(value["result"]["protocol"], 9);
+ assert_eq!(value["result"]["protocol"], 10);
cleanup_spawned_herdr(child, base);
}
@@ -1073,7 +1073,7 @@ fn events_subscribe_streams_tab_and_workspace_close_events() {
let mut reader = open_subscription(
&socket_path,
- r#"{"id":"sub_life_c","method":"events.subscribe","params":{"subscriptions":[{"type":"tab.closed"},{"type":"workspace.closed"}]}}"#,
+ r#"{"id":"sub_life_c","method":"events.subscribe","params":{"subscriptions":[{"type":"workspace.renamed"},{"type":"tab.closed"},{"type":"workspace.closed"}]}}"#,
);
let ack = reader.read_json_line(Duration::from_secs(2));
@@ -1092,10 +1092,24 @@ fn events_subscribe_streams_tab_and_workspace_close_events() {
let tab_closed = wait_for_event(&mut reader, "tab_closed", Duration::from_secs(2));
assert_eq!(tab_closed["data"]["tab_id"], second_tab_id);
+ let renamed_ws = send_request(
+ &socket_path,
+ &format!(
+ r#"{{"id":"req_tc_4","method":"workspace.rename","params":{{"workspace_id":"{}","label":"renamed"}}}}"#,
+ workspace_id
+ ),
+ );
+ assert_eq!(renamed_ws["result"]["workspace"]["label"], "renamed");
+
+ let workspace_renamed =
+ wait_for_event(&mut reader, "workspace_renamed", Duration::from_secs(2));
+ assert_eq!(workspace_renamed["data"]["workspace_id"], workspace_id);
+ assert_eq!(workspace_renamed["data"]["label"], "renamed");
+
let closed_ws = send_request(
&socket_path,
&format!(
- r#"{{"id":"req_tc_4","method":"workspace.close","params":{{"workspace_id":"{}"}}}}"#,
+ r#"{{"id":"req_tc_5","method":"workspace.close","params":{{"workspace_id":"{}"}}}}"#,
workspace_id
),
);
diff --git a/tests/cli_wrapper.rs b/tests/cli_wrapper.rs
index 93d0161f..902ea467 100644
--- a/tests/cli_wrapper.rs
+++ b/tests/cli_wrapper.rs
@@ -24,6 +24,31 @@ fn unique_test_dir() -> PathBuf {
PathBuf::from(format!("/tmp/hcli-{}-{nanos}", std::process::id()))
}
+fn run_git(repo: &Path, args: &[&str]) {
+ let status = Command::new("git")
+ .arg("-C")
+ .arg(repo)
+ .args(args)
+ .status()
+ .unwrap();
+ assert!(
+ status.success(),
+ "git command failed: git -C {} {}",
+ repo.display(),
+ args.join(" ")
+ );
+}
+
+fn create_committed_repo(path: &Path) {
+ fs::create_dir_all(path).unwrap();
+ run_git(path, &["init", "--quiet"]);
+ run_git(path, &["config", "user.email", "herdr@example.invalid"]);
+ run_git(path, &["config", "user.name", "Herdr Test"]);
+ fs::write(path.join("README.md"), "test\n").unwrap();
+ run_git(path, &["add", "README.md"]);
+ run_git(path, &["commit", "--quiet", "-m", "initial"]);
+}
+
struct SpawnedHerdr {
_master: Box<dyn MasterPty + Send>,
child: Box<dyn Child + Send + Sync>,
@@ -220,8 +245,25 @@ fn run_cli(socket_path: &Path, args: &[&str]) -> std::process::Output {
command.output().unwrap()
}
+fn run_cli_in_dir(socket_path: &Path, args: &[&str], current_dir: &Path) -> std::process::Output {
+ let mut command = Command::new(env!("CARGO_BIN_EXE_herdr"));
+ command.args(args);
+ command.current_dir(current_dir);
+ command.env("HERDR_SOCKET_PATH", socket_path);
+ command.output().unwrap()
+}
+
fn run_cli_json(socket_path: &Path, args: &[&str]) -> serde_json::Value {
let output = run_cli(socket_path, args);
+ parse_cli_json_output(args, output)
+}
+
+fn run_cli_json_in_dir(socket_path: &Path, args: &[&str], current_dir: &Path) -> serde_json::Value {
+ let output = run_cli_in_dir(socket_path, args, current_dir);
+ parse_cli_json_output(args, output)
+}
+
+fn parse_cli_json_output(args: &[&str], output: std::process::Output) -> serde_json::Value {
assert!(
output.status.success(),
"command failed: herdr {}\nstatus: {:?}\nstderr: {}\nstdout: {}",
@@ -560,6 +602,7 @@ fn help_commands_exit_successfully() {
&["status", "-h"],
&["server", "-h"],
&["workspace", "-h"],
+ &["worktree", "-h"],
&["tab", "-h"],
&["pane", "-h"],
&["wait", "-h"],
@@ -968,7 +1011,7 @@ fn status_commands_report_client_and_server_versions() {
"stdout: {full_stdout}"
);
assert!(
- full_stdout.contains(" protocol: 9"),
+ full_stdout.contains(" protocol: 10"),
"stdout: {full_stdout}"
);
assert!(full_stdout.contains("server:\n"), "stdout: {full_stdout}");
@@ -1001,7 +1044,7 @@ fn status_commands_report_client_and_server_versions() {
"stdout: {server_stdout}"
);
assert!(
- server_stdout.contains("protocol: 9"),
+ server_stdout.contains("protocol: 10"),
"stdout: {server_stdout}"
);
@@ -1013,7 +1056,7 @@ fn status_commands_report_client_and_server_versions() {
"stdout: {client_stdout}"
);
assert!(
- client_stdout.contains("protocol: 9"),
+ client_stdout.contains("protocol: 10"),
"stdout: {client_stdout}"
);
assert!(
@@ -1023,7 +1066,7 @@ fn status_commands_report_client_and_server_versions() {
let full_json = run_cli_json(&socket_path, &["status", "--json"]);
assert_eq!(full_json["client"]["version"], env!("CARGO_PKG_VERSION"));
- assert_eq!(full_json["client"]["protocol"], 9);
+ assert_eq!(full_json["client"]["protocol"], 10);
assert_eq!(full_json["server"]["status"], "running");
assert_eq!(full_json["server"]["running"], true);
assert_eq!(full_json["server"]["compatible"], true);
@@ -1037,12 +1080,12 @@ fn status_commands_report_client_and_server_versions() {
let server_json = run_cli_json(&socket_path, &["status", "server", "--json"]);
assert_eq!(server_json["status"], "running");
assert_eq!(server_json["version"], env!("CARGO_PKG_VERSION"));
- assert_eq!(server_json["protocol"], 9);
+ assert_eq!(server_json["protocol"], 10);
assert_eq!(server_json["compatible"], true);
let client_json = run_cli_json(&socket_path, &["status", "client", "--json"]);
assert_eq!(client_json["version"], env!("CARGO_PKG_VERSION"));
- assert_eq!(client_json["protocol"], 9);
+ assert_eq!(client_json["protocol"], 10);
assert!(client_json["binary"]
.as_str()
.is_some_and(|path| !path.is_empty()));
@@ -1218,6 +1261,294 @@ fn workspace_and_pane_management_commands_work() {
}
#[test]
+fn worktree_management_commands_work() {
+ let base = unique_test_dir();
+ let config_home = base.join("config");
+ let runtime_dir = base.join("runtime");
+ let socket_path = runtime_dir.join("herdr.sock");
+ let repo = base.join("repo");
+ let checkout = base.join("checkout");
+ create_committed_repo(&repo);
+
+ let herdr = spawn_herdr(&config_home, &runtime_dir, &socket_path);
+ wait_for_socket(&socket_path, Duration::from_secs(5));
+
+ let branch = "worktree/cli-wrapper";
+ let created = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "create",
+ "--cwd",
+ repo.to_str().unwrap(),
+ "--branch",
+ branch,
+ "--path",
+ checkout.to_str().unwrap(),
+ "--json",
+ ],
+ );
+ assert_eq!(created["result"]["type"], "worktree_created");
+ assert_eq!(created["result"]["worktree"]["branch"], branch);
+ let child_workspace_id = created["result"]["workspace"]["workspace_id"]
+ .as_str()
+ .unwrap()
+ .to_string();
+ assert!(checkout.join("README.md").exists());
+
+ let workspaces = run_cli_json(&socket_path, &["workspace", "list"]);
+ let workspace_list = workspaces["result"]["workspaces"].as_array().unwrap();
+ let parent_workspace_id = workspace_list
+ .iter()
+ .find(|workspace| workspace["worktree"]["is_linked_worktree"].as_bool() == Some(false))
+ .and_then(|workspace| workspace["workspace_id"].as_str())
+ .unwrap()
+ .to_string();
+ assert!(workspace_list.iter().any(|workspace| {
+ workspace["workspace_id"].as_str() == Some(child_workspace_id.as_str())
+ && workspace["worktree"]["is_linked_worktree"].as_bool() == Some(true)
+ }));
+
+ let listed = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "list",
+ "--workspace",
+ &parent_workspace_id,
+ "--json",
+ ],
+ );
+ let listed_entry = listed["result"]["worktrees"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .find(|entry| entry["branch"].as_str() == Some(branch))
+ .unwrap();
+ assert_eq!(
+ listed_entry["open_workspace_id"].as_str(),
+ Some(child_workspace_id.as_str())
+ );
+
+ let opened = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "open",
+ "--workspace",
+ &parent_workspace_id,
+ "--branch",
+ branch,
+ "--json",
+ ],
+ );
+ assert_eq!(opened["result"]["type"], "worktree_opened");
+ assert_eq!(opened["result"]["already_open"], true);
+ assert_eq!(
+ opened["result"]["workspace"]["workspace_id"].as_str(),
+ Some(child_workspace_id.as_str())
+ );
+
+ fs::write(checkout.join("README.md"), "dirty\n").unwrap();
+ let safe_remove = run_cli(
+ &socket_path,
+ &[
+ "worktree",
+ "remove",
+ "--workspace",
+ &child_workspace_id,
+ "--json",
+ ],
+ );
+ assert_eq!(safe_remove.status.code(), Some(1));
+ let safe_remove_json: serde_json::Value = serde_json::from_slice(&safe_remove.stderr).unwrap();
+ assert_eq!(
+ safe_remove_json["error"]["code"],
+ "dirty_worktree_requires_force"
+ );
+ assert!(checkout.exists());
+
+ let force_removed = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "remove",
+ "--workspace",
+ &child_workspace_id,
+ "--force",
+ "--json",
+ ],
+ );
+ assert_eq!(force_removed["result"]["type"], "worktree_removed");
+ assert_eq!(force_removed["result"]["forced"], true);
+ assert!(!checkout.exists());
+
+ cleanup_spawned_herdr(herdr, base);
+}
+
+#[test]
+fn worktree_open_existing_checkout_by_path_and_branch() {
+ let base = unique_test_dir();
+ let config_home = base.join("config");
+ let runtime_dir = base.join("runtime");
+ let socket_path = runtime_dir.join("herdr.sock");
+ let repo = base.join("repo");
+ let checkout = base.join("external-checkout");
+ create_committed_repo(&repo);
+ let branch = "worktree/cli-open-existing";
+ run_git(
+ &repo,
+ &[
+ "worktree",
+ "add",
+ "--quiet",
+ "-b",
+ branch,
+ checkout.to_str().unwrap(),
+ "HEAD",
+ ],
+ );
+
+ let herdr = spawn_herdr(&config_home, &runtime_dir, &socket_path);
+ wait_for_socket(&socket_path, Duration::from_secs(5));
+
+ let opened = run_cli_json_in_dir(
+ &socket_path,
+ &[
+ "worktree",
+ "open",
+ "--cwd",
+ "repo",
+ "--path",
+ "external-checkout",
+ "--json",
+ ],
+ &base,
+ );
+ assert_eq!(opened["result"]["type"], "worktree_opened");
+ assert_eq!(opened["result"]["already_open"], false);
+ assert_eq!(opened["result"]["worktree"]["branch"], branch);
+ assert_eq!(
+ opened["result"]["workspace"]["worktree"]["is_linked_worktree"],
+ true
+ );
+ let child_workspace_id = opened["result"]["workspace"]["workspace_id"]
+ .as_str()
+ .unwrap()
+ .to_string();
+
+ let workspaces = run_cli_json(&socket_path, &["workspace", "list"]);
+ let workspace_list = workspaces["result"]["workspaces"].as_array().unwrap();
+ let parent_workspace_id = workspace_list
+ .iter()
+ .find(|workspace| workspace["worktree"]["is_linked_worktree"].as_bool() == Some(false))
+ .and_then(|workspace| workspace["workspace_id"].as_str())
+ .unwrap()
+ .to_string();
+
+ let listed = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "list",
+ "--workspace",
+ &parent_workspace_id,
+ "--json",
+ ],
+ );
+ let listed_entry = listed["result"]["worktrees"]
+ .as_array()
+ .unwrap()
+ .iter()
+ .find(|entry| entry["branch"].as_str() == Some(branch))
+ .unwrap();
+ assert_eq!(
+ listed_entry["open_workspace_id"].as_str(),
+ Some(child_workspace_id.as_str())
+ );
+
+ let reopened = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "open",
+ "--workspace",
+ &parent_workspace_id,
+ "--branch",
+ branch,
+ "--json",
+ ],
+ );
+ assert_eq!(reopened["result"]["type"], "worktree_opened");
+ assert_eq!(reopened["result"]["already_open"], true);
+ assert_eq!(
+ reopened["result"]["workspace"]["workspace_id"].as_str(),
+ Some(child_workspace_id.as_str())
+ );
+
+ let removed = run_cli_json(
+ &socket_path,
+ &[
+ "worktree",
+ "remove",
+ "--workspace",
+ &child_workspace_id,
+ "--force",
+ "--json",
+ ],
+ );
+ assert_eq!(removed["result"]["type"], "worktree_removed");
+
+ cleanup_spawned_herdr(herdr, base);
+}
+
+#[test]
+fn worktree_cli_rejects_local_argument_errors_before_socket_use() {
+ let base = unique_test_dir();
+ fs::create_dir_all(&base).unwrap();
+ let socket_path = base.join("missing.sock");
+ let cases: &[&[&str]] = &[
+ &["worktree", "list", "--workspace", "1", "--cwd", "/tmp"],
+ &["worktree", "create", "--workspace", "1", "--cwd", "/tmp"],
+ &["worktree", "open", "--workspace", "1"],
+ &[
+ "worktree",
+ "open",
+ "--workspace",
+ "1",
+ "--path",
+ "a",
+ "--branch",
+ "b",
+ ],
+ &[
+ "worktree",
+ "open",
+ "--workspace",
+ "1",
+ "--cwd",
+ "/tmp",
+ "--branch",
+ "b",
+ ],
+ ];
+
+ for args in cases {
+ let output = run_cli(&socket_path, args);
+ assert_eq!(
+ output.status.code(),
+ Some(2),
+ "herdr {} should fail as local parse error; stdout={} stderr={}",
+ args.join(" "),
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr)
+ );
+ }
+
+ cleanup_test_base(&base);
+}
+
+#[test]
fn tab_management_commands_work() {
let base = unique_test_dir();
let config_home = base.join("config");
diff --git a/tests/client_mode.rs b/tests/client_mode.rs
index 6a9546a3..6e3e52cd 100644
--- a/tests/client_mode.rs
+++ b/tests/client_mode.rs
@@ -274,8 +274,8 @@ fn client_connects_and_receives_frame() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9, "server should report protocol version 9");
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10, "server should report protocol version 10");
assert!(
error.is_none(),
"handshake should not have error: {:?}",
@@ -342,8 +342,8 @@ fn client_sees_headless_startup_config_diagnostic() {
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
stream
@@ -391,8 +391,8 @@ fn client_input_forwarded_to_pane() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Send an Input message containing "echo hello\n".
@@ -445,8 +445,8 @@ fn client_resize_sends_message() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain the initial frame(s).
@@ -504,8 +504,8 @@ fn server_shutdown_sends_message_to_client() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Send SIGINT so the server takes the graceful shutdown path and
@@ -736,8 +736,8 @@ fn client_receives_frame_after_pane_output() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
read_next_frame_payload(&mut stream, Duration::from_secs(10))
@@ -783,8 +783,8 @@ fn navigate_mode_keybind_dispatch_in_server() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -901,8 +901,8 @@ fn graceful_shutdown_sends_server_shutdown_to_client() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frame(s).
@@ -1000,8 +1000,8 @@ fn client_receives_notify_on_agent_state_change() {
// Connect as a client and perform handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frame(s).
diff --git a/tests/cross_area.rs b/tests/cross_area.rs
index 5bd37efe..37adda43 100644
--- a/tests/cross_area.rs
+++ b/tests/cross_area.rs
@@ -686,7 +686,7 @@ fn cross_area_detach_and_reattach_preserves_state() {
// Local attach (client A).
let mut client_a = UnixStream::connect(&client_socket).expect("client A should connect");
- client_handshake(&mut client_a, 9, 100, 30);
+ client_handshake(&mut client_a, 10, 100, 30);
assert!(wait_for_frame(&mut client_a, Duration::from_secs(2)));
// Use herdr: create a workspace and write output into its pane.
@@ -723,7 +723,7 @@ fn cross_area_detach_and_reattach_preserves_state() {
// Reattach from another terminal/session (client B).
let mut client_b = UnixStream::connect(&client_socket).expect("client B should connect");
- client_handshake(&mut client_b, 9, 80, 24);
+ client_handshake(&mut client_b, 10, 80, 24);
assert!(
wait_for_frame(&mut client_b, Duration::from_secs(5)),
"reattached client should receive frame"
@@ -779,7 +779,7 @@ fn cross_area_agent_process_survives_detach_and_reattach() {
wait_for_socket(&client_socket, Duration::from_secs(10));
let mut client_a = UnixStream::connect(&client_socket).expect("client A should connect");
- client_handshake(&mut client_a, 9, 100, 30);
+ client_handshake(&mut client_a, 10, 100, 30);
assert!(wait_for_frame(&mut client_a, Duration::from_secs(2)));
let created = workspace_create(&api_socket, "agent-persist");
@@ -832,7 +832,7 @@ fn cross_area_agent_process_survives_detach_and_reattach() {
// Reattach and ensure client-side state reflects the persisted working status.
let mut client_b = UnixStream::connect(&client_socket).expect("client B should connect");
- client_handshake(&mut client_b, 9, 80, 24);
+ client_handshake(&mut client_b, 10, 80, 24);
let saw_working_on_client =
wait_for_frame_matching(&mut client_b, Duration::from_secs(5), |frame| {
frame_contains_text(frame, "working")
@@ -877,7 +877,7 @@ fn cross_area_client_and_api_workspace_views_are_consistent() {
wait_for_socket(&client_socket, Duration::from_secs(10));
let mut client = UnixStream::connect(&client_socket).expect("client should connect");
- client_handshake(&mut client, 9, 100, 30);
+ client_handshake(&mut client, 10, 100, 30);
assert!(wait_for_frame(&mut client, Duration::from_secs(2)));
drain_server_messages(&mut client, Duration::from_millis(300));
@@ -940,9 +940,9 @@ fn cross_area_two_clients_shared_view_and_single_detach_stability() {
wait_for_socket(&client_socket, Duration::from_secs(10));
let mut client_a = UnixStream::connect(&client_socket).expect("client A should connect");
- client_handshake(&mut client_a, 9, 110, 30);
+ client_handshake(&mut client_a, 10, 110, 30);
let mut client_b = UnixStream::connect(&client_socket).expect("client B should connect");
- client_handshake(&mut client_b, 9, 100, 30);
+ client_handshake(&mut client_b, 10, 100, 30);
assert!(wait_for_frame(&mut client_a, Duration::from_secs(2)));
assert!(wait_for_frame(&mut client_b, Duration::from_secs(2)));
@@ -1111,7 +1111,7 @@ fn cross_area_server_kill_then_restart_and_reconnect() {
let mut reconnect_client =
UnixStream::connect(&client_socket).expect("new client should connect after restart");
- client_handshake(&mut reconnect_client, 9, 80, 24);
+ client_handshake(&mut reconnect_client, 10, 80, 24);
assert!(
wait_for_frame(&mut reconnect_client, Duration::from_secs(5)),
"new client should receive frame after restart"
diff --git a/tests/detach_reattach.rs b/tests/detach_reattach.rs
index 1d17739a..d486fb82 100644
--- a/tests/detach_reattach.rs
+++ b/tests/detach_reattach.rs
@@ -276,8 +276,8 @@ fn navigate_q_detaches_client_and_server_persists() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -338,8 +338,8 @@ fn explicit_detach_message_causes_clean_disconnect() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -397,8 +397,8 @@ fn reattach_after_detach_shows_current_state() {
// --- Client A ---
let mut stream_a = UnixStream::connect(&client_socket).expect("client A should connect");
let (version, error) =
- client_handshake(&mut stream_a, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_a, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -436,8 +436,8 @@ fn reattach_after_detach_shows_current_state() {
// --- Client B (reattach) ---
let mut stream_b = UnixStream::connect(&client_socket).expect("client B should connect");
let (version, error) =
- client_handshake(&mut stream_b, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_b, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(
error.is_none(),
"reattach handshake should succeed: {:?}",
@@ -516,8 +516,8 @@ fn processes_survive_during_and_after_detach() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -555,8 +555,8 @@ fn processes_survive_during_and_after_detach() {
// Reattach — verify we can connect and receive a frame.
let mut stream_b = UnixStream::connect(&client_socket).expect("should reattach");
let (version, error) =
- client_handshake(&mut stream_b, 9, 80, 24).expect("reattach handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_b, 10, 80, 24).expect("reattach handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Verify the reattached client receives a frame.
@@ -604,8 +604,8 @@ fn server_persists_after_client_connection_drop() {
// Connect and handshake.
let mut stream = UnixStream::connect(&client_socket).expect("should connect");
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Drain initial frames.
@@ -631,8 +631,8 @@ fn server_persists_after_client_connection_drop() {
// Reattach — verify we can connect and handshake again.
let mut stream_b = UnixStream::connect(&client_socket).expect("should reattach");
let (version, error) =
- client_handshake(&mut stream_b, 9, 80, 24).expect("reattach handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_b, 10, 80, 24).expect("reattach handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "reattach should succeed: {:?}", error);
cleanup_spawned_herdr(spawned, base);
@@ -653,8 +653,8 @@ fn detached_output_preserves_last_attached_pty_size() {
let mut stream = UnixStream::connect(&client_socket).expect("client should connect");
let (version, error) =
- client_handshake(&mut stream, 9, 120, 40).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream, 10, 120, 40).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
drain_messages(&mut stream);
@@ -722,8 +722,8 @@ fn output_accumulated_while_detached_visible_on_reattach() {
// Connect and handshake client A.
let mut stream_a = UnixStream::connect(&client_socket).expect("client A should connect");
let (version, error) =
- client_handshake(&mut stream_a, 9, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_a, 10, 80, 24).expect("handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Detach client A immediately.
@@ -780,8 +780,8 @@ fn output_accumulated_while_detached_visible_on_reattach() {
// --- Client B (reattach) ---
let mut stream_b = UnixStream::connect(&client_socket).expect("client B should connect");
let (version, error) =
- client_handshake(&mut stream_b, 9, 80, 24).expect("reattach handshake should succeed");
- assert_eq!(version, 9);
+ client_handshake(&mut stream_b, 10, 80, 24).expect("reattach handshake should succeed");
+ assert_eq!(version, 10);
assert!(error.is_none(), "{:?}", error);
// Client B should receive a frame with the current state.
diff --git a/tests/multi_client.rs b/tests/multi_client.rs
index 21a6dddc..cf507c44 100644
--- a/tests/multi_client.rs
+++ b/tests/multi_client.rs
@@ -550,7 +550,7 @@ fn client_handshake(
fn connect_raw_client(client_socket: &Path, cols: u16, rows: u16) -> UnixStream {
let mut stream = UnixStream::connect(client_socket).expect("should connect to client socket");
- client_handshake(&mut stream, 9, cols, rows).expect("handshake should succeed");
+ client_handshake(&mut stream, 10, cols, rows).expect("handshake should succeed");
stream
}
diff --git a/tests/server_headless.rs b/tests/server_headless.rs
index 93531324..a81d8302 100644
--- a/tests/server_headless.rs
+++ b/tests/server_headless.rs
@@ -594,9 +594,9 @@ fn client_handshake_succeeds() {
// Send Hello with the current protocol version, 80 cols, 24 rows.
let (version, error) =
- client_handshake(&mut stream, 9, 80, 24).expect("handshake should succeed");
+ client_handshake(&mut stream, 10, 80, 24).expect("handshake should succeed");
- assert_eq!(version, 9, "server should report protocol version 9");
+ assert_eq!(version, 10, "server should report protocol version 10");
assert!(
error.is_none(),
"handshake should not have an error: {:?}",
@@ -625,7 +625,7 @@ fn client_handshake_rejects_incompatible_version() {
let (version, error) = client_handshake(&mut stream, 0, 80, 24)
.expect("should read Welcome response even on rejection");
- assert_eq!(version, 9, "server should report its version 9");
+ assert_eq!(version, 10, "server should report its version 10");
assert!(
error.is_some(),
"version 0 should be rejected with an error"
@@ -650,10 +650,10 @@ fn client_handshake_clamps_small_terminal_size() {
// Send Hello with 0x0 terminal size — should be clamped.
let mut stream = UnixStream::connect(&client_socket).expect("should connect to client socket");
- let (version, error) = client_handshake(&mut stream, 9, 0, 0)
+ let (version, error) = client_handshake(&mut stream, 10, 0, 0)
.expect("handshake with 0x0 should succeed (server clamps)");
- assert_eq!(version, 9);
+ assert_eq!(version, 10);
assert!(
error.is_none(),
"0x0 size should be accepted (clamped): {:?}",
@@ -713,9 +713,9 @@ fn no_hello_client_closed_within_five_seconds() {
// Verify the server is still healthy — a proper client can still connect.
let mut good_stream =
UnixStream::connect(&client_socket).expect("should connect after no-hello client");
- let (version, error) = client_handshake(&mut good_stream, 9, 80, 24)
+ let (version, error) = client_handshake(&mut good_stream, 10, 80, 24)
.expect("proper handshake should still work after no-hello client");
- assert_eq!(version, 9);
+ assert_eq!(version, 10);
assert!(error.is_none());
// API should still work.