
This restructures the code in `remote` so that it's easier to replace the current SSH connection with a new one in case of disconnects/reconnects. Right now, it successfully reconnects, BUT we're still missing the big piece on the server-side: keeping the server process alive and reconnecting to the same process that keeps the project-state. Release Notes: - N/A --------- Co-authored-by: Bennet <bennet@zed.dev>
161 lines
4.9 KiB
Rust
161 lines
4.9 KiB
Rust
use crate::tests::TestServer;
|
|
use call::ActiveCall;
|
|
use fs::{FakeFs, Fs as _};
|
|
use gpui::{Context as _, TestAppContext};
|
|
use language::language_settings::all_language_settings;
|
|
use project::ProjectPath;
|
|
use remote::SshRemoteClient;
|
|
use remote_server::HeadlessProject;
|
|
use serde_json::json;
|
|
use std::{path::Path, sync::Arc};
|
|
|
|
#[gpui::test(iterations = 10)]
|
|
async fn test_sharing_an_ssh_remote_project(
|
|
cx_a: &mut TestAppContext,
|
|
cx_b: &mut TestAppContext,
|
|
server_cx: &mut TestAppContext,
|
|
) {
|
|
let executor = cx_a.executor();
|
|
let mut server = TestServer::start(executor.clone()).await;
|
|
let client_a = server.create_client(cx_a, "user_a").await;
|
|
let client_b = server.create_client(cx_b, "user_b").await;
|
|
server
|
|
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
|
|
.await;
|
|
|
|
// Set up project on remote FS
|
|
let (client_ssh, server_ssh) = SshRemoteClient::fake(cx_a, server_cx);
|
|
let remote_fs = FakeFs::new(server_cx.executor());
|
|
remote_fs
|
|
.insert_tree(
|
|
"/code",
|
|
json!({
|
|
"project1": {
|
|
".zed": {
|
|
"settings.json": r#"{"languages":{"Rust":{"language_servers":["override-rust-analyzer"]}}}"#
|
|
},
|
|
"README.md": "# project 1",
|
|
"src": {
|
|
"lib.rs": "fn one() -> usize { 1 }"
|
|
}
|
|
},
|
|
"project2": {
|
|
"README.md": "# project 2",
|
|
},
|
|
}),
|
|
)
|
|
.await;
|
|
|
|
// User A connects to the remote project via SSH.
|
|
server_cx.update(HeadlessProject::init);
|
|
let _headless_project =
|
|
server_cx.new_model(|cx| HeadlessProject::new(server_ssh, remote_fs.clone(), cx));
|
|
|
|
let (project_a, worktree_id) = client_a
|
|
.build_ssh_project("/code/project1", client_ssh, cx_a)
|
|
.await;
|
|
|
|
// While the SSH worktree is being scanned, user A shares the remote project.
|
|
let active_call_a = cx_a.read(ActiveCall::global);
|
|
let project_id = active_call_a
|
|
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
|
.await
|
|
.unwrap();
|
|
|
|
// User B joins the project.
|
|
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
|
let worktree_b = project_b
|
|
.update(cx_b, |project, cx| project.worktree_for_id(worktree_id, cx))
|
|
.unwrap();
|
|
|
|
let worktree_a = project_a
|
|
.update(cx_a, |project, cx| project.worktree_for_id(worktree_id, cx))
|
|
.unwrap();
|
|
|
|
executor.run_until_parked();
|
|
|
|
worktree_a.update(cx_a, |worktree, _cx| {
|
|
assert_eq!(
|
|
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
|
|
vec![
|
|
Path::new(".zed"),
|
|
Path::new(".zed/settings.json"),
|
|
Path::new("README.md"),
|
|
Path::new("src"),
|
|
Path::new("src/lib.rs"),
|
|
]
|
|
);
|
|
});
|
|
|
|
worktree_b.update(cx_b, |worktree, _cx| {
|
|
assert_eq!(
|
|
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
|
|
vec![
|
|
Path::new(".zed"),
|
|
Path::new(".zed/settings.json"),
|
|
Path::new("README.md"),
|
|
Path::new("src"),
|
|
Path::new("src/lib.rs"),
|
|
]
|
|
);
|
|
});
|
|
|
|
// User B can open buffers in the remote project.
|
|
let buffer_b = project_b
|
|
.update(cx_b, |project, cx| {
|
|
project.open_buffer((worktree_id, "src/lib.rs"), cx)
|
|
})
|
|
.await
|
|
.unwrap();
|
|
buffer_b.update(cx_b, |buffer, cx| {
|
|
assert_eq!(buffer.text(), "fn one() -> usize { 1 }");
|
|
let ix = buffer.text().find('1').unwrap();
|
|
buffer.edit([(ix..ix + 1, "100")], None, cx);
|
|
});
|
|
|
|
executor.run_until_parked();
|
|
|
|
cx_b.read(|cx| {
|
|
let file = buffer_b.read(cx).file();
|
|
assert_eq!(
|
|
all_language_settings(file, cx)
|
|
.language(Some(&("Rust".into())))
|
|
.language_servers,
|
|
["override-rust-analyzer".to_string()]
|
|
)
|
|
});
|
|
|
|
project_b
|
|
.update(cx_b, |project, cx| {
|
|
project.save_buffer_as(
|
|
buffer_b.clone(),
|
|
ProjectPath {
|
|
worktree_id: worktree_id.to_owned(),
|
|
path: Arc::from(Path::new("src/renamed.rs")),
|
|
},
|
|
cx,
|
|
)
|
|
})
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(
|
|
remote_fs
|
|
.load("/code/project1/src/renamed.rs".as_ref())
|
|
.await
|
|
.unwrap(),
|
|
"fn one() -> usize { 100 }"
|
|
);
|
|
cx_b.run_until_parked();
|
|
cx_b.update(|cx| {
|
|
assert_eq!(
|
|
buffer_b
|
|
.read(cx)
|
|
.file()
|
|
.unwrap()
|
|
.path()
|
|
.to_string_lossy()
|
|
.to_string(),
|
|
"src/renamed.rs".to_string()
|
|
);
|
|
});
|
|
}
|