channel_tests.rs

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