@@ -1,18 +1,20 @@
use crate::TestServer;
use call::ActiveCall;
+use client::ChannelId;
use gpui::{App, BackgroundExecutor, Entity, TestAppContext, TestScreenCaptureSource};
use project::Project;
-use serde_json::json;
-use util::path;
-use workspace::Workspace;
+use rpc::proto::PeerId;
+use workspace::{AutoWatch, SharedScreen, Workspace};
use super::TestClient;
struct AutoWatchTestSetup {
client_a: TestClient,
- _client_b: TestClient,
- _client_c: TestClient,
- project_a: Entity<Project>,
+ client_b: TestClient,
+ client_c: TestClient,
+ channel_id: ChannelId,
+ user_a_project: Entity<Project>,
+ user_b_project: Entity<Project>,
}
async fn setup_auto_watch_test(
@@ -20,35 +22,67 @@ async fn setup_auto_watch_test(
user_a: &mut TestAppContext,
user_b: &mut TestAppContext,
user_c: &mut TestAppContext,
+) -> AutoWatchTestSetup {
+ setup_auto_watch_test_with_initial_participants(server, user_a, user_b, user_c, true).await
+}
+
+async fn setup_auto_watch_late_joiner_test(
+ server: &mut TestServer,
+ user_a: &mut TestAppContext,
+ user_b: &mut TestAppContext,
+ user_c: &mut TestAppContext,
+) -> AutoWatchTestSetup {
+ setup_auto_watch_test_with_initial_participants(server, user_a, user_b, user_c, false).await
+}
+
+async fn setup_auto_watch_test_with_initial_participants(
+ server: &mut TestServer,
+ user_a: &mut TestAppContext,
+ user_b: &mut TestAppContext,
+ user_c: &mut TestAppContext,
+ join_user_c: bool,
) -> AutoWatchTestSetup {
let client_a = server.create_client(user_a, "user_a").await;
let client_b = server.create_client(user_b, "user_b").await;
let client_c = server.create_client(user_c, "user_c").await;
- server
- .create_room(&mut [
+ let channel_id = server
+ .make_channel(
+ "the-channel",
+ None,
(&client_a, user_a),
- (&client_b, user_b),
- (&client_c, user_c),
- ])
+ &mut [(&client_b, user_b), (&client_c, user_c)],
+ )
.await;
- let active_call_a = user_a.read(ActiveCall::global);
+ let user_a_project = client_a.build_empty_local_project(false, user_a);
+ let user_b_project = client_b.build_empty_local_project(false, user_b);
- client_a
- .fs()
- .insert_tree(path!("/a"), json!({ "file.txt": "content" }))
- .await;
- let (project_a, _worktree_id) = client_a.build_local_project(path!("/a"), user_a).await;
+ let active_call_a = user_a.read(ActiveCall::global);
active_call_a
- .update(user_a, |call, cx| call.set_location(Some(&project_a), cx))
+ .update(user_a, |call, cx| call.join_channel(channel_id, cx))
.await
.unwrap();
+ let active_call_b = user_b.read(ActiveCall::global);
+ active_call_b
+ .update(user_b, |call, cx| call.join_channel(channel_id, cx))
+ .await
+ .unwrap();
+
+ if join_user_c {
+ let active_call_c = user_c.read(ActiveCall::global);
+ active_call_c
+ .update(user_c, |call, cx| call.join_channel(channel_id, cx))
+ .await
+ .unwrap();
+ }
AutoWatchTestSetup {
client_a,
- _client_b: client_b,
- _client_c: client_c,
- project_a,
+ client_b,
+ client_c,
+ channel_id,
+ user_a_project,
+ user_b_project,
}
}
@@ -61,7 +95,9 @@ async fn test_auto_watch_opens_existing_share_on_toggle(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
executor.run_until_parked();
start_screen_share(user_b).await;
@@ -73,7 +109,11 @@ async fn test_auto_watch_opens_existing_share_on_toggle(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
});
}
@@ -86,7 +126,9 @@ async fn test_auto_watch_opens_share_when_no_one_is_sharing_yet(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
workspace_a.update_in(user_a, |workspace, window, cx| {
workspace.toggle_auto_watch(window, cx);
@@ -96,7 +138,11 @@ async fn test_auto_watch_opens_share_when_no_one_is_sharing_yet(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
});
}
@@ -109,7 +155,9 @@ async fn test_auto_watch_switches_to_next_share_on_share_end(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
workspace_a.update_in(user_a, |workspace, window, cx| {
workspace.toggle_auto_watch(window, cx);
@@ -119,7 +167,11 @@ async fn test_auto_watch_switches_to_next_share_on_share_end(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
});
start_screen_share(user_c).await;
@@ -129,7 +181,11 @@ async fn test_auto_watch_switches_to_next_share_on_share_end(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_c's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_c.peer_id().unwrap(),
+ cx,
+ );
});
}
@@ -142,7 +198,9 @@ async fn test_auto_watch_ignores_shares_while_user_is_sharing(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
start_screen_share(user_a).await;
executor.run_until_parked();
@@ -155,16 +213,11 @@ async fn test_auto_watch_ignores_shares_while_user_is_sharing(
});
executor.run_until_parked();
- // Ensure that no screen share is found in user a's tab bar
workspace_a.update(user_a, |workspace, cx| {
- let has_shared_screen_tab = workspace
- .active_pane()
- .read(cx)
- .items()
- .any(|item| item.tab_content_text(0, cx).contains("screen"));
- assert!(
- !has_shared_screen_tab,
- "should not open anyone's screen share when toggling on while sharing"
+ assert_no_screen_share_tabs_exist(
+ workspace,
+ "should not open anyone's screen share when toggling on while sharing",
+ cx,
);
});
}
@@ -178,7 +231,9 @@ async fn test_auto_watch_opens_share_after_local_user_stops_sharing(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
workspace_a.update_in(user_a, |workspace, window, cx| {
workspace.toggle_auto_watch(window, cx);
@@ -193,7 +248,11 @@ async fn test_auto_watch_opens_share_after_local_user_stops_sharing(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
});
}
@@ -206,7 +265,9 @@ async fn test_auto_watch_toggle_off_leaves_tabs_open(
) {
let mut server = TestServer::start(executor.clone()).await;
let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
- let (workspace_a, user_a) = setup.client_a.build_workspace(&setup.project_a, user_a);
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
workspace_a.update_in(user_a, |workspace, window, cx| {
workspace.toggle_auto_watch(window, cx);
@@ -215,27 +276,177 @@ async fn test_auto_watch_toggle_off_leaves_tabs_open(
executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
+ });
+
+ workspace_a.update_in(user_a, |workspace, window, cx| {
+ workspace.toggle_auto_watch(window, cx);
+ });
+
+ workspace_a.update(user_a, |workspace, cx| {
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
+ });
+}
+
+#[gpui::test]
+async fn test_auto_watch_reopens_screen_share_from_returning_channel_participant(
+ executor: BackgroundExecutor,
+ user_a: &mut TestAppContext,
+ user_b: &mut TestAppContext,
+ user_c: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(executor.clone()).await;
+ let setup = setup_auto_watch_late_joiner_test(&mut server, user_a, user_b, user_c).await;
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
+ let (workspace_b, user_b) = setup
+ .client_b
+ .build_workspace(&setup.user_b_project, user_b);
+
+ workspace_a.update_in(user_a, |workspace, window, cx| {
+ workspace.toggle_auto_watch(window, cx);
+ });
+ workspace_b.update_in(user_b, |workspace, window, cx| {
+ workspace.toggle_auto_watch(window, cx);
+ });
+ executor.run_until_parked();
+
+ let active_call_c = user_c.read(ActiveCall::global);
+ active_call_c
+ .update(user_c, |call, cx| call.join_channel(setup.channel_id, cx))
+ .await
+ .unwrap();
+ executor.run_until_parked();
+
+ start_screen_share(user_c).await;
+ executor.run_until_parked();
+
+ workspace_a.update(user_a, |workspace, cx| {
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_c.peer_id().unwrap(),
+ cx,
+ );
+ });
+ workspace_b.update(user_b, |workspace, cx| {
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_c.peer_id().unwrap(),
+ cx,
+ );
+ });
+
+ active_call_c
+ .update(user_c, |call, cx| call.hang_up(cx))
+ .await
+ .unwrap();
+ executor.run_until_parked();
+
+ workspace_a.update(user_a, |workspace, cx| {
+ assert_no_screen_share_tabs_exist(
+ workspace,
+ "user A should stop seeing user C's screen after user C hangs up",
+ cx,
+ );
});
+ workspace_b.update(user_b, |workspace, cx| {
+ assert_no_screen_share_tabs_exist(
+ workspace,
+ "user B should stop seeing user C's screen after user C hangs up",
+ cx,
+ );
+ });
+
+ let active_call_c = user_c.read(ActiveCall::global);
+ active_call_c
+ .update(user_c, |call, cx| call.join_channel(setup.channel_id, cx))
+ .await
+ .unwrap();
+ executor.run_until_parked();
+
+ start_screen_share(user_c).await;
+ executor.run_until_parked();
+
+ workspace_a.update(user_a, |workspace, cx| {
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_c.peer_id().unwrap(),
+ cx,
+ );
+ });
+ workspace_b.update(user_b, |workspace, cx| {
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_c.peer_id().unwrap(),
+ cx,
+ );
+ });
+}
+
+#[gpui::test]
+async fn test_auto_watch_is_disabled_when_following_collaborator(
+ executor: BackgroundExecutor,
+ user_a: &mut TestAppContext,
+ user_b: &mut TestAppContext,
+ user_c: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(executor.clone()).await;
+ let setup = setup_auto_watch_test(&mut server, user_a, user_b, user_c).await;
+ let (workspace_a, user_a) = setup
+ .client_a
+ .build_workspace(&setup.user_a_project, user_a);
+ let user_b_peer_id = setup.client_b.peer_id().unwrap();
workspace_a.update_in(user_a, |workspace, window, cx| {
workspace.toggle_auto_watch(window, cx);
});
+ start_screen_share(user_b).await;
+ executor.run_until_parked();
workspace_a.update(user_a, |workspace, cx| {
- assert_active_matches_title(workspace, "user_b's screen", cx);
+ assert_active_item_is_screen_share_for_peer(
+ workspace,
+ setup.client_b.peer_id().unwrap(),
+ cx,
+ );
});
+
+ workspace_a.update_in(user_a, |workspace, window, cx| {
+ workspace.follow(user_b_peer_id, window, cx);
+ });
+ executor.run_until_parked();
+
+ workspace_a.update(user_a, |workspace, _cx| {
+ assert_eq!(*workspace.auto_watch_state(), AutoWatch::Off);
+ });
+}
+
+#[track_caller]
+fn assert_no_screen_share_tabs_exist(workspace: &Workspace, message: &str, cx: &App) {
+ let has_shared_screen_tab = workspace
+ .active_pane()
+ .read(cx)
+ .items()
+ .any(|item| item.downcast::<SharedScreen>().is_some());
+ assert!(!has_shared_screen_tab, "{message}");
}
#[track_caller]
-fn assert_active_matches_title(workspace: &Workspace, expected_title: &str, cx: &App) {
+fn assert_active_item_is_screen_share_for_peer(workspace: &Workspace, peer_id: PeerId, cx: &App) {
let active_item = workspace.active_item(cx).expect("no active item");
- assert_eq!(
- active_item.tab_content_text(0, cx),
- expected_title,
- "expected active item to be '{}'",
- expected_title
- );
+ let shared_screen = active_item
+ .downcast::<SharedScreen>()
+ .expect("expected active item to be a shared screen");
+ assert_eq!(shared_screen.read(cx).peer_id, peer_id);
}
async fn start_screen_share(cx: &mut TestAppContext) {
@@ -260,6 +471,7 @@ async fn start_screen_share(cx: &mut TestAppContext) {
.unwrap();
}
+#[track_caller]
fn stop_screen_share(cx: &mut TestAppContext) {
let active_call = cx.read(ActiveCall::global);
active_call