first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
File diff suppressed because it is too large Load Diff
@@ -3,32 +3,32 @@ use std::sync::Arc;
use async_channel::Sender;
use futures_util::stream::AbortHandle;
use instant::Instant;
use galaxyui::{App, ModelHandle};
use parking_lot::FairMutex;
use session_sharing_protocol::{
common::{
ActivePrompt, OrderedTerminalEvent, OrderedTerminalEventType, ParticipantId, Selection,
SessionId,
},
sharer::{DownstreamMessage, ReconnectToken, UpstreamMessage},
use session_sharing_protocol::common::{
ActivePrompt, OrderedTerminalEvent, OrderedTerminalEventType, ParticipantId, Selection,
SessionId,
};
use session_sharing_protocol::sharer::{
DownstreamMessage, FailedToInitializeSessionReason, QuotaType, ReconnectToken, UpstreamMessage,
};
use galaxy_server_client::iap::IapManager;
use galaxyui::{App, ModelHandle};
use websocket::{Message, WebsocketMessage as _};
use crate::{
auth::{auth_manager::AuthManager, AuthStateProvider},
editor::ReplicaId,
server::{
server_api::ServerApiProvider, telemetry::context_provider::AppTelemetryContextProvider,
},
terminal::{
shared_session::{SharedSessionScrollbackType, MAX_BYTES_SHAREABLE},
TerminalModel,
},
test_util::assert_eventually,
use super::{
startup_max_attempts, Network, PtyBytesBatchStatus, Stage, StartupFailure, StartupRetryState,
AMBIENT_CREATE_SESSION_MAX_ATTEMPTS,
};
use super::{Network, PtyBytesBatchStatus, Stage};
use crate::auth::auth_manager::AuthManager;
use crate::auth::AuthStateProvider;
use crate::editor::ReplicaId;
use crate::server::server_api::ServerApiProvider;
use crate::server::telemetry::context_provider::AppTelemetryContextProvider;
use crate::terminal::shared_session::{
SharedSessionScrollbackType, SharedSessionSource, MAX_BYTES_SHAREABLE,
};
use crate::terminal::TerminalModel;
use crate::test_util::assert_eventually;
fn is_upstream_message_pty_bytes_read(
message: UpstreamMessage,
@@ -42,6 +42,117 @@ fn is_upstream_message_pty_bytes_read(
}) if event_no == expected_event_no && bytes == compressed_bytes)
}
#[test]
fn test_startup_max_attempts_only_retries_ambient_agent_sources() {
assert_eq!(
startup_max_attempts(&SharedSessionSource::ambient_agent(Some(
"task-id".to_string()
))),
AMBIENT_CREATE_SESSION_MAX_ATTEMPTS
);
assert_eq!(startup_max_attempts(&SharedSessionSource::user(None)), 1);
}
#[test]
fn test_startup_failure_retryability() {
assert!(StartupFailure::Transport.is_retryable());
assert!(StartupFailure::InitializeSend.is_retryable());
assert!(StartupFailure::WebsocketClosedBeforeStarted.is_retryable());
assert!(StartupFailure::WebsocketError.is_retryable());
assert!(StartupFailure::Timeout.is_retryable());
assert!(
StartupFailure::ServerRejected(FailedToInitializeSessionReason::InternalServerError {
details: "transient".to_string(),
})
.is_retryable()
);
assert!(!StartupFailure::ServerRejected(
FailedToInitializeSessionReason::ScrollbackTooLarge {}
)
.is_retryable());
assert!(!StartupFailure::ServerRejected(
FailedToInitializeSessionReason::NoUserQuotaRemaining {
quota_type: QuotaType::SessionsCreated,
}
)
.is_retryable());
assert!(
!StartupFailure::ServerRejected(FailedToInitializeSessionReason::UserNotFound)
.is_retryable()
);
}
#[test]
fn test_should_retry_startup_failure_respects_attempt_budget() {
App::test((), |mut app| async move {
let network = create_network(&mut app, false).0;
network.update(&mut app, |network, _| {
network.stage = Stage::BeforeStarted {
startup_retry: StartupRetryState {
current_attempt: 1,
max_attempts: AMBIENT_CREATE_SESSION_MAX_ATTEMPTS,
timeout_abort_handle: None,
transport_abort_handle: None,
},
};
assert!(network.should_retry_startup_failure(&StartupFailure::Timeout));
network.stage = Stage::BeforeStarted {
startup_retry: StartupRetryState {
current_attempt: AMBIENT_CREATE_SESSION_MAX_ATTEMPTS,
max_attempts: AMBIENT_CREATE_SESSION_MAX_ATTEMPTS,
timeout_abort_handle: None,
transport_abort_handle: None,
},
};
assert!(!network.should_retry_startup_failure(&StartupFailure::Timeout));
let mut startup_retry = StartupRetryState::new(1);
startup_retry.current_attempt = 1;
network.stage = Stage::BeforeStarted { startup_retry };
assert!(
!network.should_retry_startup_failure(&StartupFailure::ServerRejected(
FailedToInitializeSessionReason::InternalServerError {
details: "transient".to_string(),
}
))
);
});
});
}
#[test]
fn test_startup_attempt_stale_filtering() {
App::test((), |mut app| async move {
let network = create_network(&mut app, false).0;
network.update(&mut app, |network, _| {
network.stage = Stage::BeforeStarted {
startup_retry: StartupRetryState {
current_attempt: 1,
max_attempts: AMBIENT_CREATE_SESSION_MAX_ATTEMPTS,
timeout_abort_handle: None,
transport_abort_handle: None,
},
};
assert!(!network.should_ignore_startup_attempt_websocket_callback(1));
assert!(network.should_ignore_startup_attempt_websocket_callback(0));
network.stage = Stage::StartedSuccessfully {
startup_attempt: Some(1),
};
assert!(!network.should_ignore_startup_attempt_websocket_callback(1));
assert!(network.should_ignore_startup_attempt_websocket_callback(0));
network.stage = Stage::StartedSuccessfully {
startup_attempt: None,
};
assert!(!network.should_ignore_startup_attempt_websocket_callback(0));
});
});
}
fn is_upstream_message_command_executed(
message: &UpstreamMessage,
expected_event_no: usize,
@@ -75,7 +186,9 @@ fn create_network(
if session_initialized {
network.update(app, |network, _| {
network.stage = Stage::StartedSuccessfully;
network.stage = Stage::StartedSuccessfully {
startup_attempt: None,
};
});
}
@@ -473,7 +586,7 @@ fn test_messages_are_buffered_before_session_initialized() {
// The network should start in the BeforeStarted state with no events.
assert_eq!(ws_proxy_rx.len(), 0);
network.read(&app, |network, _| {
assert!(matches!(&network.stage, Stage::BeforeStarted));
assert!(matches!(&network.stage, Stage::BeforeStarted { .. }));
assert_eq!(network.unacked_terminal_events.len(), 0);
});
@@ -494,7 +607,7 @@ fn test_messages_are_buffered_before_session_initialized() {
// The message should not be sent to the server but should instead be buffered.
assert_eq!(ws_proxy_rx.len(), 0);
network.read(&app, |network, _| {
assert!(matches!(&network.stage, Stage::BeforeStarted));
assert!(matches!(&network.stage, Stage::BeforeStarted { .. }));
assert!(is_upstream_message_command_executed(
&UpstreamMessage::OrderedTerminalEvent(
network.unacked_terminal_events.get(&0).unwrap().clone()
@@ -525,7 +638,7 @@ fn test_messages_are_buffered_before_session_initialized() {
matches!(item.unwrap(), UpstreamMessage::UpdateActivePrompt(_));
network.read(&app, |network, _| {
assert!(matches!(&network.stage, Stage::StartedSuccessfully));
assert!(matches!(&network.stage, Stage::StartedSuccessfully { .. }));
});
});
}
@@ -534,6 +647,15 @@ fn test_messages_are_buffered_before_session_initialized() {
fn test_messages_are_buffered_while_reconnecting() {
App::test((), |mut app| async move {
app.add_singleton_model(|_| ServerApiProvider::new_for_test());
// Disabled (`None`) IapManager so the reconnect path, which reads the
// singleton, doesn't panic; inert no-op in tests.
app.add_singleton_model(|ctx| {
IapManager::new(
None,
Box::new(|_| futures::FutureExt::boxed(futures::future::ready(None::<String>))),
ctx,
)
});
app.add_singleton_model(|_| AuthStateProvider::new_for_test());
app.add_singleton_model(AppTelemetryContextProvider::new_context_provider);
app.add_singleton_model(AuthManager::new_for_test);
@@ -543,7 +665,7 @@ fn test_messages_are_buffered_while_reconnecting() {
// The network should start in the BeforeStarted state with no events.
assert_eq!(ws_proxy_rx.len(), 0);
network.read(&app, |network, _| {
assert!(matches!(&network.stage, Stage::BeforeStarted));
assert!(matches!(&network.stage, Stage::BeforeStarted { .. }));
assert_eq!(network.unacked_terminal_events.len(), 0);
});
@@ -620,7 +742,7 @@ fn test_messages_are_buffered_while_reconnecting() {
matches!(item.unwrap(), UpstreamMessage::UpdateActivePrompt(_));
network.read(&app, |network, _| {
assert!(matches!(&network.stage, Stage::StartedSuccessfully));
assert!(matches!(&network.stage, Stage::StartedSuccessfully { .. }));
});
});
}