1use crate::{
2 db::{
3 tests::{channel_tree, new_test_connection, new_test_user, TEST_RELEASE_CHANNEL},
4 Channel, ChannelId, ChannelRole, Database, NewUserParams, RoomId,
5 },
6 test_both_dbs,
7};
8use rpc::{
9 proto::{self},
10 ConnectionId,
11};
12use std::sync::Arc;
13
14test_both_dbs!(test_channels, test_channels_postgres, test_channels_sqlite);
15
16async fn test_channels(db: &Arc<Database>) {
17 let a_id = new_test_user(db, "user1@example.com").await;
18 let b_id = new_test_user(db, "user2@example.com").await;
19
20 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
21
22 // Make sure that people cannot read channels they haven't been invited to
23 assert!(db.get_channel(zed_id, b_id).await.is_err());
24
25 db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
26 .await
27 .unwrap();
28
29 db.respond_to_channel_invite(zed_id, b_id, true)
30 .await
31 .unwrap();
32
33 let crdb_id = db.create_sub_channel("crdb", zed_id, a_id).await.unwrap();
34 let livestreaming_id = db
35 .create_sub_channel("livestreaming", zed_id, a_id)
36 .await
37 .unwrap();
38 let replace_id = db
39 .create_sub_channel("replace", zed_id, a_id)
40 .await
41 .unwrap();
42
43 let mut members = db
44 .transaction(|tx| async move {
45 let channel = db.get_channel_internal(replace_id, &*tx).await?;
46 Ok(db.get_channel_participants(&channel, &*tx).await?)
47 })
48 .await
49 .unwrap();
50 members.sort();
51 assert_eq!(members, &[a_id, b_id]);
52
53 let rust_id = db.create_root_channel("rust", a_id).await.unwrap();
54 let cargo_id = db.create_sub_channel("cargo", rust_id, a_id).await.unwrap();
55
56 let cargo_ra_id = db
57 .create_sub_channel("cargo-ra", cargo_id, a_id)
58 .await
59 .unwrap();
60
61 let result = db.get_channels_for_user(a_id).await.unwrap();
62 assert_eq!(
63 result.channels,
64 channel_tree(&[
65 (zed_id, &[], "zed", ChannelRole::Admin),
66 (crdb_id, &[zed_id], "crdb", ChannelRole::Admin),
67 (
68 livestreaming_id,
69 &[zed_id],
70 "livestreaming",
71 ChannelRole::Admin
72 ),
73 (replace_id, &[zed_id], "replace", ChannelRole::Admin),
74 (rust_id, &[], "rust", ChannelRole::Admin),
75 (cargo_id, &[rust_id], "cargo", ChannelRole::Admin),
76 (
77 cargo_ra_id,
78 &[rust_id, cargo_id],
79 "cargo-ra",
80 ChannelRole::Admin
81 )
82 ],)
83 );
84
85 let result = db.get_channels_for_user(b_id).await.unwrap();
86 assert_eq!(
87 result.channels,
88 channel_tree(&[
89 (zed_id, &[], "zed", ChannelRole::Member),
90 (crdb_id, &[zed_id], "crdb", ChannelRole::Member),
91 (
92 livestreaming_id,
93 &[zed_id],
94 "livestreaming",
95 ChannelRole::Member
96 ),
97 (replace_id, &[zed_id], "replace", ChannelRole::Member)
98 ],)
99 );
100
101 // Update member permissions
102 let set_subchannel_admin = db
103 .set_channel_member_role(crdb_id, a_id, b_id, ChannelRole::Admin)
104 .await;
105 assert!(set_subchannel_admin.is_err());
106 let set_channel_admin = db
107 .set_channel_member_role(zed_id, a_id, b_id, ChannelRole::Admin)
108 .await;
109 assert!(set_channel_admin.is_ok());
110
111 let result = db.get_channels_for_user(b_id).await.unwrap();
112 assert_eq!(
113 result.channels,
114 channel_tree(&[
115 (zed_id, &[], "zed", ChannelRole::Admin),
116 (crdb_id, &[zed_id], "crdb", ChannelRole::Admin),
117 (
118 livestreaming_id,
119 &[zed_id],
120 "livestreaming",
121 ChannelRole::Admin
122 ),
123 (replace_id, &[zed_id], "replace", ChannelRole::Admin)
124 ],)
125 );
126
127 // Remove a single channel
128 db.delete_channel(crdb_id, a_id).await.unwrap();
129 assert!(db.get_channel(crdb_id, a_id).await.is_err());
130
131 // Remove a channel tree
132 let (mut channel_ids, user_ids) = db.delete_channel(rust_id, a_id).await.unwrap();
133 channel_ids.sort();
134 assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
135 assert_eq!(user_ids, &[a_id]);
136
137 assert!(db.get_channel(rust_id, a_id).await.is_err());
138 assert!(db.get_channel(cargo_id, a_id).await.is_err());
139 assert!(db.get_channel(cargo_ra_id, a_id).await.is_err());
140}
141
142test_both_dbs!(
143 test_joining_channels,
144 test_joining_channels_postgres,
145 test_joining_channels_sqlite
146);
147
148async fn test_joining_channels(db: &Arc<Database>) {
149 let owner_id = db.create_server("test").await.unwrap().0 as u32;
150
151 let user_1 = new_test_user(db, "user1@example.com").await;
152 let user_2 = new_test_user(db, "user2@example.com").await;
153
154 let channel_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
155
156 // can join a room with membership to its channel
157 let (joined_room, _, _) = db
158 .join_channel(
159 channel_1,
160 user_1,
161 ConnectionId { owner_id, id: 1 },
162 TEST_RELEASE_CHANNEL,
163 )
164 .await
165 .unwrap();
166 assert_eq!(joined_room.room.participants.len(), 1);
167
168 let room_id = RoomId::from_proto(joined_room.room.id);
169 drop(joined_room);
170 // cannot join a room without membership to its channel
171 assert!(db
172 .join_room(
173 room_id,
174 user_2,
175 ConnectionId { owner_id, id: 1 },
176 TEST_RELEASE_CHANNEL
177 )
178 .await
179 .is_err());
180}
181
182test_both_dbs!(
183 test_channel_invites,
184 test_channel_invites_postgres,
185 test_channel_invites_sqlite
186);
187
188async fn test_channel_invites(db: &Arc<Database>) {
189 db.create_server("test").await.unwrap();
190
191 let user_1 = new_test_user(db, "user1@example.com").await;
192 let user_2 = new_test_user(db, "user2@example.com").await;
193 let user_3 = new_test_user(db, "user3@example.com").await;
194
195 let channel_1_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
196
197 let channel_1_2 = db.create_root_channel("channel_2", user_1).await.unwrap();
198
199 db.invite_channel_member(channel_1_1, user_2, user_1, ChannelRole::Member)
200 .await
201 .unwrap();
202 db.invite_channel_member(channel_1_2, user_2, user_1, ChannelRole::Member)
203 .await
204 .unwrap();
205 db.invite_channel_member(channel_1_1, user_3, user_1, ChannelRole::Admin)
206 .await
207 .unwrap();
208
209 let user_2_invites = db
210 .get_channel_invites_for_user(user_2) // -> [channel_1_1, channel_1_2]
211 .await
212 .unwrap()
213 .into_iter()
214 .map(|channel| channel.id)
215 .collect::<Vec<_>>();
216
217 assert_eq!(user_2_invites, &[channel_1_1, channel_1_2]);
218
219 let user_3_invites = db
220 .get_channel_invites_for_user(user_3) // -> [channel_1_1]
221 .await
222 .unwrap()
223 .into_iter()
224 .map(|channel| channel.id)
225 .collect::<Vec<_>>();
226
227 assert_eq!(user_3_invites, &[channel_1_1]);
228
229 let mut members = db
230 .get_channel_participant_details(channel_1_1, user_1)
231 .await
232 .unwrap();
233
234 members.sort_by_key(|member| member.user_id);
235 assert_eq!(
236 members,
237 &[
238 proto::ChannelMember {
239 user_id: user_1.to_proto(),
240 kind: proto::channel_member::Kind::Member.into(),
241 role: proto::ChannelRole::Admin.into(),
242 },
243 proto::ChannelMember {
244 user_id: user_2.to_proto(),
245 kind: proto::channel_member::Kind::Invitee.into(),
246 role: proto::ChannelRole::Member.into(),
247 },
248 proto::ChannelMember {
249 user_id: user_3.to_proto(),
250 kind: proto::channel_member::Kind::Invitee.into(),
251 role: proto::ChannelRole::Admin.into(),
252 },
253 ]
254 );
255
256 db.respond_to_channel_invite(channel_1_1, user_2, true)
257 .await
258 .unwrap();
259
260 let channel_1_3 = db
261 .create_sub_channel("channel_3", channel_1_1, user_1)
262 .await
263 .unwrap();
264
265 let members = db
266 .get_channel_participant_details(channel_1_3, user_1)
267 .await
268 .unwrap();
269 assert_eq!(
270 members,
271 &[
272 proto::ChannelMember {
273 user_id: user_1.to_proto(),
274 kind: proto::channel_member::Kind::AncestorMember.into(),
275 role: proto::ChannelRole::Admin.into(),
276 },
277 proto::ChannelMember {
278 user_id: user_2.to_proto(),
279 kind: proto::channel_member::Kind::AncestorMember.into(),
280 role: proto::ChannelRole::Member.into(),
281 },
282 ]
283 );
284}
285
286test_both_dbs!(
287 test_channel_renames,
288 test_channel_renames_postgres,
289 test_channel_renames_sqlite
290);
291
292async fn test_channel_renames(db: &Arc<Database>) {
293 db.create_server("test").await.unwrap();
294
295 let user_1 = db
296 .create_user(
297 "user1@example.com",
298 false,
299 NewUserParams {
300 github_login: "user1".into(),
301 github_user_id: 5,
302 },
303 )
304 .await
305 .unwrap()
306 .user_id;
307
308 let user_2 = db
309 .create_user(
310 "user2@example.com",
311 false,
312 NewUserParams {
313 github_login: "user2".into(),
314 github_user_id: 6,
315 },
316 )
317 .await
318 .unwrap()
319 .user_id;
320
321 let zed_id = db.create_root_channel("zed", user_1).await.unwrap();
322
323 db.rename_channel(zed_id, user_1, "#zed-archive")
324 .await
325 .unwrap();
326
327 let channel = db.get_channel(zed_id, user_1).await.unwrap();
328 assert_eq!(channel.name, "zed-archive");
329
330 let non_permissioned_rename = db.rename_channel(zed_id, user_2, "hacked-lol").await;
331 assert!(non_permissioned_rename.is_err());
332
333 let bad_name_rename = db.rename_channel(zed_id, user_1, "#").await;
334 assert!(bad_name_rename.is_err())
335}
336
337test_both_dbs!(
338 test_db_channel_moving,
339 test_channels_moving_postgres,
340 test_channels_moving_sqlite
341);
342
343async fn test_db_channel_moving(db: &Arc<Database>) {
344 let a_id = db
345 .create_user(
346 "user1@example.com",
347 false,
348 NewUserParams {
349 github_login: "user1".into(),
350 github_user_id: 5,
351 },
352 )
353 .await
354 .unwrap()
355 .user_id;
356
357 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
358
359 let crdb_id = db.create_sub_channel("crdb", zed_id, a_id).await.unwrap();
360
361 let gpui2_id = db.create_sub_channel("gpui2", zed_id, a_id).await.unwrap();
362
363 let livestreaming_id = db
364 .create_sub_channel("livestreaming", crdb_id, a_id)
365 .await
366 .unwrap();
367
368 let livestreaming_dag_id = db
369 .create_sub_channel("livestreaming_dag", livestreaming_id, a_id)
370 .await
371 .unwrap();
372
373 // ========================================================================
374 // sanity check
375 // Initial DAG:
376 // /- gpui2
377 // zed -- crdb - livestreaming - livestreaming_dag
378 let result = db.get_channels_for_user(a_id).await.unwrap();
379 assert_channel_tree(
380 result.channels,
381 &[
382 (zed_id, &[]),
383 (crdb_id, &[zed_id]),
384 (livestreaming_id, &[zed_id, crdb_id]),
385 (livestreaming_dag_id, &[zed_id, crdb_id, livestreaming_id]),
386 (gpui2_id, &[zed_id]),
387 ],
388 );
389}
390
391test_both_dbs!(
392 test_db_channel_moving_bugs,
393 test_db_channel_moving_bugs_postgres,
394 test_db_channel_moving_bugs_sqlite
395);
396
397async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
398 let user_id = db
399 .create_user(
400 "user1@example.com",
401 false,
402 NewUserParams {
403 github_login: "user1".into(),
404 github_user_id: 5,
405 },
406 )
407 .await
408 .unwrap()
409 .user_id;
410
411 let zed_id = db.create_root_channel("zed", user_id).await.unwrap();
412
413 let projects_id = db
414 .create_sub_channel("projects", zed_id, user_id)
415 .await
416 .unwrap();
417
418 let livestreaming_id = db
419 .create_sub_channel("livestreaming", projects_id, user_id)
420 .await
421 .unwrap();
422
423 // Dag is: zed - projects - livestreaming
424
425 // Move to same parent should be a no-op
426 assert!(db
427 .move_channel(projects_id, Some(zed_id), user_id)
428 .await
429 .unwrap()
430 .is_none());
431
432 let result = db.get_channels_for_user(user_id).await.unwrap();
433 assert_channel_tree(
434 result.channels,
435 &[
436 (zed_id, &[]),
437 (projects_id, &[zed_id]),
438 (livestreaming_id, &[zed_id, projects_id]),
439 ],
440 );
441
442 // Move the project channel to the root
443 db.move_channel(projects_id, None, user_id).await.unwrap();
444 let result = db.get_channels_for_user(user_id).await.unwrap();
445 assert_channel_tree(
446 result.channels,
447 &[
448 (zed_id, &[]),
449 (projects_id, &[]),
450 (livestreaming_id, &[projects_id]),
451 ],
452 );
453
454 // Can't move a channel into its ancestor
455 db.move_channel(projects_id, Some(livestreaming_id), user_id)
456 .await
457 .unwrap_err();
458 let result = db.get_channels_for_user(user_id).await.unwrap();
459 assert_channel_tree(
460 result.channels,
461 &[
462 (zed_id, &[]),
463 (projects_id, &[]),
464 (livestreaming_id, &[projects_id]),
465 ],
466 );
467}
468
469test_both_dbs!(
470 test_user_is_channel_participant,
471 test_user_is_channel_participant_postgres,
472 test_user_is_channel_participant_sqlite
473);
474
475async fn test_user_is_channel_participant(db: &Arc<Database>) {
476 let admin = new_test_user(db, "admin@example.com").await;
477 let member = new_test_user(db, "member@example.com").await;
478 let guest = new_test_user(db, "guest@example.com").await;
479
480 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
481 let active_channel_id = db
482 .create_sub_channel("active", zed_channel, admin)
483 .await
484 .unwrap();
485 let vim_channel_id = db
486 .create_sub_channel("vim", active_channel_id, admin)
487 .await
488 .unwrap();
489
490 db.set_channel_visibility(vim_channel_id, crate::db::ChannelVisibility::Public, admin)
491 .await
492 .unwrap();
493 db.invite_channel_member(active_channel_id, member, admin, ChannelRole::Member)
494 .await
495 .unwrap();
496 db.invite_channel_member(vim_channel_id, guest, admin, ChannelRole::Guest)
497 .await
498 .unwrap();
499
500 db.respond_to_channel_invite(active_channel_id, member, true)
501 .await
502 .unwrap();
503
504 db.transaction(|tx| async move {
505 db.check_user_is_channel_participant(
506 &db.get_channel_internal(vim_channel_id, &*tx).await?,
507 admin,
508 &*tx,
509 )
510 .await
511 })
512 .await
513 .unwrap();
514 db.transaction(|tx| async move {
515 db.check_user_is_channel_participant(
516 &db.get_channel_internal(vim_channel_id, &*tx).await?,
517 member,
518 &*tx,
519 )
520 .await
521 })
522 .await
523 .unwrap();
524
525 let mut members = db
526 .get_channel_participant_details(vim_channel_id, admin)
527 .await
528 .unwrap();
529
530 members.sort_by_key(|member| member.user_id);
531
532 assert_eq!(
533 members,
534 &[
535 proto::ChannelMember {
536 user_id: admin.to_proto(),
537 kind: proto::channel_member::Kind::AncestorMember.into(),
538 role: proto::ChannelRole::Admin.into(),
539 },
540 proto::ChannelMember {
541 user_id: member.to_proto(),
542 kind: proto::channel_member::Kind::AncestorMember.into(),
543 role: proto::ChannelRole::Member.into(),
544 },
545 proto::ChannelMember {
546 user_id: guest.to_proto(),
547 kind: proto::channel_member::Kind::Invitee.into(),
548 role: proto::ChannelRole::Guest.into(),
549 },
550 ]
551 );
552
553 db.respond_to_channel_invite(vim_channel_id, guest, true)
554 .await
555 .unwrap();
556
557 db.transaction(|tx| async move {
558 db.check_user_is_channel_participant(
559 &db.get_channel_internal(vim_channel_id, &*tx).await?,
560 guest,
561 &*tx,
562 )
563 .await
564 })
565 .await
566 .unwrap();
567
568 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
569 assert_channel_tree(channels, &[(vim_channel_id, &[])]);
570 let channels = db.get_channels_for_user(member).await.unwrap().channels;
571 assert_channel_tree(
572 channels,
573 &[
574 (active_channel_id, &[]),
575 (vim_channel_id, &[active_channel_id]),
576 ],
577 );
578
579 db.set_channel_member_role(vim_channel_id, admin, guest, ChannelRole::Banned)
580 .await
581 .unwrap();
582 assert!(db
583 .transaction(|tx| async move {
584 db.check_user_is_channel_participant(
585 &db.get_channel_internal(vim_channel_id, &*tx).await.unwrap(),
586 guest,
587 &*tx,
588 )
589 .await
590 })
591 .await
592 .is_err());
593
594 let mut members = db
595 .get_channel_participant_details(vim_channel_id, admin)
596 .await
597 .unwrap();
598
599 members.sort_by_key(|member| member.user_id);
600
601 assert_eq!(
602 members,
603 &[
604 proto::ChannelMember {
605 user_id: admin.to_proto(),
606 kind: proto::channel_member::Kind::AncestorMember.into(),
607 role: proto::ChannelRole::Admin.into(),
608 },
609 proto::ChannelMember {
610 user_id: member.to_proto(),
611 kind: proto::channel_member::Kind::AncestorMember.into(),
612 role: proto::ChannelRole::Member.into(),
613 },
614 proto::ChannelMember {
615 user_id: guest.to_proto(),
616 kind: proto::channel_member::Kind::Member.into(),
617 role: proto::ChannelRole::Banned.into(),
618 },
619 ]
620 );
621
622 db.remove_channel_member(vim_channel_id, guest, admin)
623 .await
624 .unwrap();
625
626 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
627 .await
628 .unwrap();
629
630 db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
631 .await
632 .unwrap();
633
634 // currently people invited to parent channels are not shown here
635 let mut members = db
636 .get_channel_participant_details(vim_channel_id, admin)
637 .await
638 .unwrap();
639
640 members.sort_by_key(|member| member.user_id);
641
642 assert_eq!(
643 members,
644 &[
645 proto::ChannelMember {
646 user_id: admin.to_proto(),
647 kind: proto::channel_member::Kind::AncestorMember.into(),
648 role: proto::ChannelRole::Admin.into(),
649 },
650 proto::ChannelMember {
651 user_id: member.to_proto(),
652 kind: proto::channel_member::Kind::AncestorMember.into(),
653 role: proto::ChannelRole::Member.into(),
654 },
655 ]
656 );
657
658 db.respond_to_channel_invite(zed_channel, guest, true)
659 .await
660 .unwrap();
661
662 db.transaction(|tx| async move {
663 db.check_user_is_channel_participant(
664 &db.get_channel_internal(zed_channel, &*tx).await.unwrap(),
665 guest,
666 &*tx,
667 )
668 .await
669 })
670 .await
671 .unwrap();
672 assert!(db
673 .transaction(|tx| async move {
674 db.check_user_is_channel_participant(
675 &db.get_channel_internal(active_channel_id, &*tx)
676 .await
677 .unwrap(),
678 guest,
679 &*tx,
680 )
681 .await
682 })
683 .await
684 .is_err(),);
685
686 db.transaction(|tx| async move {
687 db.check_user_is_channel_participant(
688 &db.get_channel_internal(vim_channel_id, &*tx).await.unwrap(),
689 guest,
690 &*tx,
691 )
692 .await
693 })
694 .await
695 .unwrap();
696
697 let mut members = db
698 .get_channel_participant_details(vim_channel_id, admin)
699 .await
700 .unwrap();
701
702 members.sort_by_key(|member| member.user_id);
703
704 assert_eq!(
705 members,
706 &[
707 proto::ChannelMember {
708 user_id: admin.to_proto(),
709 kind: proto::channel_member::Kind::AncestorMember.into(),
710 role: proto::ChannelRole::Admin.into(),
711 },
712 proto::ChannelMember {
713 user_id: member.to_proto(),
714 kind: proto::channel_member::Kind::AncestorMember.into(),
715 role: proto::ChannelRole::Member.into(),
716 },
717 proto::ChannelMember {
718 user_id: guest.to_proto(),
719 kind: proto::channel_member::Kind::AncestorMember.into(),
720 role: proto::ChannelRole::Guest.into(),
721 },
722 ]
723 );
724
725 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
726 assert_channel_tree(
727 channels,
728 &[(zed_channel, &[]), (vim_channel_id, &[zed_channel])],
729 )
730}
731
732test_both_dbs!(
733 test_user_joins_correct_channel,
734 test_user_joins_correct_channel_postgres,
735 test_user_joins_correct_channel_sqlite
736);
737
738async fn test_user_joins_correct_channel(db: &Arc<Database>) {
739 let admin = new_test_user(db, "admin@example.com").await;
740
741 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
742
743 let active_channel = db
744 .create_sub_channel("active", zed_channel, admin)
745 .await
746 .unwrap();
747
748 let vim_channel = db
749 .create_sub_channel("vim", active_channel, admin)
750 .await
751 .unwrap();
752
753 let vim2_channel = db
754 .create_sub_channel("vim2", vim_channel, admin)
755 .await
756 .unwrap();
757
758 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
759 .await
760 .unwrap();
761
762 db.set_channel_visibility(vim_channel, crate::db::ChannelVisibility::Public, admin)
763 .await
764 .unwrap();
765
766 db.set_channel_visibility(vim2_channel, crate::db::ChannelVisibility::Public, admin)
767 .await
768 .unwrap();
769
770 let most_public = db
771 .transaction(|tx| async move {
772 Ok(db
773 .public_ancestors_including_self(
774 &db.get_channel_internal(vim_channel, &*tx).await.unwrap(),
775 &tx,
776 )
777 .await?
778 .first()
779 .cloned())
780 })
781 .await
782 .unwrap()
783 .unwrap()
784 .id;
785
786 assert_eq!(most_public, zed_channel)
787}
788
789test_both_dbs!(
790 test_guest_access,
791 test_guest_access_postgres,
792 test_guest_access_sqlite
793);
794
795async fn test_guest_access(db: &Arc<Database>) {
796 let server = db.create_server("test").await.unwrap();
797
798 let admin = new_test_user(db, "admin@example.com").await;
799 let guest = new_test_user(db, "guest@example.com").await;
800 let guest_connection = new_test_connection(server);
801
802 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
803 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
804 .await
805 .unwrap();
806
807 assert!(db
808 .join_channel_chat(zed_channel, guest_connection, guest)
809 .await
810 .is_err());
811
812 db.join_channel(zed_channel, guest, guest_connection, TEST_RELEASE_CHANNEL)
813 .await
814 .unwrap();
815
816 assert!(db
817 .join_channel_chat(zed_channel, guest_connection, guest)
818 .await
819 .is_ok())
820}
821
822#[track_caller]
823fn assert_channel_tree(actual: Vec<Channel>, expected: &[(ChannelId, &[ChannelId])]) {
824 let actual = actual
825 .iter()
826 .map(|channel| (channel.id, channel.parent_path.as_slice()))
827 .collect::<Vec<_>>();
828 pretty_assertions::assert_eq!(
829 actual,
830 expected.to_vec(),
831 "wrong channel ids and parent paths"
832 );
833}