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}