channel_message_tests.rs

  1use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
  2use channel::{ChannelChat, ChannelMessageId};
  3use collab_ui::chat_panel::ChatPanel;
  4use gpui::{executor::Deterministic, BorrowAppContext, ModelHandle, TestAppContext};
  5use std::sync::Arc;
  6use workspace::dock::Panel;
  7
  8#[gpui::test]
  9async fn test_basic_channel_messages(
 10    deterministic: Arc<Deterministic>,
 11    cx_a: &mut TestAppContext,
 12    cx_b: &mut TestAppContext,
 13) {
 14    deterministic.forbid_parking();
 15    let mut server = TestServer::start(&deterministic).await;
 16    let client_a = server.create_client(cx_a, "user_a").await;
 17    let client_b = server.create_client(cx_b, "user_b").await;
 18
 19    let channel_id = server
 20        .make_channel(
 21            "the-channel",
 22            None,
 23            (&client_a, cx_a),
 24            &mut [(&client_b, cx_b)],
 25        )
 26        .await;
 27
 28    let channel_chat_a = client_a
 29        .channel_store()
 30        .update(cx_a, |store, cx| store.open_channel_chat(channel_id, cx))
 31        .await
 32        .unwrap();
 33    let channel_chat_b = client_b
 34        .channel_store()
 35        .update(cx_b, |store, cx| store.open_channel_chat(channel_id, cx))
 36        .await
 37        .unwrap();
 38
 39    channel_chat_a
 40        .update(cx_a, |c, cx| c.send_message("one".into(), cx).unwrap())
 41        .await
 42        .unwrap();
 43    channel_chat_a
 44        .update(cx_a, |c, cx| c.send_message("two".into(), cx).unwrap())
 45        .await
 46        .unwrap();
 47
 48    deterministic.run_until_parked();
 49    channel_chat_b
 50        .update(cx_b, |c, cx| c.send_message("three".into(), cx).unwrap())
 51        .await
 52        .unwrap();
 53
 54    deterministic.run_until_parked();
 55    channel_chat_a.update(cx_a, |c, _| {
 56        assert_eq!(
 57            c.messages()
 58                .iter()
 59                .map(|m| m.body.as_str())
 60                .collect::<Vec<_>>(),
 61            vec!["one", "two", "three"]
 62        );
 63    })
 64}
 65
 66#[gpui::test]
 67async fn test_rejoin_channel_chat(
 68    deterministic: Arc<Deterministic>,
 69    cx_a: &mut TestAppContext,
 70    cx_b: &mut TestAppContext,
 71) {
 72    deterministic.forbid_parking();
 73    let mut server = TestServer::start(&deterministic).await;
 74    let client_a = server.create_client(cx_a, "user_a").await;
 75    let client_b = server.create_client(cx_b, "user_b").await;
 76
 77    let channel_id = server
 78        .make_channel(
 79            "the-channel",
 80            None,
 81            (&client_a, cx_a),
 82            &mut [(&client_b, cx_b)],
 83        )
 84        .await;
 85
 86    let channel_chat_a = client_a
 87        .channel_store()
 88        .update(cx_a, |store, cx| store.open_channel_chat(channel_id, cx))
 89        .await
 90        .unwrap();
 91    let channel_chat_b = client_b
 92        .channel_store()
 93        .update(cx_b, |store, cx| store.open_channel_chat(channel_id, cx))
 94        .await
 95        .unwrap();
 96
 97    channel_chat_a
 98        .update(cx_a, |c, cx| c.send_message("one".into(), cx).unwrap())
 99        .await
100        .unwrap();
101    channel_chat_b
102        .update(cx_b, |c, cx| c.send_message("two".into(), cx).unwrap())
103        .await
104        .unwrap();
105
106    server.forbid_connections();
107    server.disconnect_client(client_a.peer_id().unwrap());
108
109    // While client A is disconnected, clients A and B both send new messages.
110    channel_chat_a
111        .update(cx_a, |c, cx| c.send_message("three".into(), cx).unwrap())
112        .await
113        .unwrap_err();
114    channel_chat_a
115        .update(cx_a, |c, cx| c.send_message("four".into(), cx).unwrap())
116        .await
117        .unwrap_err();
118    channel_chat_b
119        .update(cx_b, |c, cx| c.send_message("five".into(), cx).unwrap())
120        .await
121        .unwrap();
122    channel_chat_b
123        .update(cx_b, |c, cx| c.send_message("six".into(), cx).unwrap())
124        .await
125        .unwrap();
126
127    // Client A reconnects.
128    server.allow_connections();
129    deterministic.advance_clock(RECONNECT_TIMEOUT);
130
131    // Client A fetches the messages that were sent while they were disconnected
132    // and resends their own messages which failed to send.
133    let expected_messages = &["one", "two", "five", "six", "three", "four"];
134    assert_messages(&channel_chat_a, expected_messages, cx_a);
135    assert_messages(&channel_chat_b, expected_messages, cx_b);
136}
137
138#[gpui::test]
139async fn test_remove_channel_message(
140    deterministic: Arc<Deterministic>,
141    cx_a: &mut TestAppContext,
142    cx_b: &mut TestAppContext,
143    cx_c: &mut TestAppContext,
144) {
145    deterministic.forbid_parking();
146    let mut server = TestServer::start(&deterministic).await;
147    let client_a = server.create_client(cx_a, "user_a").await;
148    let client_b = server.create_client(cx_b, "user_b").await;
149    let client_c = server.create_client(cx_c, "user_c").await;
150
151    let channel_id = server
152        .make_channel(
153            "the-channel",
154            None,
155            (&client_a, cx_a),
156            &mut [(&client_b, cx_b), (&client_c, cx_c)],
157        )
158        .await;
159
160    let channel_chat_a = client_a
161        .channel_store()
162        .update(cx_a, |store, cx| store.open_channel_chat(channel_id, cx))
163        .await
164        .unwrap();
165    let channel_chat_b = client_b
166        .channel_store()
167        .update(cx_b, |store, cx| store.open_channel_chat(channel_id, cx))
168        .await
169        .unwrap();
170
171    // Client A sends some messages.
172    channel_chat_a
173        .update(cx_a, |c, cx| c.send_message("one".into(), cx).unwrap())
174        .await
175        .unwrap();
176    channel_chat_a
177        .update(cx_a, |c, cx| c.send_message("two".into(), cx).unwrap())
178        .await
179        .unwrap();
180    channel_chat_a
181        .update(cx_a, |c, cx| c.send_message("three".into(), cx).unwrap())
182        .await
183        .unwrap();
184
185    // Clients A and B see all of the messages.
186    deterministic.run_until_parked();
187    let expected_messages = &["one", "two", "three"];
188    assert_messages(&channel_chat_a, expected_messages, cx_a);
189    assert_messages(&channel_chat_b, expected_messages, cx_b);
190
191    // Client A deletes one of their messages.
192    channel_chat_a
193        .update(cx_a, |c, cx| {
194            let ChannelMessageId::Saved(id) = c.message(1).id else {
195                panic!("message not saved")
196            };
197            c.remove_message(id, cx)
198        })
199        .await
200        .unwrap();
201
202    // Client B sees that the message is gone.
203    deterministic.run_until_parked();
204    let expected_messages = &["one", "three"];
205    assert_messages(&channel_chat_a, expected_messages, cx_a);
206    assert_messages(&channel_chat_b, expected_messages, cx_b);
207
208    // Client C joins the channel chat, and does not see the deleted message.
209    let channel_chat_c = client_c
210        .channel_store()
211        .update(cx_c, |store, cx| store.open_channel_chat(channel_id, cx))
212        .await
213        .unwrap();
214    assert_messages(&channel_chat_c, expected_messages, cx_c);
215}
216
217#[track_caller]
218fn assert_messages(chat: &ModelHandle<ChannelChat>, messages: &[&str], cx: &mut TestAppContext) {
219    assert_eq!(
220        chat.read_with(cx, |chat, _| chat
221            .messages()
222            .iter()
223            .map(|m| m.body.clone())
224            .collect::<Vec<_>>(),),
225        messages
226    );
227}
228
229#[gpui::test]
230async fn test_channel_message_changes(
231    deterministic: Arc<Deterministic>,
232    cx_a: &mut TestAppContext,
233    cx_b: &mut TestAppContext,
234) {
235    deterministic.forbid_parking();
236    let mut server = TestServer::start(&deterministic).await;
237    let client_a = server.create_client(cx_a, "user_a").await;
238    let client_b = server.create_client(cx_b, "user_b").await;
239
240    let channel_id = server
241        .make_channel(
242            "the-channel",
243            None,
244            (&client_a, cx_a),
245            &mut [(&client_b, cx_b)],
246        )
247        .await;
248
249    // Client A sends a message, client B should see that there is a new message.
250    let channel_chat_a = client_a
251        .channel_store()
252        .update(cx_a, |store, cx| store.open_channel_chat(channel_id, cx))
253        .await
254        .unwrap();
255
256    channel_chat_a
257        .update(cx_a, |c, cx| c.send_message("one".into(), cx).unwrap())
258        .await
259        .unwrap();
260
261    deterministic.run_until_parked();
262
263    let b_has_messages = cx_b.read_with(|cx| {
264        client_b
265            .channel_store()
266            .read(cx)
267            .has_new_messages(channel_id)
268            .unwrap()
269    });
270
271    assert!(b_has_messages);
272
273    // Opening the chat should clear the changed flag.
274    cx_b.update(|cx| {
275        collab_ui::init(&client_b.app_state, cx);
276    });
277    let project_b = client_b.build_empty_local_project(cx_b);
278    let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
279    let chat_panel_b = workspace_b.update(cx_b, |workspace, cx| ChatPanel::new(workspace, cx));
280    chat_panel_b
281        .update(cx_b, |chat_panel, cx| {
282            chat_panel.set_active(true, cx);
283            chat_panel.select_channel(channel_id, cx)
284        })
285        .await
286        .unwrap();
287
288    deterministic.run_until_parked();
289
290    let b_has_messages = cx_b.read_with(|cx| {
291        client_b
292            .channel_store()
293            .read(cx)
294            .has_new_messages(channel_id)
295            .unwrap()
296    });
297
298    assert!(!b_has_messages);
299
300    // Sending a message while the chat is open should not change the flag.
301    channel_chat_a
302        .update(cx_a, |c, cx| c.send_message("two".into(), cx).unwrap())
303        .await
304        .unwrap();
305
306    deterministic.run_until_parked();
307
308    let b_has_messages = cx_b.read_with(|cx| {
309        client_b
310            .channel_store()
311            .read(cx)
312            .has_new_messages(channel_id)
313            .unwrap()
314    });
315
316    assert!(!b_has_messages);
317
318    // Sending a message while the chat is closed should change the flag.
319    chat_panel_b.update(cx_b, |chat_panel, cx| {
320        chat_panel.set_active(false, cx);
321    });
322
323    // Sending a message while the chat is open should not change the flag.
324    channel_chat_a
325        .update(cx_a, |c, cx| c.send_message("three".into(), cx).unwrap())
326        .await
327        .unwrap();
328
329    deterministic.run_until_parked();
330
331    let b_has_messages = cx_b.read_with(|cx| {
332        client_b
333            .channel_store()
334            .read(cx)
335            .has_new_messages(channel_id)
336            .unwrap()
337    });
338
339    assert!(b_has_messages);
340
341    // Closing the chat should re-enable change tracking
342    cx_b.update(|_| drop(chat_panel_b));
343
344    channel_chat_a
345        .update(cx_a, |c, cx| c.send_message("four".into(), cx).unwrap())
346        .await
347        .unwrap();
348
349    deterministic.run_until_parked();
350
351    let b_has_messages = cx_b.read_with(|cx| {
352        client_b
353            .channel_store()
354            .read(cx)
355            .has_new_messages(channel_id)
356            .unwrap()
357    });
358
359    assert!(b_has_messages);
360}