diff --git a/crates/collab/tests/integration/git_tests.rs b/crates/collab/tests/integration/git_tests.rs index 6792eb92484d34f3085287b57f48a5761e760c92..6e50e41bade5f5dfdf124f5a6d659e81fc2ce0f6 100644 --- a/crates/collab/tests/integration/git_tests.rs +++ b/crates/collab/tests/integration/git_tests.rs @@ -9,7 +9,6 @@ use serde_json::json; use util::{path, rel_path::rel_path}; use workspace::{MultiWorkspace, Workspace}; -// use crate::TestServer; #[gpui::test] diff --git a/crates/collab/tests/integration/integration_tests.rs b/crates/collab/tests/integration/integration_tests.rs index c26f20c1e294326f275dbfda1d2d41603719cd3e..3bad9c82c26392a935f67efc578b5d293b2cab3d 100644 --- a/crates/collab/tests/integration/integration_tests.rs +++ b/crates/collab/tests/integration/integration_tests.rs @@ -7205,3 +7205,89 @@ async fn test_remote_git_branches( assert_eq!(host_branch.name(), "totally-new-branch"); } + +#[gpui::test] +async fn test_guest_can_rejoin_shared_project_after_leaving_call( + executor: BackgroundExecutor, + cx_a: &mut TestAppContext, + cx_b: &mut TestAppContext, + cx_c: &mut TestAppContext, +) { + let mut server = TestServer::start(executor.clone()).await; + let client_a = server.create_client(cx_a, "user_a").await; + let client_b = server.create_client(cx_b, "user_b").await; + let client_c = server.create_client(cx_c, "user_c").await; + + server + .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)]) + .await; + + client_a + .fs() + .insert_tree( + path!("/project"), + json!({ + "file.txt": "hello\n", + }), + ) + .await; + + let (project_a, _worktree_id) = client_a.build_local_project(path!("/project"), cx_a).await; + let active_call_a = cx_a.read(ActiveCall::global); + let project_id = active_call_a + .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx)) + .await + .unwrap(); + + let _project_b = client_b.join_remote_project(project_id, cx_b).await; + executor.run_until_parked(); + + // third client joins call to prevent room from being torn down + let _project_c = client_c.join_remote_project(project_id, cx_c).await; + executor.run_until_parked(); + + let active_call_b = cx_b.read(ActiveCall::global); + active_call_b + .update(cx_b, |call, cx| call.hang_up(cx)) + .await + .unwrap(); + executor.run_until_parked(); + + let user_id_b = client_b.current_user_id(cx_b).to_proto(); + let active_call_a = cx_a.read(ActiveCall::global); + active_call_a + .update(cx_a, |call, cx| call.invite(user_id_b, None, cx)) + .await + .unwrap(); + executor.run_until_parked(); + let active_call_b = cx_b.read(ActiveCall::global); + active_call_b + .update(cx_b, |call, cx| call.accept_incoming(cx)) + .await + .unwrap(); + executor.run_until_parked(); + + let _project_b2 = client_b.join_remote_project(project_id, cx_b).await; + executor.run_until_parked(); + + project_a.read_with(cx_a, |project, _| { + let guest_count = project + .collaborators() + .values() + .filter(|c| !c.is_host) + .count(); + + assert_eq!( + guest_count, 2, + "host should have exactly one guest collaborator after rejoin" + ); + }); + + _project_b.read_with(cx_b, |project, _| { + assert_eq!( + project.client_subscriptions().len(), + 0, + "We should clear all host subscriptions after leaving the project" + ); + }) +} diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 9e37802213dfb8df5cf63af5648044ae8ec65ecb..756f095511a9688678df013458710e69d720c52e 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1942,6 +1942,11 @@ impl Project { } } + #[cfg(feature = "test-support")] + pub fn client_subscriptions(&self) -> &Vec { + &self.client_subscriptions + } + #[cfg(feature = "test-support")] pub async fn example( root_paths: impl IntoIterator, @@ -2741,6 +2746,7 @@ impl Project { } = &mut self.client_state { *sharing_has_stopped = true; + self.client_subscriptions.clear(); self.collaborators.clear(); self.worktree_store.update(cx, |store, cx| { store.disconnected_from_host(cx);