channel_tests.rs

  1use super::{assert_channel_tree_matches, channel_tree, new_test_user};
  2use crate::test_both_dbs;
  3use collab::db::{Channel, ChannelId, ChannelRole, Database, NewUserParams, RoomId, UserId};
  4use rpc::{
  5    ConnectionId,
  6    proto::{self, reorder_channel},
  7};
  8use std::{collections::HashSet, sync::Arc};
  9
 10test_both_dbs!(test_channels, test_channels_postgres, test_channels_sqlite);
 11
 12async fn test_channels(db: &Arc<Database>) {
 13    let a_id = new_test_user(db, "user1@example.com").await;
 14    let b_id = new_test_user(db, "user2@example.com").await;
 15
 16    let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
 17
 18    // Make sure that people cannot read channels they haven't been invited to
 19    assert!(db.get_channel(zed_id, b_id).await.is_err());
 20
 21    db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
 22        .await
 23        .unwrap();
 24
 25    db.respond_to_channel_invite(zed_id, b_id, true)
 26        .await
 27        .unwrap();
 28
 29    let crdb_id = db.create_sub_channel("crdb", zed_id, a_id).await.unwrap();
 30    let livestreaming_id = db
 31        .create_sub_channel("livestreaming", zed_id, a_id)
 32        .await
 33        .unwrap();
 34    let replace_id = db
 35        .create_sub_channel("replace", zed_id, a_id)
 36        .await
 37        .unwrap();
 38
 39    let (members, _) = db
 40        .get_channel_participant_details(replace_id, "", 10, a_id)
 41        .await
 42        .unwrap();
 43    let ids = members
 44        .into_iter()
 45        .map(|m| UserId::from_proto(m.user_id))
 46        .collect::<Vec<_>>();
 47    assert_eq!(ids, &[a_id, b_id]);
 48
 49    let rust_id = db.create_root_channel("rust", a_id).await.unwrap();
 50    let cargo_id = db.create_sub_channel("cargo", rust_id, a_id).await.unwrap();
 51
 52    let cargo_ra_id = db
 53        .create_sub_channel("cargo-ra", cargo_id, a_id)
 54        .await
 55        .unwrap();
 56
 57    let result = db.get_channels_for_user(a_id).await.unwrap();
 58    assert_channel_tree_matches(
 59        result.channels,
 60        channel_tree(&[
 61            (zed_id, &[], "zed"),
 62            (crdb_id, &[zed_id], "crdb"),
 63            (livestreaming_id, &[zed_id], "livestreaming"),
 64            (replace_id, &[zed_id], "replace"),
 65            (rust_id, &[], "rust"),
 66            (cargo_id, &[rust_id], "cargo"),
 67            (cargo_ra_id, &[rust_id, cargo_id], "cargo-ra"),
 68        ]),
 69    );
 70
 71    let result = db.get_channels_for_user(b_id).await.unwrap();
 72    assert_channel_tree_matches(
 73        result.channels,
 74        channel_tree(&[
 75            (zed_id, &[], "zed"),
 76            (crdb_id, &[zed_id], "crdb"),
 77            (livestreaming_id, &[zed_id], "livestreaming"),
 78            (replace_id, &[zed_id], "replace"),
 79        ]),
 80    );
 81
 82    // Update member permissions
 83    let set_subchannel_admin = db
 84        .set_channel_member_role(crdb_id, a_id, b_id, ChannelRole::Admin)
 85        .await;
 86    assert!(set_subchannel_admin.is_err());
 87    let set_channel_admin = db
 88        .set_channel_member_role(zed_id, a_id, b_id, ChannelRole::Admin)
 89        .await;
 90    assert!(set_channel_admin.is_ok());
 91
 92    let result = db.get_channels_for_user(b_id).await.unwrap();
 93    assert_channel_tree_matches(
 94        result.channels,
 95        channel_tree(&[
 96            (zed_id, &[], "zed"),
 97            (crdb_id, &[zed_id], "crdb"),
 98            (livestreaming_id, &[zed_id], "livestreaming"),
 99            (replace_id, &[zed_id], "replace"),
100        ]),
101    );
102
103    // Remove a single channel
104    db.delete_channel(crdb_id, a_id).await.unwrap();
105    assert!(db.get_channel(crdb_id, a_id).await.is_err());
106
107    // Remove a channel tree
108    let (_, mut channel_ids) = db.delete_channel(rust_id, a_id).await.unwrap();
109    channel_ids.sort();
110    assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
111
112    assert!(db.get_channel(rust_id, a_id).await.is_err());
113    assert!(db.get_channel(cargo_id, a_id).await.is_err());
114    assert!(db.get_channel(cargo_ra_id, a_id).await.is_err());
115}
116
117test_both_dbs!(
118    test_joining_channels,
119    test_joining_channels_postgres,
120    test_joining_channels_sqlite
121);
122
123async fn test_joining_channels(db: &Arc<Database>) {
124    let owner_id = db.create_server("test").await.unwrap().0 as u32;
125
126    let user_1 = new_test_user(db, "user1@example.com").await;
127    let user_2 = new_test_user(db, "user2@example.com").await;
128
129    let channel_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
130
131    // can join a room with membership to its channel
132    let (joined_room, _, _) = db
133        .join_channel(channel_1, user_1, ConnectionId { owner_id, id: 1 })
134        .await
135        .unwrap();
136    assert_eq!(joined_room.room.participants.len(), 1);
137
138    let room_id = RoomId::from_proto(joined_room.room.id);
139    drop(joined_room);
140    // cannot join a room without membership to its channel
141    assert!(
142        db.join_room(room_id, user_2, ConnectionId { owner_id, id: 1 },)
143            .await
144            .is_err()
145    );
146}
147
148test_both_dbs!(
149    test_channel_invites,
150    test_channel_invites_postgres,
151    test_channel_invites_sqlite
152);
153
154async fn test_channel_invites(db: &Arc<Database>) {
155    db.create_server("test").await.unwrap();
156
157    let user_1 = new_test_user(db, "user1@example.com").await;
158    let user_2 = new_test_user(db, "user2@example.com").await;
159    let user_3 = new_test_user(db, "user3@example.com").await;
160
161    let channel_1_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
162
163    let channel_1_2 = db.create_root_channel("channel_2", user_1).await.unwrap();
164
165    db.invite_channel_member(channel_1_1, user_2, user_1, ChannelRole::Member)
166        .await
167        .unwrap();
168    db.invite_channel_member(channel_1_2, user_2, user_1, ChannelRole::Member)
169        .await
170        .unwrap();
171    db.invite_channel_member(channel_1_1, user_3, user_1, ChannelRole::Admin)
172        .await
173        .unwrap();
174
175    let user_2_invites = db
176        .get_channels_for_user(user_2)
177        .await
178        .unwrap()
179        .invited_channels
180        .into_iter()
181        .map(|channel| channel.id)
182        .collect::<Vec<_>>();
183    assert_eq!(user_2_invites, &[channel_1_1, channel_1_2]);
184
185    let user_3_invites = db
186        .get_channels_for_user(user_3)
187        .await
188        .unwrap()
189        .invited_channels
190        .into_iter()
191        .map(|channel| channel.id)
192        .collect::<Vec<_>>();
193    assert_eq!(user_3_invites, &[channel_1_1]);
194
195    let (mut members, _) = db
196        .get_channel_participant_details(channel_1_1, "", 100, user_1)
197        .await
198        .unwrap();
199
200    members.sort_by_key(|member| member.user_id);
201    assert_eq!(
202        members,
203        &[
204            proto::ChannelMember {
205                user_id: user_1.to_proto(),
206                kind: proto::channel_member::Kind::Member.into(),
207                role: proto::ChannelRole::Admin.into(),
208            },
209            proto::ChannelMember {
210                user_id: user_2.to_proto(),
211                kind: proto::channel_member::Kind::Invitee.into(),
212                role: proto::ChannelRole::Member.into(),
213            },
214            proto::ChannelMember {
215                user_id: user_3.to_proto(),
216                kind: proto::channel_member::Kind::Invitee.into(),
217                role: proto::ChannelRole::Admin.into(),
218            },
219        ]
220    );
221
222    db.respond_to_channel_invite(channel_1_1, user_2, true)
223        .await
224        .unwrap();
225
226    let channel_1_3 = db
227        .create_sub_channel("channel_3", channel_1_1, user_1)
228        .await
229        .unwrap();
230
231    let (members, _) = db
232        .get_channel_participant_details(channel_1_3, "", 100, user_1)
233        .await
234        .unwrap();
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_3.to_proto(),
245                kind: proto::channel_member::Kind::Invitee.into(),
246                role: proto::ChannelRole::Admin.into(),
247            },
248            proto::ChannelMember {
249                user_id: user_2.to_proto(),
250                kind: proto::channel_member::Kind::Member.into(),
251                role: proto::ChannelRole::Member.into(),
252            },
253        ]
254    );
255}
256
257test_both_dbs!(
258    test_channel_renames,
259    test_channel_renames_postgres,
260    test_channel_renames_sqlite
261);
262
263async fn test_channel_renames(db: &Arc<Database>) {
264    db.create_server("test").await.unwrap();
265
266    let user_1 = db
267        .create_user(
268            "user1@example.com",
269            None,
270            false,
271            NewUserParams {
272                github_login: "user1".into(),
273                github_user_id: 5,
274            },
275        )
276        .await
277        .unwrap()
278        .user_id;
279
280    let user_2 = db
281        .create_user(
282            "user2@example.com",
283            None,
284            false,
285            NewUserParams {
286                github_login: "user2".into(),
287                github_user_id: 6,
288            },
289        )
290        .await
291        .unwrap()
292        .user_id;
293
294    let zed_id = db.create_root_channel("zed", user_1).await.unwrap();
295
296    db.rename_channel(zed_id, user_1, "#zed-archive")
297        .await
298        .unwrap();
299
300    let channel = db.get_channel(zed_id, user_1).await.unwrap();
301    assert_eq!(channel.name, "zed-archive");
302
303    let non_permissioned_rename = db.rename_channel(zed_id, user_2, "hacked-lol").await;
304    assert!(non_permissioned_rename.is_err());
305
306    let bad_name_rename = db.rename_channel(zed_id, user_1, "#").await;
307    assert!(bad_name_rename.is_err())
308}
309
310test_both_dbs!(
311    test_db_channel_moving,
312    test_db_channel_moving_postgres,
313    test_db_channel_moving_sqlite
314);
315
316async fn test_db_channel_moving(db: &Arc<Database>) {
317    let a_id = db
318        .create_user(
319            "user1@example.com",
320            None,
321            false,
322            NewUserParams {
323                github_login: "user1".into(),
324                github_user_id: 5,
325            },
326        )
327        .await
328        .unwrap()
329        .user_id;
330
331    let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
332
333    let crdb_id = db.create_sub_channel("crdb", zed_id, a_id).await.unwrap();
334
335    let gpui2_id = db.create_sub_channel("gpui2", zed_id, a_id).await.unwrap();
336
337    let livestreaming_id = db
338        .create_sub_channel("livestreaming", crdb_id, a_id)
339        .await
340        .unwrap();
341
342    let livestreaming_sub_id = db
343        .create_sub_channel("livestreaming_sub", livestreaming_id, a_id)
344        .await
345        .unwrap();
346
347    // sanity check
348    //     /- gpui2
349    // zed -- crdb - livestreaming - livestreaming_sub
350    let result = db.get_channels_for_user(a_id).await.unwrap();
351    assert_channel_tree(
352        result.channels,
353        &[
354            (zed_id, &[]),
355            (crdb_id, &[zed_id]),
356            (livestreaming_id, &[zed_id, crdb_id]),
357            (livestreaming_sub_id, &[zed_id, crdb_id, livestreaming_id]),
358            (gpui2_id, &[zed_id]),
359        ],
360    );
361
362    // Check that we can do a simple leaf -> leaf move
363    db.move_channel(livestreaming_sub_id, crdb_id, a_id)
364        .await
365        .unwrap();
366
367    //     /- gpui2
368    // zed -- crdb -- livestreaming
369    //             \- livestreaming_sub
370    let result = db.get_channels_for_user(a_id).await.unwrap();
371    assert_channel_tree(
372        result.channels,
373        &[
374            (zed_id, &[]),
375            (crdb_id, &[zed_id]),
376            (livestreaming_id, &[zed_id, crdb_id]),
377            (livestreaming_sub_id, &[zed_id, crdb_id]),
378            (gpui2_id, &[zed_id]),
379        ],
380    );
381
382    // Check that we can move a whole subtree at once
383    db.move_channel(crdb_id, gpui2_id, a_id).await.unwrap();
384
385    // zed -- gpui2 -- crdb -- livestreaming
386    //                      \- livestreaming_sub
387    let result = db.get_channels_for_user(a_id).await.unwrap();
388    assert_channel_tree(
389        result.channels,
390        &[
391            (zed_id, &[]),
392            (gpui2_id, &[zed_id]),
393            (crdb_id, &[zed_id, gpui2_id]),
394            (livestreaming_id, &[zed_id, gpui2_id, crdb_id]),
395            (livestreaming_sub_id, &[zed_id, gpui2_id, crdb_id]),
396        ],
397    );
398}
399
400test_both_dbs!(
401    test_channel_reordering,
402    test_channel_reordering_postgres,
403    test_channel_reordering_sqlite
404);
405
406async fn test_channel_reordering(db: &Arc<Database>) {
407    let admin_id = db
408        .create_user(
409            "admin@example.com",
410            None,
411            false,
412            NewUserParams {
413                github_login: "admin".into(),
414                github_user_id: 1,
415            },
416        )
417        .await
418        .unwrap()
419        .user_id;
420
421    let user_id = db
422        .create_user(
423            "user@example.com",
424            None,
425            false,
426            NewUserParams {
427                github_login: "user".into(),
428                github_user_id: 2,
429            },
430        )
431        .await
432        .unwrap()
433        .user_id;
434
435    // Create a root channel with some sub-channels
436    let root_id = db.create_root_channel("root", admin_id).await.unwrap();
437
438    // Invite user to root channel so they can see the sub-channels
439    db.invite_channel_member(root_id, user_id, admin_id, ChannelRole::Member)
440        .await
441        .unwrap();
442    db.respond_to_channel_invite(root_id, user_id, true)
443        .await
444        .unwrap();
445
446    let alpha_id = db
447        .create_sub_channel("alpha", root_id, admin_id)
448        .await
449        .unwrap();
450    let beta_id = db
451        .create_sub_channel("beta", root_id, admin_id)
452        .await
453        .unwrap();
454    let gamma_id = db
455        .create_sub_channel("gamma", root_id, admin_id)
456        .await
457        .unwrap();
458
459    // Initial order should be: root, alpha (order=1), beta (order=2), gamma (order=3)
460    let result = db.get_channels_for_user(admin_id).await.unwrap();
461    assert_channel_tree_order(
462        result.channels,
463        &[
464            (root_id, &[], 1),
465            (alpha_id, &[root_id], 1),
466            (beta_id, &[root_id], 2),
467            (gamma_id, &[root_id], 3),
468        ],
469    );
470
471    // Test moving beta up (should swap with alpha)
472    let updated_channels = db
473        .reorder_channel(beta_id, reorder_channel::Direction::Up, admin_id)
474        .await
475        .unwrap();
476
477    // Verify that beta and alpha were returned as updated
478    assert_eq!(updated_channels.len(), 2);
479    let updated_ids: std::collections::HashSet<_> = updated_channels.iter().map(|c| c.id).collect();
480    assert!(updated_ids.contains(&alpha_id));
481    assert!(updated_ids.contains(&beta_id));
482
483    // Now order should be: root, beta (order=1), alpha (order=2), gamma (order=3)
484    let result = db.get_channels_for_user(admin_id).await.unwrap();
485    assert_channel_tree_order(
486        result.channels,
487        &[
488            (root_id, &[], 1),
489            (beta_id, &[root_id], 1),
490            (alpha_id, &[root_id], 2),
491            (gamma_id, &[root_id], 3),
492        ],
493    );
494
495    // Test moving gamma down (should be no-op since it's already last)
496    let updated_channels = db
497        .reorder_channel(gamma_id, reorder_channel::Direction::Down, admin_id)
498        .await
499        .unwrap();
500
501    // Should return just nothing
502    assert_eq!(updated_channels.len(), 0);
503
504    // Test moving alpha down (should swap with gamma)
505    let updated_channels = db
506        .reorder_channel(alpha_id, reorder_channel::Direction::Down, admin_id)
507        .await
508        .unwrap();
509
510    // Verify that alpha and gamma were returned as updated
511    assert_eq!(updated_channels.len(), 2);
512    let updated_ids: std::collections::HashSet<_> = updated_channels.iter().map(|c| c.id).collect();
513    assert!(updated_ids.contains(&alpha_id));
514    assert!(updated_ids.contains(&gamma_id));
515
516    // Now order should be: root, beta (order=1), gamma (order=2), alpha (order=3)
517    let result = db.get_channels_for_user(admin_id).await.unwrap();
518    assert_channel_tree_order(
519        result.channels,
520        &[
521            (root_id, &[], 1),
522            (beta_id, &[root_id], 1),
523            (gamma_id, &[root_id], 2),
524            (alpha_id, &[root_id], 3),
525        ],
526    );
527
528    // Test that non-admin cannot reorder
529    let reorder_result = db
530        .reorder_channel(beta_id, reorder_channel::Direction::Up, user_id)
531        .await;
532    assert!(reorder_result.is_err());
533
534    // Test moving beta up (should be no-op since it's already first)
535    let updated_channels = db
536        .reorder_channel(beta_id, reorder_channel::Direction::Up, admin_id)
537        .await
538        .unwrap();
539
540    // Should return nothing
541    assert_eq!(updated_channels.len(), 0);
542
543    // Adding a channel to an existing ordering should add it to the end
544    let delta_id = db
545        .create_sub_channel("delta", root_id, admin_id)
546        .await
547        .unwrap();
548
549    let result = db.get_channels_for_user(admin_id).await.unwrap();
550    assert_channel_tree_order(
551        result.channels,
552        &[
553            (root_id, &[], 1),
554            (beta_id, &[root_id], 1),
555            (gamma_id, &[root_id], 2),
556            (alpha_id, &[root_id], 3),
557            (delta_id, &[root_id], 4),
558        ],
559    );
560
561    // And moving a channel into an existing ordering should add it to the end
562    let eta_id = db
563        .create_sub_channel("eta", delta_id, admin_id)
564        .await
565        .unwrap();
566
567    let result = db.get_channels_for_user(admin_id).await.unwrap();
568    assert_channel_tree_order(
569        result.channels,
570        &[
571            (root_id, &[], 1),
572            (beta_id, &[root_id], 1),
573            (gamma_id, &[root_id], 2),
574            (alpha_id, &[root_id], 3),
575            (delta_id, &[root_id], 4),
576            (eta_id, &[root_id, delta_id], 1),
577        ],
578    );
579
580    db.move_channel(eta_id, root_id, admin_id).await.unwrap();
581    let result = db.get_channels_for_user(admin_id).await.unwrap();
582    assert_channel_tree_order(
583        result.channels,
584        &[
585            (root_id, &[], 1),
586            (beta_id, &[root_id], 1),
587            (gamma_id, &[root_id], 2),
588            (alpha_id, &[root_id], 3),
589            (delta_id, &[root_id], 4),
590            (eta_id, &[root_id], 5),
591        ],
592    );
593}
594
595test_both_dbs!(
596    test_db_channel_moving_bugs,
597    test_db_channel_moving_bugs_postgres,
598    test_db_channel_moving_bugs_sqlite
599);
600
601async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
602    let user_id = db
603        .create_user(
604            "user1@example.com",
605            None,
606            false,
607            NewUserParams {
608                github_login: "user1".into(),
609                github_user_id: 5,
610            },
611        )
612        .await
613        .unwrap()
614        .user_id;
615
616    let zed_id = db.create_root_channel("zed", user_id).await.unwrap();
617
618    let projects_id = db
619        .create_sub_channel("projects", zed_id, user_id)
620        .await
621        .unwrap();
622
623    let livestreaming_id = db
624        .create_sub_channel("livestreaming", projects_id, user_id)
625        .await
626        .unwrap();
627
628    let result = db.get_channels_for_user(user_id).await.unwrap();
629    assert_channel_tree(
630        result.channels,
631        &[
632            (zed_id, &[]),
633            (projects_id, &[zed_id]),
634            (livestreaming_id, &[zed_id, projects_id]),
635        ],
636    );
637
638    // Can't move a channel into its ancestor
639    db.move_channel(projects_id, livestreaming_id, user_id)
640        .await
641        .unwrap_err();
642    let result = db.get_channels_for_user(user_id).await.unwrap();
643    assert_channel_tree(
644        result.channels,
645        &[
646            (zed_id, &[]),
647            (projects_id, &[zed_id]),
648            (livestreaming_id, &[zed_id, projects_id]),
649        ],
650    );
651
652    // Can't un-root a root channel
653    db.move_channel(zed_id, livestreaming_id, user_id)
654        .await
655        .unwrap_err();
656    let result = db.get_channels_for_user(user_id).await.unwrap();
657    assert_channel_tree(
658        result.channels,
659        &[
660            (zed_id, &[]),
661            (projects_id, &[zed_id]),
662            (livestreaming_id, &[zed_id, projects_id]),
663        ],
664    );
665}
666
667test_both_dbs!(
668    test_user_is_channel_participant,
669    test_user_is_channel_participant_postgres,
670    test_user_is_channel_participant_sqlite
671);
672
673async fn test_user_is_channel_participant(db: &Arc<Database>) {
674    let admin = new_test_user(db, "admin@example.com").await;
675    let member = new_test_user(db, "member@example.com").await;
676    let guest = new_test_user(db, "guest@example.com").await;
677
678    let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
679    let internal_channel_id = db
680        .create_sub_channel("active", zed_channel, admin)
681        .await
682        .unwrap();
683    let public_channel_id = db
684        .create_sub_channel("vim", zed_channel, admin)
685        .await
686        .unwrap();
687
688    db.set_channel_visibility(zed_channel, collab::db::ChannelVisibility::Public, admin)
689        .await
690        .unwrap();
691    db.set_channel_visibility(
692        public_channel_id,
693        collab::db::ChannelVisibility::Public,
694        admin,
695    )
696    .await
697    .unwrap();
698    db.invite_channel_member(zed_channel, member, admin, ChannelRole::Member)
699        .await
700        .unwrap();
701    db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
702        .await
703        .unwrap();
704
705    db.respond_to_channel_invite(zed_channel, member, true)
706        .await
707        .unwrap();
708
709    db.transaction(|tx| async move {
710        db.check_user_is_channel_participant(
711            &db.get_channel_internal(public_channel_id, &tx).await?,
712            admin,
713            &tx,
714        )
715        .await
716    })
717    .await
718    .unwrap();
719    db.transaction(|tx| async move {
720        db.check_user_is_channel_participant(
721            &db.get_channel_internal(public_channel_id, &tx).await?,
722            member,
723            &tx,
724        )
725        .await
726    })
727    .await
728    .unwrap();
729
730    let (mut members, _) = db
731        .get_channel_participant_details(public_channel_id, "", 100, admin)
732        .await
733        .unwrap();
734
735    members.sort_by_key(|member| member.user_id);
736
737    assert_eq!(
738        members,
739        &[
740            proto::ChannelMember {
741                user_id: admin.to_proto(),
742                kind: proto::channel_member::Kind::Member.into(),
743                role: proto::ChannelRole::Admin.into(),
744            },
745            proto::ChannelMember {
746                user_id: member.to_proto(),
747                kind: proto::channel_member::Kind::Member.into(),
748                role: proto::ChannelRole::Member.into(),
749            },
750            proto::ChannelMember {
751                user_id: guest.to_proto(),
752                kind: proto::channel_member::Kind::Invitee.into(),
753                role: proto::ChannelRole::Guest.into(),
754            },
755        ]
756    );
757
758    db.respond_to_channel_invite(zed_channel, guest, true)
759        .await
760        .unwrap();
761
762    db.transaction(|tx| async move {
763        db.check_user_is_channel_participant(
764            &db.get_channel_internal(public_channel_id, &tx).await?,
765            guest,
766            &tx,
767        )
768        .await
769    })
770    .await
771    .unwrap();
772
773    let channels = db.get_channels_for_user(guest).await.unwrap().channels;
774    assert_channel_tree(
775        channels,
776        &[(zed_channel, &[]), (public_channel_id, &[zed_channel])],
777    );
778    let channels = db.get_channels_for_user(member).await.unwrap().channels;
779    assert_channel_tree(
780        channels,
781        &[
782            (zed_channel, &[]),
783            (internal_channel_id, &[zed_channel]),
784            (public_channel_id, &[zed_channel]),
785        ],
786    );
787
788    db.set_channel_member_role(zed_channel, admin, guest, ChannelRole::Banned)
789        .await
790        .unwrap();
791    assert!(
792        db.transaction(|tx| async move {
793            db.check_user_is_channel_participant(
794                &db.get_channel_internal(public_channel_id, &tx)
795                    .await
796                    .unwrap(),
797                guest,
798                &tx,
799            )
800            .await
801        })
802        .await
803        .is_err()
804    );
805
806    let (mut members, _) = db
807        .get_channel_participant_details(public_channel_id, "", 100, admin)
808        .await
809        .unwrap();
810
811    members.sort_by_key(|member| member.user_id);
812
813    assert_eq!(
814        members,
815        &[
816            proto::ChannelMember {
817                user_id: admin.to_proto(),
818                kind: proto::channel_member::Kind::Member.into(),
819                role: proto::ChannelRole::Admin.into(),
820            },
821            proto::ChannelMember {
822                user_id: member.to_proto(),
823                kind: proto::channel_member::Kind::Member.into(),
824                role: proto::ChannelRole::Member.into(),
825            },
826            proto::ChannelMember {
827                user_id: guest.to_proto(),
828                kind: proto::channel_member::Kind::Member.into(),
829                role: proto::ChannelRole::Banned.into(),
830            },
831        ]
832    );
833
834    db.remove_channel_member(zed_channel, guest, admin)
835        .await
836        .unwrap();
837
838    db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
839        .await
840        .unwrap();
841
842    // currently people invited to parent channels are not shown here
843    let (mut members, _) = db
844        .get_channel_participant_details(public_channel_id, "", 100, admin)
845        .await
846        .unwrap();
847
848    members.sort_by_key(|member| member.user_id);
849
850    assert_eq!(
851        members,
852        &[
853            proto::ChannelMember {
854                user_id: admin.to_proto(),
855                kind: proto::channel_member::Kind::Member.into(),
856                role: proto::ChannelRole::Admin.into(),
857            },
858            proto::ChannelMember {
859                user_id: member.to_proto(),
860                kind: proto::channel_member::Kind::Member.into(),
861                role: proto::ChannelRole::Member.into(),
862            },
863            proto::ChannelMember {
864                user_id: guest.to_proto(),
865                kind: proto::channel_member::Kind::Invitee.into(),
866                role: proto::ChannelRole::Guest.into(),
867            },
868        ]
869    );
870
871    db.respond_to_channel_invite(zed_channel, guest, true)
872        .await
873        .unwrap();
874
875    db.transaction(|tx| async move {
876        db.check_user_is_channel_participant(
877            &db.get_channel_internal(zed_channel, &tx).await.unwrap(),
878            guest,
879            &tx,
880        )
881        .await
882    })
883    .await
884    .unwrap();
885    assert!(
886        db.transaction(|tx| async move {
887            db.check_user_is_channel_participant(
888                &db.get_channel_internal(internal_channel_id, &tx)
889                    .await
890                    .unwrap(),
891                guest,
892                &tx,
893            )
894            .await
895        })
896        .await
897        .is_err(),
898    );
899
900    db.transaction(|tx| async move {
901        db.check_user_is_channel_participant(
902            &db.get_channel_internal(public_channel_id, &tx)
903                .await
904                .unwrap(),
905            guest,
906            &tx,
907        )
908        .await
909    })
910    .await
911    .unwrap();
912
913    let (mut members, _) = db
914        .get_channel_participant_details(public_channel_id, "", 100, admin)
915        .await
916        .unwrap();
917
918    members.sort_by_key(|member| member.user_id);
919
920    assert_eq!(
921        members,
922        &[
923            proto::ChannelMember {
924                user_id: admin.to_proto(),
925                kind: proto::channel_member::Kind::Member.into(),
926                role: proto::ChannelRole::Admin.into(),
927            },
928            proto::ChannelMember {
929                user_id: member.to_proto(),
930                kind: proto::channel_member::Kind::Member.into(),
931                role: proto::ChannelRole::Member.into(),
932            },
933            proto::ChannelMember {
934                user_id: guest.to_proto(),
935                kind: proto::channel_member::Kind::Member.into(),
936                role: proto::ChannelRole::Guest.into(),
937            },
938        ]
939    );
940
941    let channels = db.get_channels_for_user(guest).await.unwrap().channels;
942    assert_channel_tree(
943        channels,
944        &[(zed_channel, &[]), (public_channel_id, &[zed_channel])],
945    )
946}
947
948#[track_caller]
949fn assert_channel_tree(actual: Vec<Channel>, expected: &[(ChannelId, &[ChannelId])]) {
950    let actual = actual
951        .iter()
952        .map(|channel| (channel.id, channel.parent_path.as_slice()))
953        .collect::<HashSet<_>>();
954    let expected = expected
955        .iter()
956        .map(|(id, parents)| (*id, *parents))
957        .collect::<HashSet<_>>();
958    pretty_assertions::assert_eq!(actual, expected, "wrong channel ids and parent paths");
959}
960
961#[track_caller]
962fn assert_channel_tree_order(actual: Vec<Channel>, expected: &[(ChannelId, &[ChannelId], i32)]) {
963    let actual = actual
964        .iter()
965        .map(|channel| {
966            (
967                channel.id,
968                channel.parent_path.as_slice(),
969                channel.channel_order,
970            )
971        })
972        .collect::<HashSet<_>>();
973    let expected = expected
974        .iter()
975        .map(|(id, parents, order)| (*id, *parents, *order))
976        .collect::<HashSet<_>>();
977    pretty_assertions::assert_eq!(actual, expected, "wrong channel ids and parent paths");
978}