Start work on an integration test for following

This commit is contained in:
Max Brunsfeld 2022-03-17 13:53:06 -07:00
parent 845457e2c4
commit 5702737de2
2 changed files with 177 additions and 7 deletions

View file

@ -112,6 +112,7 @@ impl Server {
.add_request_handler(Server::join_channel)
.add_message_handler(Server::leave_channel)
.add_request_handler(Server::send_channel_message)
.add_request_handler(Server::follow)
.add_request_handler(Server::get_channel_messages);
Arc::new(server)
@ -669,6 +670,25 @@ impl Server {
Ok(())
}
async fn follow(
self: Arc<Self>,
request: TypedEnvelope<proto::Follow>,
) -> tide::Result<proto::FollowResponse> {
let leader_id = ConnectionId(request.payload.leader_id);
if !self
.state()
.project_connection_ids(request.payload.project_id, request.sender_id)?
.contains(&leader_id)
{
Err(anyhow!("no such peer"))?;
}
let response = self
.peer
.forward_request(request.sender_id, leader_id, request.payload)
.await?;
Ok(response)
}
async fn get_channels(
self: Arc<Server>,
request: TypedEnvelope<proto::GetChannels>,
@ -1016,7 +1036,7 @@ mod tests {
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Input, Redo, Rename,
ToOffset, ToggleCodeActions, Undo,
};
use gpui::{executor, ModelHandle, TestAppContext};
use gpui::{executor, ModelHandle, TestAppContext, ViewHandle};
use language::{
tree_sitter_rust, Diagnostic, DiagnosticEntry, Language, LanguageConfig, LanguageRegistry,
LanguageServerConfig, OffsetRangeExt, Point, ToLspPosition,
@ -1028,7 +1048,7 @@ mod tests {
fs::{FakeFs, Fs as _},
search::SearchQuery,
worktree::WorktreeHandle,
DiagnosticSummary, Project, ProjectPath,
DiagnosticSummary, Project, ProjectPath, WorktreeId,
};
use rand::prelude::*;
use rpc::PeerId;
@ -1046,7 +1066,7 @@ mod tests {
},
time::Duration,
};
use workspace::{Settings, Workspace, WorkspaceParams};
use workspace::{Settings, SplitDirection, Workspace, WorkspaceParams};
#[cfg(test)]
#[ctor::ctor]
@ -3225,7 +3245,7 @@ mod tests {
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(&params, cx));
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "main.rs").into(), cx)
workspace.open_path((worktree_id, "main.rs"), cx)
})
.await
.unwrap()
@ -3459,7 +3479,7 @@ mod tests {
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(&params, cx));
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "one.rs").into(), cx)
workspace.open_path((worktree_id, "one.rs"), cx)
})
.await
.unwrap()
@ -4148,6 +4168,80 @@ mod tests {
}
}
#[gpui::test(iterations = 10)]
async fn test_following(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
cx_a.foreground().forbid_parking();
let fs = FakeFs::new(cx_a.background());
// 2 clients connect to a server.
let mut server = TestServer::start(cx_a.foreground(), cx_a.background()).await;
let mut client_a = server.create_client(cx_a, "user_a").await;
let mut client_b = server.create_client(cx_b, "user_b").await;
cx_a.update(editor::init);
cx_b.update(editor::init);
// Client A shares a project.
fs.insert_tree(
"/a",
json!({
".zed.toml": r#"collaborators = ["user_b"]"#,
"1.txt": "one",
"2.txt": "two",
"3.txt": "three",
}),
)
.await;
let (project_a, worktree_id) = client_a.build_local_project(fs.clone(), "/a", cx_a).await;
project_a
.update(cx_a, |project, cx| project.share(cx))
.await
.unwrap();
// Client B joins the project.
let project_b = client_b
.build_remote_project(
project_a
.read_with(cx_a, |project, _| project.remote_id())
.unwrap(),
cx_b,
)
.await;
// Client A opens some editors.
let workspace_a = client_a.build_workspace(&project_a, cx_a);
let editor_a1 = workspace_a
.update(cx_a, |workspace, cx| {
workspace.open_path((worktree_id, "1.txt"), cx)
})
.await
.unwrap();
let editor_a2 = workspace_a
.update(cx_a, |workspace, cx| {
workspace.open_path((worktree_id, "2.txt"), cx)
})
.await
.unwrap();
// Client B opens an editor.
let workspace_b = client_b.build_workspace(&project_b, cx_b);
let editor_b1 = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "1.txt"), cx)
})
.await
.unwrap();
// Client B starts following client A.
workspace_b
.update(cx_b, |workspace, cx| {
workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
let leader_id = project_b.read(cx).collaborators().keys().next().unwrap();
workspace.follow(*leader_id, cx)
})
.await
.unwrap();
}
#[gpui::test(iterations = 100)]
async fn test_random_collaboration(cx: &mut TestAppContext, rng: StdRng) {
cx.foreground().forbid_parking();
@ -4477,6 +4571,7 @@ mod tests {
client,
peer_id,
user_store,
language_registry: Arc::new(LanguageRegistry::test()),
project: Default::default(),
buffers: Default::default(),
};
@ -4541,6 +4636,7 @@ mod tests {
client: Arc<Client>,
pub peer_id: PeerId,
pub user_store: ModelHandle<UserStore>,
language_registry: Arc<LanguageRegistry>,
project: Option<ModelHandle<Project>>,
buffers: HashSet<ModelHandle<language::Buffer>>,
}
@ -4568,6 +4664,80 @@ mod tests {
while authed_user.next().await.unwrap().is_none() {}
}
async fn build_local_project(
&mut self,
fs: Arc<FakeFs>,
root_path: impl AsRef<Path>,
cx: &mut TestAppContext,
) -> (ModelHandle<Project>, WorktreeId) {
let project = cx.update(|cx| {
Project::local(
self.client.clone(),
self.user_store.clone(),
self.language_registry.clone(),
fs,
cx,
)
});
self.project = Some(project.clone());
let (worktree, _) = project
.update(cx, |p, cx| {
p.find_or_create_local_worktree(root_path, true, cx)
})
.await
.unwrap();
worktree
.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
.await;
project
.update(cx, |project, _| project.next_remote_id())
.await;
(project, worktree.read_with(cx, |tree, _| tree.id()))
}
async fn build_remote_project(
&mut self,
project_id: u64,
cx: &mut TestAppContext,
) -> ModelHandle<Project> {
let project = Project::remote(
project_id,
self.client.clone(),
self.user_store.clone(),
self.language_registry.clone(),
FakeFs::new(cx.background()),
&mut cx.to_async(),
)
.await
.unwrap();
self.project = Some(project.clone());
project
}
fn build_workspace(
&self,
project: &ModelHandle<Project>,
cx: &mut TestAppContext,
) -> ViewHandle<Workspace> {
let (window_id, _) = cx.add_window(|cx| EmptyView);
cx.add_view(window_id, |cx| {
let fs = project.read(cx).fs().clone();
Workspace::new(
&WorkspaceParams {
fs,
project: project.clone(),
user_store: self.user_store.clone(),
languages: self.language_registry.clone(),
channel_list: cx.add_model(|cx| {
ChannelList::new(self.user_store.clone(), self.client.clone(), cx)
}),
client: self.client.clone(),
},
cx,
)
})
}
fn simulate_host(
mut self,
project: ModelHandle<Project>,