remote_editing_collaboration_tests.rs

  1use crate::tests::TestServer;
  2use call::ActiveCall;
  3use fs::{FakeFs, Fs as _};
  4use gpui::{Context as _, TestAppContext};
  5use language::language_settings::all_language_settings;
  6use remote::SshSession;
  7use remote_server::HeadlessProject;
  8use serde_json::json;
  9use std::{path::Path, sync::Arc};
 10
 11#[gpui::test]
 12async fn test_sharing_an_ssh_remote_project(
 13    cx_a: &mut TestAppContext,
 14    cx_b: &mut TestAppContext,
 15    server_cx: &mut TestAppContext,
 16) {
 17    let executor = cx_a.executor();
 18    let mut server = TestServer::start(executor.clone()).await;
 19    let client_a = server.create_client(cx_a, "user_a").await;
 20    let client_b = server.create_client(cx_b, "user_b").await;
 21    server
 22        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
 23        .await;
 24
 25    // Set up project on remote FS
 26    let (client_ssh, server_ssh) = SshSession::fake(cx_a, server_cx);
 27    let remote_fs = FakeFs::new(server_cx.executor());
 28    remote_fs
 29        .insert_tree(
 30            "/code",
 31            json!({
 32                "project1": {
 33                    ".zed": {
 34                        "settings.json": r#"{"languages":{"Rust":{"language_servers":["override-rust-analyzer"]}}}"#
 35                    },
 36                    "README.md": "# project 1",
 37                    "src": {
 38                        "lib.rs": "fn one() -> usize { 1 }"
 39                    }
 40                },
 41                "project2": {
 42                    "README.md": "# project 2",
 43                },
 44            }),
 45        )
 46        .await;
 47
 48    // User A connects to the remote project via SSH.
 49    server_cx.update(HeadlessProject::init);
 50    let _headless_project =
 51        server_cx.new_model(|cx| HeadlessProject::new(server_ssh, remote_fs.clone(), cx));
 52
 53    let (project_a, worktree_id) = client_a
 54        .build_ssh_project("/code/project1", client_ssh, cx_a)
 55        .await;
 56
 57    // User A shares the remote project.
 58    let active_call_a = cx_a.read(ActiveCall::global);
 59    let project_id = active_call_a
 60        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
 61        .await
 62        .unwrap();
 63
 64    // User B joins the project.
 65    let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
 66    let worktree_b = project_b
 67        .update(cx_b, |project, cx| project.worktree_for_id(worktree_id, cx))
 68        .unwrap();
 69
 70    executor.run_until_parked();
 71    worktree_b.update(cx_b, |worktree, _cx| {
 72        assert_eq!(
 73            worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
 74            vec![
 75                Path::new(".zed"),
 76                Path::new(".zed/settings.json"),
 77                Path::new("README.md"),
 78                Path::new("src"),
 79                Path::new("src/lib.rs"),
 80            ]
 81        );
 82    });
 83
 84    // User B can open buffers in the remote project.
 85    let buffer_b = project_b
 86        .update(cx_b, |project, cx| {
 87            project.open_buffer((worktree_id, "src/lib.rs"), cx)
 88        })
 89        .await
 90        .unwrap();
 91    buffer_b.update(cx_b, |buffer, cx| {
 92        assert_eq!(buffer.text(), "fn one() -> usize { 1 }");
 93        let ix = buffer.text().find('1').unwrap();
 94        buffer.edit([(ix..ix + 1, "100")], None, cx);
 95    });
 96
 97    executor.run_until_parked();
 98
 99    cx_b.read(|cx| {
100        let file = buffer_b.read(cx).file();
101        assert_eq!(
102            all_language_settings(file, cx)
103                .language(Some("Rust"))
104                .language_servers,
105            ["override-rust-analyzer".into()]
106        )
107    });
108
109    project_b
110        .update(cx_b, |project, cx| project.save_buffer(buffer_b, cx))
111        .await
112        .unwrap();
113    assert_eq!(
114        remote_fs
115            .load("/code/project1/src/lib.rs".as_ref())
116            .await
117            .unwrap(),
118        "fn one() -> usize { 100 }"
119    );
120}