1use crate::tests::TestServer;
2use call::ActiveCall;
3use editor::Editor;
4use gpui::{BackgroundExecutor, TestAppContext};
5use rpc::proto;
6
7#[gpui::test]
8async fn test_channel_guests(
9 executor: BackgroundExecutor,
10 cx_a: &mut TestAppContext,
11 cx_b: &mut TestAppContext,
12) {
13 let mut server = TestServer::start(executor.clone()).await;
14 let client_a = server.create_client(cx_a, "user_a").await;
15 let client_b = server.create_client(cx_b, "user_b").await;
16 let active_call_a = cx_a.read(ActiveCall::global);
17
18 let channel_id = server
19 .make_public_channel("the-channel", &client_a, cx_a)
20 .await;
21
22 // Client A shares a project in the channel
23 let project_a = client_a.build_test_project(cx_a).await;
24 active_call_a
25 .update(cx_a, |call, cx| call.join_channel(channel_id, cx))
26 .await
27 .unwrap();
28 let project_id = active_call_a
29 .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
30 .await
31 .unwrap();
32 cx_a.executor().run_until_parked();
33
34 // Client B joins channel A as a guest
35 cx_b.update(|cx| workspace::join_channel(channel_id, client_b.app_state.clone(), None, cx))
36 .await
37 .unwrap();
38
39 // b should be following a in the shared project.
40 // B is a guest,
41 executor.run_until_parked();
42
43 let active_call_b = cx_b.read(ActiveCall::global);
44 let project_b =
45 active_call_b.read_with(cx_b, |call, _| call.location().unwrap().upgrade().unwrap());
46 let room_b = active_call_b.update(cx_b, |call, _| call.room().unwrap().clone());
47
48 assert_eq!(
49 project_b.read_with(cx_b, |project, _| project.remote_id()),
50 Some(project_id),
51 );
52 assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
53 assert!(project_b
54 .update(cx_b, |project, cx| {
55 let worktree_id = project.worktrees().next().unwrap().read(cx).id();
56 project.create_entry((worktree_id, "b.txt"), false, cx)
57 })
58 .await
59 .is_err());
60 assert!(room_b.read_with(cx_b, |room, _| !room.is_sharing_mic()));
61}
62
63#[gpui::test]
64async fn test_channel_guest_promotion(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
65 let mut server = TestServer::start(cx_a.executor()).await;
66 let client_a = server.create_client(cx_a, "user_a").await;
67 let client_b = server.create_client(cx_b, "user_b").await;
68 let active_call_a = cx_a.read(ActiveCall::global);
69
70 let channel_id = server
71 .make_public_channel("the-channel", &client_a, cx_a)
72 .await;
73
74 let project_a = client_a.build_test_project(cx_a).await;
75 cx_a.update(|cx| workspace::join_channel(channel_id, client_a.app_state.clone(), None, cx))
76 .await
77 .unwrap();
78
79 // Client A shares a project in the channel
80 active_call_a
81 .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
82 .await
83 .unwrap();
84 cx_a.run_until_parked();
85
86 // Client B joins channel A as a guest
87 cx_b.update(|cx| workspace::join_channel(channel_id, client_b.app_state.clone(), None, cx))
88 .await
89 .unwrap();
90 cx_a.run_until_parked();
91
92 // client B opens 1.txt as a guest
93 let (workspace_b, cx_b) = client_b.active_workspace(cx_b);
94 let room_b = cx_b
95 .read(ActiveCall::global)
96 .update(cx_b, |call, _| call.room().unwrap().clone());
97 cx_b.simulate_keystrokes("cmd-p 1 enter");
98
99 let (project_b, editor_b) = workspace_b.update(cx_b, |workspace, cx| {
100 (
101 workspace.project().clone(),
102 workspace.active_item_as::<Editor>(cx).unwrap(),
103 )
104 });
105 assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
106 assert!(editor_b.update(cx_b, |e, cx| e.read_only(cx)));
107 assert!(dbg!(
108 room_b
109 .update(cx_b, |room, cx| room.share_microphone(cx))
110 .await
111 )
112 .is_err());
113
114 // B is promoted
115 active_call_a
116 .update(cx_a, |call, cx| {
117 call.room().unwrap().update(cx, |room, cx| {
118 room.set_participant_role(
119 client_b.user_id().unwrap(),
120 proto::ChannelRole::Member,
121 cx,
122 )
123 })
124 })
125 .await
126 .unwrap();
127 cx_a.run_until_parked();
128
129 // project and buffers are now editable
130 assert!(project_b.read_with(cx_b, |project, _| !project.is_read_only()));
131 assert!(editor_b.update(cx_b, |editor, cx| !editor.read_only(cx)));
132 room_b
133 .update(cx_b, |room, cx| room.share_microphone(cx))
134 .await
135 .unwrap();
136
137 // B is demoted
138 active_call_a
139 .update(cx_a, |call, cx| {
140 call.room().unwrap().update(cx, |room, cx| {
141 room.set_participant_role(
142 client_b.user_id().unwrap(),
143 proto::ChannelRole::Guest,
144 cx,
145 )
146 })
147 })
148 .await
149 .unwrap();
150 cx_a.run_until_parked();
151
152 // project and buffers are no longer editable
153 assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
154 assert!(editor_b.update(cx_b, |editor, cx| editor.read_only(cx)));
155 assert!(room_b
156 .update(cx_b, |room, cx| room.share_microphone(cx))
157 .await
158 .is_err());
159}