aboutsummaryrefslogtreecommitdiff
path: root/src/server/headless/tests
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-02 02:45:20 +0300
committerGitHub <noreply@github.com>2026-09-02 02:45:20 +0300
commitcc88b3b8e5bb9f7d9f23ed6ae85a52fd7b5b9ed6 (patch)
tree4d37c760099070f1a1488b61c7b7271875aafef8 /src/server/headless/tests
parent18e69891dca486d669a584facd80644bb51f54a2 (diff)
feat: add stable client endpoint compatibility (#3509)
* feat: add stable client endpoint compatibility * fix: keep portable-pty patch checks composable * ci: run maintenance checks in pull requests * fix: reject endpoint errors from terminal clients * feat: keep compatible servers running across updates
Diffstat (limited to 'src/server/headless/tests')
-rw-r--r--src/server/headless/tests/mod.rs109
1 files changed, 68 insertions, 41 deletions
diff --git a/src/server/headless/tests/mod.rs b/src/server/headless/tests/mod.rs
index f5c33f6a..93c7420c 100644
--- a/src/server/headless/tests/mod.rs
+++ b/src/server/headless/tests/mod.rs
@@ -3,6 +3,14 @@ use super::*;
#[path = "pane_graphics.rs"]
mod pane_graphics_tests;
+fn client_shell_snapshot(message: ServerMessage) -> Box<crate::protocol::ClientShellSnapshot> {
+ let ServerMessage::EndpointControl { kind, data } = message else {
+ panic!("expected client shell snapshot");
+ };
+ assert_eq!(kind, crate::protocol::endpoint::ENDPOINT_SNAPSHOT_KIND);
+ Box::new(serde_json::from_str(&data).expect("decode client shell snapshot"))
+}
+
fn test_headless_server() -> HeadlessServer {
test_headless_server_with_event_hub(api::EventHub::default())
}
@@ -671,6 +679,33 @@ async fn client_shell_endpoint_request_uses_the_selected_connection() {
shutdown_test_runtimes(&mut server);
}
+#[test]
+fn terminal_client_endpoint_request_error_removes_client() {
+ let mut server = test_headless_server();
+ let (writer, _control_rx, _render_rx) = test_client_writer();
+ let client_id = 42;
+ assert!(!server.handle_server_event(ServerEvent::ClientConnected {
+ client_id,
+ cols: 80,
+ rows: 24,
+ cell_width_px: 0,
+ cell_height_px: 0,
+ pixel_mouse: false,
+ writer,
+ }));
+
+ assert!(
+ server.handle_server_event(ServerEvent::ClientShellEndpointRequestError {
+ client_id,
+ boot_id: "boot".into(),
+ request_id: "request".into(),
+ code: "unsupported_method",
+ message: "unsupported".into(),
+ })
+ );
+ assert!(!server.clients.contains_key(&client_id));
+}
+
#[tokio::test]
async fn client_shell_receives_metadata_then_shell_free_pane_surface() {
let mut server = test_headless_server();
@@ -713,25 +748,23 @@ async fn client_shell_receives_metadata_then_shell_free_pane_surface() {
writer,
})
);
- match read_server_message(control_rx.recv().expect("shell snapshot")) {
- ServerMessage::ClientShellSnapshot(snapshot) => {
- assert_eq!(snapshot.workspaces.len(), 1);
- assert_eq!(snapshot.workspaces[0].label, "shell-only-label");
- assert_eq!(
- snapshot.config_diagnostic.as_deref(),
- Some("endpoint config warning")
- );
- assert_eq!(
- snapshot.product_announcement.as_ref().map(|announcement| (
- announcement.version.as_str(),
- announcement.id.as_str(),
- announcement.preview,
- )),
- Some(("0.8.2", "client-shell", true))
- );
- }
- other => panic!("expected client shell snapshot, got {other:?}"),
- }
+ let snapshot = client_shell_snapshot(read_server_message(
+ control_rx.recv().expect("shell snapshot"),
+ ));
+ assert_eq!(snapshot.workspaces.len(), 1);
+ assert_eq!(snapshot.workspaces[0].label, "shell-only-label");
+ assert_eq!(
+ snapshot.config_diagnostic.as_deref(),
+ Some("endpoint config warning")
+ );
+ assert_eq!(
+ snapshot.product_announcement.as_ref().map(|announcement| (
+ announcement.version.as_str(),
+ announcement.id.as_str(),
+ announcement.preview,
+ )),
+ Some(("0.8.2", "client-shell", true))
+ );
server.render_and_stream();
let initial_surface = match read_server_message(render_rx.recv().expect("pane surface")) {
@@ -1132,11 +1165,9 @@ async fn client_shell_config_diagnostics_follow_keybinding_ownership() {
writer: local_writer,
})
);
- let ServerMessage::ClientShellSnapshot(local_snapshot) =
- read_server_message(local_control.recv().expect("local shell snapshot"))
- else {
- panic!("expected local shell snapshot");
- };
+ let local_snapshot = client_shell_snapshot(read_server_message(
+ local_control.recv().expect("local shell snapshot"),
+ ));
assert_eq!(
local_snapshot.config_diagnostic.as_deref(),
Some("theme warning")
@@ -1157,11 +1188,9 @@ async fn client_shell_config_diagnostics_follow_keybinding_ownership() {
writer: endpoint_writer,
})
);
- let ServerMessage::ClientShellSnapshot(endpoint_snapshot) =
- read_server_message(endpoint_control.recv().expect("endpoint shell snapshot"))
- else {
- panic!("expected endpoint shell snapshot");
- };
+ let endpoint_snapshot = client_shell_snapshot(read_server_message(
+ endpoint_control.recv().expect("endpoint shell snapshot"),
+ ));
assert_eq!(
endpoint_snapshot.config_diagnostic.as_deref(),
Some("server keybinding warning\ntheme warning")
@@ -1199,10 +1228,10 @@ async fn client_shell_replaces_projection_and_focuses_stable_ids() {
writer,
})
);
- let initial_revision = match read_server_message(control_rx.recv().expect("initial snapshot")) {
- ServerMessage::ClientShellSnapshot(snapshot) => snapshot.revision,
- other => panic!("expected initial shell snapshot, got {other:?}"),
- };
+ let initial_revision = client_shell_snapshot(read_server_message(
+ control_rx.recv().expect("initial snapshot"),
+ ))
+ .revision;
let _ = server.app.handle_api_request(crate::api::schema::Request {
id: "test.client.shell.workspace.focus".into(),
@@ -1213,10 +1242,9 @@ async fn client_shell_replaces_projection_and_focuses_stable_ids() {
assert_eq!(server.app.state.active, Some(1));
server.render_and_stream();
- let replacement = match read_server_message(control_rx.recv().expect("replacement snapshot")) {
- ServerMessage::ClientShellSnapshot(snapshot) => snapshot,
- other => panic!("expected replacement shell snapshot, got {other:?}"),
- };
+ let replacement = client_shell_snapshot(read_server_message(
+ control_rx.recv().expect("replacement snapshot"),
+ ));
assert!(replacement.revision > initial_revision);
assert_eq!(
replacement.focused_workspace_id.as_deref(),
@@ -1441,9 +1469,8 @@ async fn client_shell_streams_and_targets_popup_terminal_content() {
writer,
})
);
- assert!(matches!(
- read_server_message(control_rx.recv().expect("shell snapshot")),
- ServerMessage::ClientShellSnapshot(_)
+ let _snapshot = client_shell_snapshot(read_server_message(
+ control_rx.recv().expect("shell snapshot"),
));
server.render_and_stream();
@@ -4553,7 +4580,7 @@ fn update_notification_is_semantic_for_system_delivery() {
assert_eq!(notification.title, "Herdr v9.9.9 available");
assert_eq!(
notification.body.as_deref(),
- Some("detach, run `herdr update`, then follow its restart guidance")
+ Some("detach, run `herdr update`, then run Herdr again to reconnect")
);
}
other => panic!("expected semantic update notification, got {other:?}"),