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    executor.run_until_parked();
 57
 58    // User A shares the remote project.
 59    let active_call_a = cx_a.read(ActiveCall::global);
 60    let project_id = active_call_a
 61        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
 62        .await
 63        .unwrap();
 64
 65    // User B joins the project.
 66    let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
 67    let worktree_b = project_b
 68        .update(cx_b, |project, cx| project.worktree_for_id(worktree_id, cx))
 69        .unwrap();
 70
 71    executor.run_until_parked();
 72    worktree_b.update(cx_b, |worktree, _cx| {
 73        assert_eq!(
 74            worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
 75            vec![
 76                Path::new(".zed"),
 77                Path::new(".zed/settings.json"),
 78                Path::new("README.md"),
 79                Path::new("src"),
 80                Path::new("src/lib.rs"),
 81            ]
 82        );
 83    });
 84
 85    // User B can open buffers in the remote project.
 86    let buffer_b = project_b
 87        .update(cx_b, |project, cx| {
 88            project.open_buffer((worktree_id, "src/lib.rs"), cx)
 89        })
 90        .await
 91        .unwrap();
 92    buffer_b.update(cx_b, |buffer, cx| {
 93        assert_eq!(buffer.text(), "fn one() -> usize { 1 }");
 94        let ix = buffer.text().find('1').unwrap();
 95        buffer.edit([(ix..ix + 1, "100")], None, cx);
 96    });
 97
 98    executor.run_until_parked();
 99
100    cx_b.read(|cx| {
101        let file = buffer_b.read(cx).file();
102        assert_eq!(
103            all_language_settings(file, cx)
104                .language(Some(&("Rust".into())))
105                .language_servers,
106            ["override-rust-analyzer".to_string()]
107        )
108    });
109
110    project_b
111        .update(cx_b, |project, cx| project.save_buffer(buffer_b, cx))
112        .await
113        .unwrap();
114    assert_eq!(
115        remote_fs
116            .load("/code/project1/src/lib.rs".as_ref())
117            .await
118            .unwrap(),
119        "fn one() -> usize { 100 }"
120    );
121}