remote_editing_tests.rs

  1use crate::headless_project::HeadlessProject;
  2use client::{Client, UserStore};
  3use clock::FakeSystemClock;
  4use fs::{FakeFs, Fs as _};
  5use gpui::{Context, Model, TestAppContext};
  6use http::FakeHttpClient;
  7use language::LanguageRegistry;
  8use node_runtime::FakeNodeRuntime;
  9use project::Project;
 10use remote::SshSession;
 11use serde_json::json;
 12use settings::SettingsStore;
 13use std::{path::Path, sync::Arc};
 14
 15#[gpui::test]
 16async fn test_remote_editing(cx: &mut TestAppContext, server_cx: &mut TestAppContext) {
 17    let (client_ssh, server_ssh) = SshSession::fake(cx, server_cx);
 18
 19    let fs = FakeFs::new(server_cx.executor());
 20    fs.insert_tree(
 21        "/code",
 22        json!({
 23            "project1": {
 24                "README.md": "# project 1",
 25                "src": {
 26                    "lib.rs": "fn one() -> usize { 1 }"
 27                }
 28            },
 29            "project2": {
 30                "README.md": "# project 2",
 31            },
 32        }),
 33    )
 34    .await;
 35
 36    server_cx.update(HeadlessProject::init);
 37    let _headless_project =
 38        server_cx.new_model(|cx| HeadlessProject::new(server_ssh, fs.clone(), cx));
 39
 40    let project = build_project(client_ssh, cx);
 41    let (worktree, _) = project
 42        .update(cx, |project, cx| {
 43            project.find_or_create_worktree("/code/project1", true, cx)
 44        })
 45        .await
 46        .unwrap();
 47
 48    // The client sees the worktree's contents.
 49    cx.executor().run_until_parked();
 50    let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
 51    worktree.update(cx, |worktree, _cx| {
 52        assert_eq!(
 53            worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
 54            vec![
 55                Path::new("README.md"),
 56                Path::new("src"),
 57                Path::new("src/lib.rs"),
 58            ]
 59        );
 60    });
 61
 62    // The user opens a buffer in the remote worktree. The buffer's
 63    // contents are loaded from the remote filesystem.
 64    let buffer = project
 65        .update(cx, |project, cx| {
 66            project.open_buffer((worktree_id, Path::new("src/lib.rs")), cx)
 67        })
 68        .await
 69        .unwrap();
 70    buffer.update(cx, |buffer, cx| {
 71        assert_eq!(buffer.text(), "fn one() -> usize { 1 }");
 72        let ix = buffer.text().find('1').unwrap();
 73        buffer.edit([(ix..ix + 1, "100")], None, cx);
 74    });
 75
 76    // The user saves the buffer. The new contents are written to the
 77    // remote filesystem.
 78    project
 79        .update(cx, |project, cx| project.save_buffer(buffer, cx))
 80        .await
 81        .unwrap();
 82    assert_eq!(
 83        fs.load("/code/project1/src/lib.rs".as_ref()).await.unwrap(),
 84        "fn one() -> usize { 100 }"
 85    );
 86
 87    // A new file is created in the remote filesystem. The user
 88    // sees the new file.
 89    fs.save(
 90        "/code/project1/src/main.rs".as_ref(),
 91        &"fn main() {}".into(),
 92        Default::default(),
 93    )
 94    .await
 95    .unwrap();
 96    cx.executor().run_until_parked();
 97    worktree.update(cx, |worktree, _cx| {
 98        assert_eq!(
 99            worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
100            vec![
101                Path::new("README.md"),
102                Path::new("src"),
103                Path::new("src/lib.rs"),
104                Path::new("src/main.rs"),
105            ]
106        );
107    });
108}
109
110fn build_project(ssh: Arc<SshSession>, cx: &mut TestAppContext) -> Model<Project> {
111    cx.update(|cx| {
112        let settings_store = SettingsStore::test(cx);
113        cx.set_global(settings_store);
114    });
115
116    let client = cx.update(|cx| {
117        Client::new(
118            Arc::new(FakeSystemClock::default()),
119            FakeHttpClient::with_404_response(),
120            cx,
121        )
122    });
123
124    let node = FakeNodeRuntime::new();
125    let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx));
126    let languages = Arc::new(LanguageRegistry::test(cx.executor()));
127    let fs = FakeFs::new(cx.executor());
128    cx.update(|cx| {
129        Project::init(&client, cx);
130        language::init(cx);
131    });
132
133    cx.update(|cx| Project::ssh(ssh, client, node, user_store, languages, fs, cx))
134}