channel_tests.rs

  1use crate::{
  2    rpc::RECONNECT_TIMEOUT,
  3    tests::{room_participants, RoomParticipants, TestServer},
  4};
  5use call::ActiveCall;
  6use client::{Channel, ChannelMembership, User};
  7use gpui::{executor::Deterministic, TestAppContext};
  8use rpc::{proto, RECEIVE_TIMEOUT};
  9use std::sync::Arc;
 10
 11#[gpui::test]
 12async fn test_core_channels(
 13    deterministic: Arc<Deterministic>,
 14    cx_a: &mut TestAppContext,
 15    cx_b: &mut TestAppContext,
 16) {
 17    deterministic.forbid_parking();
 18    let mut server = TestServer::start(&deterministic).await;
 19    let client_a = server.create_client(cx_a, "user_a").await;
 20    let client_b = server.create_client(cx_b, "user_b").await;
 21
 22    let channel_a_id = client_a
 23        .channel_store()
 24        .update(cx_a, |channel_store, cx| {
 25            channel_store.create_channel("channel-a", None, cx)
 26        })
 27        .await
 28        .unwrap();
 29    let channel_b_id = client_a
 30        .channel_store()
 31        .update(cx_a, |channel_store, cx| {
 32            channel_store.create_channel("channel-b", Some(channel_a_id), cx)
 33        })
 34        .await
 35        .unwrap();
 36
 37    deterministic.run_until_parked();
 38    client_a.channel_store().read_with(cx_a, |channels, _| {
 39        assert_eq!(
 40            channels.channels(),
 41            &[
 42                Arc::new(Channel {
 43                    id: channel_a_id,
 44                    name: "channel-a".to_string(),
 45                    parent_id: None,
 46                    depth: 0,
 47                }),
 48                Arc::new(Channel {
 49                    id: channel_b_id,
 50                    name: "channel-b".to_string(),
 51                    parent_id: Some(channel_a_id),
 52                    depth: 1,
 53                })
 54            ]
 55        );
 56        assert!(channels.is_user_admin(channel_a_id));
 57        assert!(channels.is_user_admin(channel_b_id));
 58    });
 59
 60    client_b
 61        .channel_store()
 62        .read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
 63
 64    // Invite client B to channel A as client A.
 65    client_a
 66        .channel_store()
 67        .update(cx_a, |store, cx| {
 68            assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
 69
 70            let invite = store.invite_member(channel_a_id, client_b.user_id().unwrap(), false, cx);
 71
 72            // Make sure we're synchronously storing the pending invite
 73            assert!(store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
 74            invite
 75        })
 76        .await
 77        .unwrap();
 78
 79    // Client A sees that B has been invited.
 80    deterministic.run_until_parked();
 81    client_b.channel_store().read_with(cx_b, |channels, _| {
 82        assert_eq!(
 83            channels.channel_invitations(),
 84            &[Arc::new(Channel {
 85                id: channel_a_id,
 86                name: "channel-a".to_string(),
 87                parent_id: None,
 88                depth: 0,
 89            })]
 90        )
 91    });
 92
 93    let members = client_a
 94        .channel_store()
 95        .update(cx_a, |store, cx| {
 96            assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
 97            store.get_channel_member_details(channel_a_id, cx)
 98        })
 99        .await
100        .unwrap();
101    assert_members_eq(
102        &members,
103        &[
104            (
105                client_a.user_id().unwrap(),
106                true,
107                proto::channel_member::Kind::Member,
108            ),
109            (
110                client_b.user_id().unwrap(),
111                false,
112                proto::channel_member::Kind::Invitee,
113            ),
114        ],
115    );
116
117    // Client B accepts the invitation.
118    client_b
119        .channel_store()
120        .update(cx_b, |channels, _| {
121            channels.respond_to_channel_invite(channel_a_id, true)
122        })
123        .await
124        .unwrap();
125    deterministic.run_until_parked();
126
127    // Client B now sees that they are a member of channel A and its existing subchannels.
128    client_b.channel_store().read_with(cx_b, |channels, _| {
129        assert_eq!(channels.channel_invitations(), &[]);
130        assert_eq!(
131            channels.channels(),
132            &[
133                Arc::new(Channel {
134                    id: channel_a_id,
135                    name: "channel-a".to_string(),
136                    parent_id: None,
137                    depth: 0,
138                }),
139                Arc::new(Channel {
140                    id: channel_b_id,
141                    name: "channel-b".to_string(),
142                    parent_id: Some(channel_a_id),
143                    depth: 1,
144                })
145            ]
146        );
147        assert!(!channels.is_user_admin(channel_a_id));
148        assert!(!channels.is_user_admin(channel_b_id));
149    });
150
151    let channel_c_id = client_a
152        .channel_store()
153        .update(cx_a, |channel_store, cx| {
154            channel_store.create_channel("channel-c", Some(channel_b_id), cx)
155        })
156        .await
157        .unwrap();
158
159    deterministic.run_until_parked();
160    client_b.channel_store().read_with(cx_b, |channels, _| {
161        assert_eq!(
162            channels.channels(),
163            &[
164                Arc::new(Channel {
165                    id: channel_a_id,
166                    name: "channel-a".to_string(),
167                    parent_id: None,
168                    depth: 0,
169                }),
170                Arc::new(Channel {
171                    id: channel_b_id,
172                    name: "channel-b".to_string(),
173                    parent_id: Some(channel_a_id),
174                    depth: 1,
175                }),
176                Arc::new(Channel {
177                    id: channel_c_id,
178                    name: "channel-c".to_string(),
179                    parent_id: Some(channel_b_id),
180                    depth: 2,
181                }),
182            ]
183        )
184    });
185
186    // Update client B's membership to channel A to be an admin.
187    client_a
188        .channel_store()
189        .update(cx_a, |store, cx| {
190            store.set_member_admin(channel_a_id, client_b.user_id().unwrap(), true, cx)
191        })
192        .await
193        .unwrap();
194    deterministic.run_until_parked();
195
196    // Observe that client B is now an admin of channel A, and that
197    // their admin priveleges extend to subchannels of channel A.
198    client_b.channel_store().read_with(cx_b, |channels, _| {
199        assert_eq!(channels.channel_invitations(), &[]);
200        assert_eq!(
201            channels.channels(),
202            &[
203                Arc::new(Channel {
204                    id: channel_a_id,
205                    name: "channel-a".to_string(),
206                    parent_id: None,
207                    depth: 0,
208                }),
209                Arc::new(Channel {
210                    id: channel_b_id,
211                    name: "channel-b".to_string(),
212                    parent_id: Some(channel_a_id),
213                    depth: 1,
214                }),
215                Arc::new(Channel {
216                    id: channel_c_id,
217                    name: "channel-c".to_string(),
218                    parent_id: Some(channel_b_id),
219                    depth: 2,
220                }),
221            ]
222        );
223
224        assert!(channels.is_user_admin(channel_c_id))
225    });
226
227    // Client A deletes the channel, deletion also deletes subchannels.
228    client_a
229        .channel_store()
230        .update(cx_a, |channel_store, _| {
231            channel_store.remove_channel(channel_b_id)
232        })
233        .await
234        .unwrap();
235
236    deterministic.run_until_parked();
237    client_a.channel_store().read_with(cx_a, |channels, _| {
238        assert_eq!(
239            channels.channels(),
240            &[Arc::new(Channel {
241                id: channel_a_id,
242                name: "channel-a".to_string(),
243                parent_id: None,
244
245                depth: 0,
246            })]
247        )
248    });
249    client_b.channel_store().read_with(cx_b, |channels, _| {
250        assert_eq!(
251            channels.channels(),
252            &[Arc::new(Channel {
253                id: channel_a_id,
254                name: "channel-a".to_string(),
255                parent_id: None,
256
257                depth: 0,
258            })]
259        )
260    });
261
262    // Remove client B
263    client_a
264        .channel_store()
265        .update(cx_a, |channel_store, cx| {
266            channel_store.remove_member(channel_a_id, client_b.user_id().unwrap(), cx)
267        })
268        .await
269        .unwrap();
270
271    deterministic.run_until_parked();
272
273    // Client A still has their channel
274    client_a.channel_store().read_with(cx_a, |channels, _| {
275        assert_eq!(
276            channels.channels(),
277            &[Arc::new(Channel {
278                id: channel_a_id,
279                name: "channel-a".to_string(),
280                parent_id: None,
281                depth: 0,
282            })]
283        )
284    });
285
286    // Client B is gone
287    client_b
288        .channel_store()
289        .read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
290
291    // When disconnected, client A sees no channels.
292    server.forbid_connections();
293    server.disconnect_client(client_a.peer_id().unwrap());
294    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
295    client_a.channel_store().read_with(cx_a, |channels, _| {
296        assert_eq!(channels.channels(), &[]);
297        assert!(!channels.is_user_admin(channel_a_id));
298    });
299
300    server.allow_connections();
301    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
302    client_a.channel_store().read_with(cx_a, |channels, _| {
303        assert_eq!(
304            channels.channels(),
305            &[Arc::new(Channel {
306                id: channel_a_id,
307                name: "channel-a".to_string(),
308                parent_id: None,
309                depth: 0,
310            })]
311        );
312        assert!(channels.is_user_admin(channel_a_id));
313    });
314}
315
316fn assert_participants_eq(participants: &[Arc<User>], expected_partitipants: &[u64]) {
317    assert_eq!(
318        participants.iter().map(|p| p.id).collect::<Vec<_>>(),
319        expected_partitipants
320    );
321}
322
323fn assert_members_eq(
324    members: &[ChannelMembership],
325    expected_members: &[(u64, bool, proto::channel_member::Kind)],
326) {
327    assert_eq!(
328        members
329            .iter()
330            .map(|member| (member.user.id, member.admin, member.kind))
331            .collect::<Vec<_>>(),
332        expected_members
333    );
334}
335
336#[gpui::test]
337async fn test_joining_channel_ancestor_member(
338    deterministic: Arc<Deterministic>,
339    cx_a: &mut TestAppContext,
340    cx_b: &mut TestAppContext,
341) {
342    deterministic.forbid_parking();
343    let mut server = TestServer::start(&deterministic).await;
344
345    let client_a = server.create_client(cx_a, "user_a").await;
346    let client_b = server.create_client(cx_b, "user_b").await;
347
348    let parent_id = server
349        .make_channel("parent", (&client_a, cx_a), &mut [(&client_b, cx_b)])
350        .await;
351
352    let sub_id = client_a
353        .channel_store()
354        .update(cx_a, |channel_store, cx| {
355            channel_store.create_channel("sub_channel", Some(parent_id), cx)
356        })
357        .await
358        .unwrap();
359
360    let active_call_b = cx_b.read(ActiveCall::global);
361
362    assert!(active_call_b
363        .update(cx_b, |active_call, cx| active_call.join_channel(sub_id, cx))
364        .await
365        .is_ok());
366}
367
368#[gpui::test]
369async fn test_channel_room(
370    deterministic: Arc<Deterministic>,
371    cx_a: &mut TestAppContext,
372    cx_b: &mut TestAppContext,
373    cx_c: &mut TestAppContext,
374) {
375    deterministic.forbid_parking();
376    let mut server = TestServer::start(&deterministic).await;
377    let client_a = server.create_client(cx_a, "user_a").await;
378    let client_b = server.create_client(cx_b, "user_b").await;
379    let client_c = server.create_client(cx_c, "user_c").await;
380
381    let zed_id = server
382        .make_channel(
383            "zed",
384            (&client_a, cx_a),
385            &mut [(&client_b, cx_b), (&client_c, cx_c)],
386        )
387        .await;
388
389    let active_call_a = cx_a.read(ActiveCall::global);
390    let active_call_b = cx_b.read(ActiveCall::global);
391
392    active_call_a
393        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
394        .await
395        .unwrap();
396
397    // Give everyone a chance to observe user A joining
398    deterministic.run_until_parked();
399
400    client_a.channel_store().read_with(cx_a, |channels, _| {
401        assert_participants_eq(
402            channels.channel_participants(zed_id),
403            &[client_a.user_id().unwrap()],
404        );
405    });
406
407    client_b.channel_store().read_with(cx_b, |channels, _| {
408        assert_participants_eq(
409            channels.channel_participants(zed_id),
410            &[client_a.user_id().unwrap()],
411        );
412        assert_eq!(
413            channels.channels(),
414            &[Arc::new(Channel {
415                id: zed_id,
416                name: "zed".to_string(),
417                parent_id: None,
418                depth: 0,
419            })]
420        )
421    });
422
423    client_c.channel_store().read_with(cx_c, |channels, _| {
424        assert_participants_eq(
425            channels.channel_participants(zed_id),
426            &[client_a.user_id().unwrap()],
427        );
428    });
429
430    active_call_b
431        .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
432        .await
433        .unwrap();
434
435    deterministic.run_until_parked();
436
437    client_a.channel_store().read_with(cx_a, |channels, _| {
438        assert_participants_eq(
439            channels.channel_participants(zed_id),
440            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
441        );
442    });
443
444    client_b.channel_store().read_with(cx_b, |channels, _| {
445        assert_participants_eq(
446            channels.channel_participants(zed_id),
447            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
448        );
449    });
450
451    client_c.channel_store().read_with(cx_c, |channels, _| {
452        assert_participants_eq(
453            channels.channel_participants(zed_id),
454            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
455        );
456    });
457
458    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
459    room_a.read_with(cx_a, |room, _| assert!(room.is_connected()));
460    assert_eq!(
461        room_participants(&room_a, cx_a),
462        RoomParticipants {
463            remote: vec!["user_b".to_string()],
464            pending: vec![]
465        }
466    );
467
468    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
469    room_b.read_with(cx_b, |room, _| assert!(room.is_connected()));
470    assert_eq!(
471        room_participants(&room_b, cx_b),
472        RoomParticipants {
473            remote: vec!["user_a".to_string()],
474            pending: vec![]
475        }
476    );
477
478    // Make sure that leaving and rejoining works
479
480    active_call_a
481        .update(cx_a, |active_call, cx| active_call.hang_up(cx))
482        .await
483        .unwrap();
484
485    deterministic.run_until_parked();
486
487    client_a.channel_store().read_with(cx_a, |channels, _| {
488        assert_participants_eq(
489            channels.channel_participants(zed_id),
490            &[client_b.user_id().unwrap()],
491        );
492    });
493
494    client_b.channel_store().read_with(cx_b, |channels, _| {
495        assert_participants_eq(
496            channels.channel_participants(zed_id),
497            &[client_b.user_id().unwrap()],
498        );
499    });
500
501    client_c.channel_store().read_with(cx_c, |channels, _| {
502        assert_participants_eq(
503            channels.channel_participants(zed_id),
504            &[client_b.user_id().unwrap()],
505        );
506    });
507
508    active_call_b
509        .update(cx_b, |active_call, cx| active_call.hang_up(cx))
510        .await
511        .unwrap();
512
513    deterministic.run_until_parked();
514
515    client_a.channel_store().read_with(cx_a, |channels, _| {
516        assert_participants_eq(channels.channel_participants(zed_id), &[]);
517    });
518
519    client_b.channel_store().read_with(cx_b, |channels, _| {
520        assert_participants_eq(channels.channel_participants(zed_id), &[]);
521    });
522
523    client_c.channel_store().read_with(cx_c, |channels, _| {
524        assert_participants_eq(channels.channel_participants(zed_id), &[]);
525    });
526
527    active_call_a
528        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
529        .await
530        .unwrap();
531
532    active_call_b
533        .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
534        .await
535        .unwrap();
536
537    deterministic.run_until_parked();
538
539    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
540    room_a.read_with(cx_a, |room, _| assert!(room.is_connected()));
541    assert_eq!(
542        room_participants(&room_a, cx_a),
543        RoomParticipants {
544            remote: vec!["user_b".to_string()],
545            pending: vec![]
546        }
547    );
548
549    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
550    room_b.read_with(cx_b, |room, _| assert!(room.is_connected()));
551    assert_eq!(
552        room_participants(&room_b, cx_b),
553        RoomParticipants {
554            remote: vec!["user_a".to_string()],
555            pending: vec![]
556        }
557    );
558}
559
560#[gpui::test]
561async fn test_channel_jumping(deterministic: Arc<Deterministic>, cx_a: &mut TestAppContext) {
562    deterministic.forbid_parking();
563    let mut server = TestServer::start(&deterministic).await;
564    let client_a = server.create_client(cx_a, "user_a").await;
565
566    let zed_id = server.make_channel("zed", (&client_a, cx_a), &mut []).await;
567    let rust_id = server
568        .make_channel("rust", (&client_a, cx_a), &mut [])
569        .await;
570
571    let active_call_a = cx_a.read(ActiveCall::global);
572
573    active_call_a
574        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
575        .await
576        .unwrap();
577
578    // Give everything a chance to observe user A joining
579    deterministic.run_until_parked();
580
581    client_a.channel_store().read_with(cx_a, |channels, _| {
582        assert_participants_eq(
583            channels.channel_participants(zed_id),
584            &[client_a.user_id().unwrap()],
585        );
586        assert_participants_eq(channels.channel_participants(rust_id), &[]);
587    });
588
589    active_call_a
590        .update(cx_a, |active_call, cx| {
591            active_call.join_channel(rust_id, cx)
592        })
593        .await
594        .unwrap();
595
596    deterministic.run_until_parked();
597
598    client_a.channel_store().read_with(cx_a, |channels, _| {
599        assert_participants_eq(channels.channel_participants(zed_id), &[]);
600        assert_participants_eq(
601            channels.channel_participants(rust_id),
602            &[client_a.user_id().unwrap()],
603        );
604    });
605}
606
607#[gpui::test]
608async fn test_permissions_update_while_invited(
609    deterministic: Arc<Deterministic>,
610    cx_a: &mut TestAppContext,
611    cx_b: &mut TestAppContext,
612) {
613    deterministic.forbid_parking();
614    let mut server = TestServer::start(&deterministic).await;
615    let client_a = server.create_client(cx_a, "user_a").await;
616    let client_b = server.create_client(cx_b, "user_b").await;
617
618    let rust_id = server
619        .make_channel("rust", (&client_a, cx_a), &mut [])
620        .await;
621
622    client_a
623        .channel_store()
624        .update(cx_a, |channel_store, cx| {
625            channel_store.invite_member(rust_id, client_b.user_id().unwrap(), false, cx)
626        })
627        .await
628        .unwrap();
629
630    deterministic.run_until_parked();
631
632    client_b.channel_store().read_with(cx_b, |channels, _| {
633        assert_eq!(
634            channels.channel_invitations(),
635            &[Arc::new(Channel {
636                id: rust_id,
637                name: "rust".to_string(),
638                parent_id: None,
639
640                depth: 0,
641            })],
642        );
643
644        assert_eq!(channels.channels(), &[],);
645    });
646
647    // Update B's invite before they've accepted it
648    client_a
649        .channel_store()
650        .update(cx_a, |channel_store, cx| {
651            channel_store.set_member_admin(rust_id, client_b.user_id().unwrap(), true, cx)
652        })
653        .await
654        .unwrap();
655
656    deterministic.run_until_parked();
657
658    client_b.channel_store().read_with(cx_b, |channels, _| {
659        assert_eq!(
660            channels.channel_invitations(),
661            &[Arc::new(Channel {
662                id: rust_id,
663                name: "rust".to_string(),
664                parent_id: None,
665
666                depth: 0,
667            })],
668        );
669
670        assert_eq!(channels.channels(), &[],);
671    });
672}
673
674#[gpui::test]
675async fn test_channel_rename(
676    deterministic: Arc<Deterministic>,
677    cx_a: &mut TestAppContext,
678    cx_b: &mut TestAppContext,
679) {
680    deterministic.forbid_parking();
681    let mut server = TestServer::start(&deterministic).await;
682    let client_a = server.create_client(cx_a, "user_a").await;
683    let client_b = server.create_client(cx_b, "user_b").await;
684
685    let rust_id = server
686        .make_channel("rust", (&client_a, cx_a), &mut [(&client_b, cx_b)])
687        .await;
688
689    // Rename the channel
690    client_a
691        .channel_store()
692        .update(cx_a, |channel_store, cx| {
693            channel_store.rename(rust_id, "#rust-archive", cx)
694        })
695        .await
696        .unwrap();
697
698    let rust_archive_id = rust_id;
699    deterministic.run_until_parked();
700
701    // Client A sees the channel with its new name.
702    client_a.channel_store().read_with(cx_a, |channels, _| {
703        assert_eq!(
704            channels.channels(),
705            &[Arc::new(Channel {
706                id: rust_archive_id,
707                name: "rust-archive".to_string(),
708                parent_id: None,
709
710                depth: 0,
711            })],
712        );
713    });
714
715    // Client B sees the channel with its new name.
716    client_b.channel_store().read_with(cx_b, |channels, _| {
717        assert_eq!(
718            channels.channels(),
719            &[Arc::new(Channel {
720                id: rust_archive_id,
721                name: "rust-archive".to_string(),
722                parent_id: None,
723
724                depth: 0,
725            })],
726        );
727    });
728}