remote_editing_collaboration_tests.rs

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