Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/src/terminal/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10289,6 +10289,13 @@ impl TerminalView {
// start nor close the pane.
let remote_restore_cancelled =
self.remote_input_phase == Some(RemoteInputPhase::Cancelled);
// A daemon-backed pane that ends before its shell bootstrapped
// lost its connection, not its shell start: the remote readiness
// notice already explains the failure and offers Retry, so the
// local shell-start banner (which blames the bootstrap script)
// would be wrong and redundant.
let daemon_startup_failure =
self.remote_input_session_id.is_some() && !self.is_login_shell_bootstrapped;
if self.remote_input_phase.is_some() {
self.set_remote_input_phase(
RemoteInputPhase::Failed,
Expand All @@ -10301,7 +10308,7 @@ impl TerminalView {
}

// If the pty spawn has failed, we've already inserted a banner.
if !self.pty_spawn_failed && !remote_restore_cancelled {
if !self.pty_spawn_failed && !remote_restore_cancelled && !daemon_startup_failure {
let shell_detail = self.shell_detail.take().unwrap_or("shell".to_owned());
self.insert_shell_process_terminated_banner(
shell_terminated_banner::TerminationType::Premature {
Expand Down
46 changes: 46 additions & 0 deletions app/src/terminal/view_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,52 @@ fn cancelled_remote_restore_teardown_shows_no_shell_failure_banner() {
});
}

/// A daemon-backed pane whose connection fails before the remote shell
/// bootstrapped exits its terminal model. The remote failure notice (with
/// Retry) must stay the only explanation; no shell-start failure banner may be
/// added that blames the bootstrap script for a network problem.
#[test]
fn daemon_connect_failure_before_bootstrap_shows_no_shell_start_banner() {
App::test((), |mut app| async move {
initialize_app_for_terminal_view(&mut app);
let session = warp_core::SessionId::from(943u64);
let terminal = add_window_with_terminal(&mut app, None);
terminal.update(&mut app, |view, ctx| {
view.is_login_shell_bootstrapped = false;
view.set_remote_input_phase(RemoteInputPhase::Transport, Some(session), ctx);
view.show_remote_session_error(
"ssh: connect to host 192.0.2.10 port 22: Network is unreachable".to_string(),
Some(session),
ctx,
);
view.set_remote_input_phase(RemoteInputPhase::Failed, Some(session), ctx);
});
let rich_content_before = terminal.read(&app, |view, _| view.rich_content_views.len());

terminal.update(&mut app, |view, ctx| {
view.handle_terminal_event(
&ModelEvent::Exit {
reason: crate::terminal::model::terminal_model::ExitReason::PtyDisconnected,
},
ctx,
);
});

terminal.read(&app, |view, _| {
assert_eq!(view.rich_content_views.len(), rich_content_before);
assert!(view
.inline_banners_state
.shell_process_terminated_banner
.is_none());
assert_eq!(view.remote_input_phase, Some(RemoteInputPhase::Failed));
assert_eq!(
view.remote_session_error.as_deref(),
Some("ssh: connect to host 192.0.2.10 port 22: Network is unreachable")
);
});
});
}

#[test]
fn remote_notice_tone_separates_failures_from_ended_sessions() {
assert_eq!(
Expand Down
Loading