diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-02 02:45:20 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-02 02:45:20 +0300 |
| commit | cc88b3b8e5bb9f7d9f23ed6ae85a52fd7b5b9ed6 (patch) | |
| tree | 4d37c760099070f1a1488b61c7b7271875aafef8 /src/server/headless/tests | |
| parent | 18e69891dca486d669a584facd80644bb51f54a2 (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.rs | 109 |
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:?}"), |
