1use crate::{
2 db::{
3 queries::channels::ChannelGraph,
4 tests::{graph, new_test_user, TEST_RELEASE_CHANNEL},
5 ChannelId, ChannelRole, Database, NewUserParams, RoomId,
6 },
7 test_both_dbs,
8};
9use collections::{HashMap, HashSet};
10use rpc::{
11 proto::{self},
12 ConnectionId,
13};
14use std::sync::Arc;
15
16test_both_dbs!(test_channels, test_channels_postgres, test_channels_sqlite);
17
18async fn test_channels(db: &Arc<Database>) {
19 let a_id = db
20 .create_user(
21 "user1@example.com",
22 false,
23 NewUserParams {
24 github_login: "user1".into(),
25 github_user_id: 5,
26 },
27 )
28 .await
29 .unwrap()
30 .user_id;
31
32 let b_id = db
33 .create_user(
34 "user2@example.com",
35 false,
36 NewUserParams {
37 github_login: "user2".into(),
38 github_user_id: 6,
39 },
40 )
41 .await
42 .unwrap()
43 .user_id;
44
45 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
46
47 // Make sure that people cannot read channels they haven't been invited to
48 assert!(db.get_channel(zed_id, b_id).await.is_err());
49
50 db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
51 .await
52 .unwrap();
53
54 db.respond_to_channel_invite(zed_id, b_id, true)
55 .await
56 .unwrap();
57
58 let crdb_id = db.create_channel("crdb", Some(zed_id), a_id).await.unwrap();
59 let livestreaming_id = db
60 .create_channel("livestreaming", Some(zed_id), a_id)
61 .await
62 .unwrap();
63 let replace_id = db
64 .create_channel("replace", Some(zed_id), a_id)
65 .await
66 .unwrap();
67
68 let mut members = db.get_channel_members(replace_id).await.unwrap();
69 members.sort();
70 assert_eq!(members, &[a_id, b_id]);
71
72 let rust_id = db.create_root_channel("rust", a_id).await.unwrap();
73 let cargo_id = db
74 .create_channel("cargo", Some(rust_id), a_id)
75 .await
76 .unwrap();
77
78 let cargo_ra_id = db
79 .create_channel("cargo-ra", Some(cargo_id), a_id)
80 .await
81 .unwrap();
82
83 let result = db.get_channels_for_user(a_id).await.unwrap();
84 assert_eq!(
85 result.channels,
86 graph(
87 &[
88 (zed_id, "zed"),
89 (crdb_id, "crdb"),
90 (livestreaming_id, "livestreaming"),
91 (replace_id, "replace"),
92 (rust_id, "rust"),
93 (cargo_id, "cargo"),
94 (cargo_ra_id, "cargo-ra")
95 ],
96 &[
97 (crdb_id, zed_id),
98 (livestreaming_id, zed_id),
99 (replace_id, zed_id),
100 (cargo_id, rust_id),
101 (cargo_ra_id, cargo_id),
102 ]
103 )
104 );
105
106 let result = db.get_channels_for_user(b_id).await.unwrap();
107 assert_eq!(
108 result.channels,
109 graph(
110 &[
111 (zed_id, "zed"),
112 (crdb_id, "crdb"),
113 (livestreaming_id, "livestreaming"),
114 (replace_id, "replace")
115 ],
116 &[
117 (crdb_id, zed_id),
118 (livestreaming_id, zed_id),
119 (replace_id, zed_id)
120 ]
121 )
122 );
123
124 // Update member permissions
125 let set_subchannel_admin = db
126 .set_channel_member_role(crdb_id, a_id, b_id, ChannelRole::Admin)
127 .await;
128 assert!(set_subchannel_admin.is_err());
129 let set_channel_admin = db
130 .set_channel_member_role(zed_id, a_id, b_id, ChannelRole::Admin)
131 .await;
132 assert!(set_channel_admin.is_ok());
133
134 let result = db.get_channels_for_user(b_id).await.unwrap();
135 assert_eq!(
136 result.channels,
137 graph(
138 &[
139 (zed_id, "zed"),
140 (crdb_id, "crdb"),
141 (livestreaming_id, "livestreaming"),
142 (replace_id, "replace")
143 ],
144 &[
145 (crdb_id, zed_id),
146 (livestreaming_id, zed_id),
147 (replace_id, zed_id)
148 ]
149 )
150 );
151
152 // Remove a single channel
153 db.delete_channel(crdb_id, a_id).await.unwrap();
154 assert!(db.get_channel(crdb_id, a_id).await.is_err());
155
156 // Remove a channel tree
157 let (mut channel_ids, user_ids) = db.delete_channel(rust_id, a_id).await.unwrap();
158 channel_ids.sort();
159 assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
160 assert_eq!(user_ids, &[a_id]);
161
162 assert!(db.get_channel(rust_id, a_id).await.is_err());
163 assert!(db.get_channel(cargo_id, a_id).await.is_err());
164 assert!(db.get_channel(cargo_ra_id, a_id).await.is_err());
165}
166
167test_both_dbs!(
168 test_joining_channels,
169 test_joining_channels_postgres,
170 test_joining_channels_sqlite
171);
172
173async fn test_joining_channels(db: &Arc<Database>) {
174 let owner_id = db.create_server("test").await.unwrap().0 as u32;
175
176 let user_1 = db
177 .create_user(
178 "user1@example.com",
179 false,
180 NewUserParams {
181 github_login: "user1".into(),
182 github_user_id: 5,
183 },
184 )
185 .await
186 .unwrap()
187 .user_id;
188 let user_2 = db
189 .create_user(
190 "user2@example.com",
191 false,
192 NewUserParams {
193 github_login: "user2".into(),
194 github_user_id: 6,
195 },
196 )
197 .await
198 .unwrap()
199 .user_id;
200
201 let channel_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
202
203 // can join a room with membership to its channel
204 let (joined_room, _) = db
205 .join_channel(
206 channel_1,
207 user_1,
208 ConnectionId { owner_id, id: 1 },
209 TEST_RELEASE_CHANNEL,
210 )
211 .await
212 .unwrap();
213 assert_eq!(joined_room.room.participants.len(), 1);
214
215 let room_id = RoomId::from_proto(joined_room.room.id);
216 drop(joined_room);
217 // cannot join a room without membership to its channel
218 assert!(db
219 .join_room(
220 room_id,
221 user_2,
222 ConnectionId { owner_id, id: 1 },
223 TEST_RELEASE_CHANNEL
224 )
225 .await
226 .is_err());
227}
228
229test_both_dbs!(
230 test_channel_invites,
231 test_channel_invites_postgres,
232 test_channel_invites_sqlite
233);
234
235async fn test_channel_invites(db: &Arc<Database>) {
236 db.create_server("test").await.unwrap();
237
238 let user_1 = new_test_user(db, "user1@example.com").await;
239 let user_2 = new_test_user(db, "user2@example.com").await;
240 let user_3 = new_test_user(db, "user3@example.com").await;
241
242 let channel_1_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
243
244 let channel_1_2 = db.create_root_channel("channel_2", user_1).await.unwrap();
245
246 db.invite_channel_member(channel_1_1, user_2, user_1, ChannelRole::Member)
247 .await
248 .unwrap();
249 db.invite_channel_member(channel_1_2, user_2, user_1, ChannelRole::Member)
250 .await
251 .unwrap();
252 db.invite_channel_member(channel_1_1, user_3, user_1, ChannelRole::Admin)
253 .await
254 .unwrap();
255
256 let user_2_invites = db
257 .get_channel_invites_for_user(user_2) // -> [channel_1_1, channel_1_2]
258 .await
259 .unwrap()
260 .into_iter()
261 .map(|channel| channel.id)
262 .collect::<Vec<_>>();
263
264 assert_eq!(user_2_invites, &[channel_1_1, channel_1_2]);
265
266 let user_3_invites = db
267 .get_channel_invites_for_user(user_3) // -> [channel_1_1]
268 .await
269 .unwrap()
270 .into_iter()
271 .map(|channel| channel.id)
272 .collect::<Vec<_>>();
273
274 assert_eq!(user_3_invites, &[channel_1_1]);
275
276 let mut members = db
277 .get_channel_participant_details(channel_1_1, user_1)
278 .await
279 .unwrap();
280
281 members.sort_by_key(|member| member.user_id);
282 assert_eq!(
283 members,
284 &[
285 proto::ChannelMember {
286 user_id: user_1.to_proto(),
287 kind: proto::channel_member::Kind::Member.into(),
288 role: proto::ChannelRole::Admin.into(),
289 },
290 proto::ChannelMember {
291 user_id: user_2.to_proto(),
292 kind: proto::channel_member::Kind::Invitee.into(),
293 role: proto::ChannelRole::Member.into(),
294 },
295 proto::ChannelMember {
296 user_id: user_3.to_proto(),
297 kind: proto::channel_member::Kind::Invitee.into(),
298 role: proto::ChannelRole::Admin.into(),
299 },
300 ]
301 );
302
303 db.respond_to_channel_invite(channel_1_1, user_2, true)
304 .await
305 .unwrap();
306
307 let channel_1_3 = db
308 .create_channel("channel_3", Some(channel_1_1), user_1)
309 .await
310 .unwrap();
311
312 let members = db
313 .get_channel_participant_details(channel_1_3, user_1)
314 .await
315 .unwrap();
316 assert_eq!(
317 members,
318 &[
319 proto::ChannelMember {
320 user_id: user_1.to_proto(),
321 kind: proto::channel_member::Kind::Member.into(),
322 role: proto::ChannelRole::Admin.into(),
323 },
324 proto::ChannelMember {
325 user_id: user_2.to_proto(),
326 kind: proto::channel_member::Kind::AncestorMember.into(),
327 role: proto::ChannelRole::Member.into(),
328 },
329 ]
330 );
331}
332
333test_both_dbs!(
334 test_channel_renames,
335 test_channel_renames_postgres,
336 test_channel_renames_sqlite
337);
338
339async fn test_channel_renames(db: &Arc<Database>) {
340 db.create_server("test").await.unwrap();
341
342 let user_1 = db
343 .create_user(
344 "user1@example.com",
345 false,
346 NewUserParams {
347 github_login: "user1".into(),
348 github_user_id: 5,
349 },
350 )
351 .await
352 .unwrap()
353 .user_id;
354
355 let user_2 = db
356 .create_user(
357 "user2@example.com",
358 false,
359 NewUserParams {
360 github_login: "user2".into(),
361 github_user_id: 6,
362 },
363 )
364 .await
365 .unwrap()
366 .user_id;
367
368 let zed_id = db.create_root_channel("zed", user_1).await.unwrap();
369
370 db.rename_channel(zed_id, user_1, "#zed-archive")
371 .await
372 .unwrap();
373
374 let zed_archive_id = zed_id;
375
376 let channel = db.get_channel(zed_archive_id, user_1).await.unwrap();
377 assert_eq!(channel.name, "zed-archive");
378
379 let non_permissioned_rename = db
380 .rename_channel(zed_archive_id, user_2, "hacked-lol")
381 .await;
382 assert!(non_permissioned_rename.is_err());
383
384 let bad_name_rename = db.rename_channel(zed_id, user_1, "#").await;
385 assert!(bad_name_rename.is_err())
386}
387
388test_both_dbs!(
389 test_db_channel_moving,
390 test_channels_moving_postgres,
391 test_channels_moving_sqlite
392);
393
394async fn test_db_channel_moving(db: &Arc<Database>) {
395 let a_id = db
396 .create_user(
397 "user1@example.com",
398 false,
399 NewUserParams {
400 github_login: "user1".into(),
401 github_user_id: 5,
402 },
403 )
404 .await
405 .unwrap()
406 .user_id;
407
408 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
409
410 let crdb_id = db.create_channel("crdb", Some(zed_id), a_id).await.unwrap();
411
412 let gpui2_id = db
413 .create_channel("gpui2", Some(zed_id), a_id)
414 .await
415 .unwrap();
416
417 let livestreaming_id = db
418 .create_channel("livestreaming", Some(crdb_id), a_id)
419 .await
420 .unwrap();
421
422 let livestreaming_dag_id = db
423 .create_channel("livestreaming_dag", Some(livestreaming_id), a_id)
424 .await
425 .unwrap();
426
427 // ========================================================================
428 // sanity check
429 // Initial DAG:
430 // /- gpui2
431 // zed -- crdb - livestreaming - livestreaming_dag
432 let result = db.get_channels_for_user(a_id).await.unwrap();
433 assert_dag(
434 result.channels,
435 &[
436 (zed_id, None),
437 (crdb_id, Some(zed_id)),
438 (gpui2_id, Some(zed_id)),
439 (livestreaming_id, Some(crdb_id)),
440 (livestreaming_dag_id, Some(livestreaming_id)),
441 ],
442 );
443
444 // Attempt to make a cycle
445 assert!(db
446 .link_channel(a_id, zed_id, livestreaming_id)
447 .await
448 .is_err());
449
450 // ========================================================================
451 // Make a link
452 db.link_channel(a_id, livestreaming_id, zed_id)
453 .await
454 .unwrap();
455
456 // DAG is now:
457 // /- gpui2
458 // zed -- crdb - livestreaming - livestreaming_dag
459 // \---------/
460 let result = db.get_channels_for_user(a_id).await.unwrap();
461 assert_dag(
462 result.channels,
463 &[
464 (zed_id, None),
465 (crdb_id, Some(zed_id)),
466 (gpui2_id, Some(zed_id)),
467 (livestreaming_id, Some(zed_id)),
468 (livestreaming_id, Some(crdb_id)),
469 (livestreaming_dag_id, Some(livestreaming_id)),
470 ],
471 );
472
473 // ========================================================================
474 // Create a new channel below a channel with multiple parents
475 let livestreaming_dag_sub_id = db
476 .create_channel("livestreaming_dag_sub", Some(livestreaming_dag_id), a_id)
477 .await
478 .unwrap();
479
480 // DAG is now:
481 // /- gpui2
482 // zed -- crdb - livestreaming - livestreaming_dag - livestreaming_dag_sub_id
483 // \---------/
484 let result = db.get_channels_for_user(a_id).await.unwrap();
485 assert_dag(
486 result.channels,
487 &[
488 (zed_id, None),
489 (crdb_id, Some(zed_id)),
490 (gpui2_id, Some(zed_id)),
491 (livestreaming_id, Some(zed_id)),
492 (livestreaming_id, Some(crdb_id)),
493 (livestreaming_dag_id, Some(livestreaming_id)),
494 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
495 ],
496 );
497
498 // ========================================================================
499 // Test a complex DAG by making another link
500 let returned_channels = db
501 .link_channel(a_id, livestreaming_dag_sub_id, livestreaming_id)
502 .await
503 .unwrap();
504
505 // DAG is now:
506 // /- gpui2 /---------------------\
507 // zed - crdb - livestreaming - livestreaming_dag - livestreaming_dag_sub_id
508 // \--------/
509
510 // make sure we're getting just the new link
511 // Not using the assert_dag helper because we want to make sure we're returning the full data
512 pretty_assertions::assert_eq!(
513 returned_channels,
514 graph(
515 &[(livestreaming_dag_sub_id, "livestreaming_dag_sub")],
516 &[(livestreaming_dag_sub_id, livestreaming_id)]
517 )
518 );
519
520 let result = db.get_channels_for_user(a_id).await.unwrap();
521 assert_dag(
522 result.channels,
523 &[
524 (zed_id, None),
525 (crdb_id, Some(zed_id)),
526 (gpui2_id, Some(zed_id)),
527 (livestreaming_id, Some(zed_id)),
528 (livestreaming_id, Some(crdb_id)),
529 (livestreaming_dag_id, Some(livestreaming_id)),
530 (livestreaming_dag_sub_id, Some(livestreaming_id)),
531 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
532 ],
533 );
534
535 // ========================================================================
536 // Test a complex DAG by making another link
537 let returned_channels = db
538 .link_channel(a_id, livestreaming_id, gpui2_id)
539 .await
540 .unwrap();
541
542 // DAG is now:
543 // /- gpui2 -\ /---------------------\
544 // zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub_id
545 // \---------/
546
547 // Make sure that we're correctly getting the full sub-dag
548 pretty_assertions::assert_eq!(
549 returned_channels,
550 graph(
551 &[
552 (livestreaming_id, "livestreaming"),
553 (livestreaming_dag_id, "livestreaming_dag"),
554 (livestreaming_dag_sub_id, "livestreaming_dag_sub"),
555 ],
556 &[
557 (livestreaming_id, gpui2_id),
558 (livestreaming_dag_id, livestreaming_id),
559 (livestreaming_dag_sub_id, livestreaming_id),
560 (livestreaming_dag_sub_id, livestreaming_dag_id),
561 ]
562 )
563 );
564
565 let result = db.get_channels_for_user(a_id).await.unwrap();
566 assert_dag(
567 result.channels,
568 &[
569 (zed_id, None),
570 (crdb_id, Some(zed_id)),
571 (gpui2_id, Some(zed_id)),
572 (livestreaming_id, Some(zed_id)),
573 (livestreaming_id, Some(crdb_id)),
574 (livestreaming_id, Some(gpui2_id)),
575 (livestreaming_dag_id, Some(livestreaming_id)),
576 (livestreaming_dag_sub_id, Some(livestreaming_id)),
577 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
578 ],
579 );
580
581 // ========================================================================
582 // Test unlinking in a complex DAG by removing the inner link
583 db.unlink_channel(a_id, livestreaming_dag_sub_id, livestreaming_id)
584 .await
585 .unwrap();
586
587 // DAG is now:
588 // /- gpui2 -\
589 // zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub
590 // \---------/
591
592 let result = db.get_channels_for_user(a_id).await.unwrap();
593 assert_dag(
594 result.channels,
595 &[
596 (zed_id, None),
597 (crdb_id, Some(zed_id)),
598 (gpui2_id, Some(zed_id)),
599 (livestreaming_id, Some(gpui2_id)),
600 (livestreaming_id, Some(zed_id)),
601 (livestreaming_id, Some(crdb_id)),
602 (livestreaming_dag_id, Some(livestreaming_id)),
603 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
604 ],
605 );
606
607 // ========================================================================
608 // Test unlinking in a complex DAG by removing the inner link
609 db.unlink_channel(a_id, livestreaming_id, gpui2_id)
610 .await
611 .unwrap();
612
613 // DAG is now:
614 // /- gpui2
615 // zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub
616 // \---------/
617 let result = db.get_channels_for_user(a_id).await.unwrap();
618 assert_dag(
619 result.channels,
620 &[
621 (zed_id, None),
622 (crdb_id, Some(zed_id)),
623 (gpui2_id, Some(zed_id)),
624 (livestreaming_id, Some(zed_id)),
625 (livestreaming_id, Some(crdb_id)),
626 (livestreaming_dag_id, Some(livestreaming_id)),
627 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
628 ],
629 );
630
631 // ========================================================================
632 // Test moving DAG nodes by moving livestreaming to be below gpui2
633 db.move_channel(a_id, livestreaming_id, crdb_id, gpui2_id)
634 .await
635 .unwrap();
636
637 // DAG is now:
638 // /- gpui2 -- livestreaming - livestreaming_dag - livestreaming_dag_sub
639 // zed - crdb /
640 // \---------/
641 let result = db.get_channels_for_user(a_id).await.unwrap();
642 assert_dag(
643 result.channels,
644 &[
645 (zed_id, None),
646 (crdb_id, Some(zed_id)),
647 (gpui2_id, Some(zed_id)),
648 (livestreaming_id, Some(zed_id)),
649 (livestreaming_id, Some(gpui2_id)),
650 (livestreaming_dag_id, Some(livestreaming_id)),
651 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
652 ],
653 );
654
655 // ========================================================================
656 // Deleting a channel should not delete children that still have other parents
657 db.delete_channel(gpui2_id, a_id).await.unwrap();
658
659 // DAG is now:
660 // zed - crdb
661 // \- livestreaming - livestreaming_dag - livestreaming_dag_sub
662 let result = db.get_channels_for_user(a_id).await.unwrap();
663 assert_dag(
664 result.channels,
665 &[
666 (zed_id, None),
667 (crdb_id, Some(zed_id)),
668 (livestreaming_id, Some(zed_id)),
669 (livestreaming_dag_id, Some(livestreaming_id)),
670 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
671 ],
672 );
673
674 // ========================================================================
675 // Unlinking a channel from it's parent should automatically promote it to a root channel
676 db.unlink_channel(a_id, crdb_id, zed_id).await.unwrap();
677
678 // DAG is now:
679 // crdb
680 // zed
681 // \- livestreaming - livestreaming_dag - livestreaming_dag_sub
682
683 let result = db.get_channels_for_user(a_id).await.unwrap();
684 assert_dag(
685 result.channels,
686 &[
687 (zed_id, None),
688 (crdb_id, None),
689 (livestreaming_id, Some(zed_id)),
690 (livestreaming_dag_id, Some(livestreaming_id)),
691 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
692 ],
693 );
694
695 // ========================================================================
696 // You should be able to move a root channel into a non-root channel
697 db.link_channel(a_id, crdb_id, zed_id).await.unwrap();
698
699 // DAG is now:
700 // zed - crdb
701 // \- livestreaming - livestreaming_dag - livestreaming_dag_sub
702
703 let result = db.get_channels_for_user(a_id).await.unwrap();
704 assert_dag(
705 result.channels,
706 &[
707 (zed_id, None),
708 (crdb_id, Some(zed_id)),
709 (livestreaming_id, Some(zed_id)),
710 (livestreaming_dag_id, Some(livestreaming_id)),
711 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
712 ],
713 );
714
715 // ========================================================================
716 // Prep for DAG deletion test
717 db.link_channel(a_id, livestreaming_id, crdb_id)
718 .await
719 .unwrap();
720
721 // DAG is now:
722 // zed - crdb - livestreaming - livestreaming_dag - livestreaming_dag_sub
723 // \--------/
724
725 let result = db.get_channels_for_user(a_id).await.unwrap();
726 assert_dag(
727 result.channels,
728 &[
729 (zed_id, None),
730 (crdb_id, Some(zed_id)),
731 (livestreaming_id, Some(zed_id)),
732 (livestreaming_id, Some(crdb_id)),
733 (livestreaming_dag_id, Some(livestreaming_id)),
734 (livestreaming_dag_sub_id, Some(livestreaming_dag_id)),
735 ],
736 );
737
738 // Deleting the parent of a DAG should delete the whole DAG:
739 db.delete_channel(zed_id, a_id).await.unwrap();
740 let result = db.get_channels_for_user(a_id).await.unwrap();
741
742 assert!(result.channels.is_empty())
743}
744
745test_both_dbs!(
746 test_db_channel_moving_bugs,
747 test_db_channel_moving_bugs_postgres,
748 test_db_channel_moving_bugs_sqlite
749);
750
751async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
752 let user_id = db
753 .create_user(
754 "user1@example.com",
755 false,
756 NewUserParams {
757 github_login: "user1".into(),
758 github_user_id: 5,
759 },
760 )
761 .await
762 .unwrap()
763 .user_id;
764
765 let zed_id = db.create_root_channel("zed", user_id).await.unwrap();
766
767 let projects_id = db
768 .create_channel("projects", Some(zed_id), user_id)
769 .await
770 .unwrap();
771
772 let livestreaming_id = db
773 .create_channel("livestreaming", Some(projects_id), user_id)
774 .await
775 .unwrap();
776
777 // Dag is: zed - projects - livestreaming
778
779 // Move to same parent should be a no-op
780 assert!(db
781 .move_channel(user_id, projects_id, zed_id, zed_id)
782 .await
783 .unwrap()
784 .is_empty());
785
786 // Stranding a channel should retain it's sub channels
787 db.unlink_channel(user_id, projects_id, zed_id)
788 .await
789 .unwrap();
790
791 let result = db.get_channels_for_user(user_id).await.unwrap();
792 assert_dag(
793 result.channels,
794 &[
795 (zed_id, None),
796 (projects_id, None),
797 (livestreaming_id, Some(projects_id)),
798 ],
799 );
800}
801
802test_both_dbs!(
803 test_user_is_channel_participant,
804 test_user_is_channel_participant_postgres,
805 test_user_is_channel_participant_sqlite
806);
807
808async fn test_user_is_channel_participant(db: &Arc<Database>) {
809 let admin = new_test_user(db, "admin@example.com").await;
810 let member = new_test_user(db, "member@example.com").await;
811 let guest = new_test_user(db, "guest@example.com").await;
812
813 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
814 let active_channel = db
815 .create_channel("active", Some(zed_channel), admin)
816 .await
817 .unwrap();
818 let vim_channel = db
819 .create_channel("vim", Some(active_channel), admin)
820 .await
821 .unwrap();
822
823 db.set_channel_visibility(vim_channel, crate::db::ChannelVisibility::Public, admin)
824 .await
825 .unwrap();
826 db.invite_channel_member(active_channel, member, admin, ChannelRole::Member)
827 .await
828 .unwrap();
829 db.invite_channel_member(vim_channel, guest, admin, ChannelRole::Guest)
830 .await
831 .unwrap();
832
833 db.respond_to_channel_invite(active_channel, member, true)
834 .await
835 .unwrap();
836
837 db.transaction(|tx| async move {
838 db.check_user_is_channel_participant(vim_channel, admin, &*tx)
839 .await
840 })
841 .await
842 .unwrap();
843 db.transaction(|tx| async move {
844 db.check_user_is_channel_participant(vim_channel, member, &*tx)
845 .await
846 })
847 .await
848 .unwrap();
849
850 let mut members = db
851 .get_channel_participant_details(vim_channel, admin)
852 .await
853 .unwrap();
854
855 members.sort_by_key(|member| member.user_id);
856
857 assert_eq!(
858 members,
859 &[
860 proto::ChannelMember {
861 user_id: admin.to_proto(),
862 kind: proto::channel_member::Kind::Member.into(),
863 role: proto::ChannelRole::Admin.into(),
864 },
865 proto::ChannelMember {
866 user_id: member.to_proto(),
867 kind: proto::channel_member::Kind::AncestorMember.into(),
868 role: proto::ChannelRole::Member.into(),
869 },
870 proto::ChannelMember {
871 user_id: guest.to_proto(),
872 kind: proto::channel_member::Kind::Invitee.into(),
873 role: proto::ChannelRole::Guest.into(),
874 },
875 ]
876 );
877
878 db.respond_to_channel_invite(vim_channel, guest, true)
879 .await
880 .unwrap();
881
882 db.transaction(|tx| async move {
883 db.check_user_is_channel_participant(vim_channel, guest, &*tx)
884 .await
885 })
886 .await
887 .unwrap();
888
889 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
890 assert_dag(channels, &[(vim_channel, None)]);
891 let channels = db.get_channels_for_user(member).await.unwrap().channels;
892 assert_dag(
893 channels,
894 &[(active_channel, None), (vim_channel, Some(active_channel))],
895 );
896
897 db.set_channel_member_role(vim_channel, admin, guest, ChannelRole::Banned)
898 .await
899 .unwrap();
900 assert!(db
901 .transaction(|tx| async move {
902 db.check_user_is_channel_participant(vim_channel, guest, &*tx)
903 .await
904 })
905 .await
906 .is_err());
907
908 let mut members = db
909 .get_channel_participant_details(vim_channel, admin)
910 .await
911 .unwrap();
912
913 members.sort_by_key(|member| member.user_id);
914
915 assert_eq!(
916 members,
917 &[
918 proto::ChannelMember {
919 user_id: admin.to_proto(),
920 kind: proto::channel_member::Kind::Member.into(),
921 role: proto::ChannelRole::Admin.into(),
922 },
923 proto::ChannelMember {
924 user_id: member.to_proto(),
925 kind: proto::channel_member::Kind::AncestorMember.into(),
926 role: proto::ChannelRole::Member.into(),
927 },
928 proto::ChannelMember {
929 user_id: guest.to_proto(),
930 kind: proto::channel_member::Kind::Member.into(),
931 role: proto::ChannelRole::Banned.into(),
932 },
933 ]
934 );
935
936 db.remove_channel_member(vim_channel, guest, admin)
937 .await
938 .unwrap();
939
940 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
941 .await
942 .unwrap();
943
944 db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
945 .await
946 .unwrap();
947
948 // currently people invited to parent channels are not shown here
949 let mut members = db
950 .get_channel_participant_details(vim_channel, admin)
951 .await
952 .unwrap();
953
954 members.sort_by_key(|member| member.user_id);
955
956 assert_eq!(
957 members,
958 &[
959 proto::ChannelMember {
960 user_id: admin.to_proto(),
961 kind: proto::channel_member::Kind::Member.into(),
962 role: proto::ChannelRole::Admin.into(),
963 },
964 proto::ChannelMember {
965 user_id: member.to_proto(),
966 kind: proto::channel_member::Kind::AncestorMember.into(),
967 role: proto::ChannelRole::Member.into(),
968 },
969 ]
970 );
971
972 db.respond_to_channel_invite(zed_channel, guest, true)
973 .await
974 .unwrap();
975
976 db.transaction(|tx| async move {
977 db.check_user_is_channel_participant(zed_channel, guest, &*tx)
978 .await
979 })
980 .await
981 .unwrap();
982 assert!(db
983 .transaction(|tx| async move {
984 db.check_user_is_channel_participant(active_channel, guest, &*tx)
985 .await
986 })
987 .await
988 .is_err(),);
989
990 db.transaction(|tx| async move {
991 db.check_user_is_channel_participant(vim_channel, guest, &*tx)
992 .await
993 })
994 .await
995 .unwrap();
996
997 let mut members = db
998 .get_channel_participant_details(vim_channel, admin)
999 .await
1000 .unwrap();
1001
1002 members.sort_by_key(|member| member.user_id);
1003
1004 assert_eq!(
1005 members,
1006 &[
1007 proto::ChannelMember {
1008 user_id: admin.to_proto(),
1009 kind: proto::channel_member::Kind::Member.into(),
1010 role: proto::ChannelRole::Admin.into(),
1011 },
1012 proto::ChannelMember {
1013 user_id: member.to_proto(),
1014 kind: proto::channel_member::Kind::AncestorMember.into(),
1015 role: proto::ChannelRole::Member.into(),
1016 },
1017 proto::ChannelMember {
1018 user_id: guest.to_proto(),
1019 kind: proto::channel_member::Kind::AncestorMember.into(),
1020 role: proto::ChannelRole::Guest.into(),
1021 },
1022 ]
1023 );
1024
1025 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
1026 assert_dag(
1027 channels,
1028 &[(zed_channel, None), (vim_channel, Some(zed_channel))],
1029 )
1030}
1031
1032test_both_dbs!(
1033 test_user_joins_correct_channel,
1034 test_user_joins_correct_channel_postgres,
1035 test_user_joins_correct_channel_sqlite
1036);
1037
1038async fn test_user_joins_correct_channel(db: &Arc<Database>) {
1039 let admin = new_test_user(db, "admin@example.com").await;
1040
1041 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
1042
1043 let active_channel = db
1044 .create_channel("active", Some(zed_channel), admin)
1045 .await
1046 .unwrap();
1047
1048 let vim_channel = db
1049 .create_channel("vim", Some(active_channel), admin)
1050 .await
1051 .unwrap();
1052
1053 let vim2_channel = db
1054 .create_channel("vim2", Some(vim_channel), admin)
1055 .await
1056 .unwrap();
1057
1058 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
1059 .await
1060 .unwrap();
1061
1062 db.set_channel_visibility(vim_channel, crate::db::ChannelVisibility::Public, admin)
1063 .await
1064 .unwrap();
1065
1066 db.set_channel_visibility(vim2_channel, crate::db::ChannelVisibility::Public, admin)
1067 .await
1068 .unwrap();
1069
1070 let most_public = db
1071 .transaction(
1072 |tx| async move { db.most_public_ancestor_for_channel(vim_channel, &*tx).await },
1073 )
1074 .await
1075 .unwrap();
1076
1077 assert_eq!(most_public, Some(zed_channel))
1078}
1079
1080#[track_caller]
1081fn assert_dag(actual: ChannelGraph, expected: &[(ChannelId, Option<ChannelId>)]) {
1082 let mut actual_map: HashMap<ChannelId, HashSet<ChannelId>> = HashMap::default();
1083 for channel in actual.channels {
1084 actual_map.insert(channel.id, HashSet::default());
1085 }
1086 for edge in actual.edges {
1087 actual_map
1088 .get_mut(&ChannelId::from_proto(edge.channel_id))
1089 .unwrap()
1090 .insert(ChannelId::from_proto(edge.parent_id));
1091 }
1092
1093 let mut expected_map: HashMap<ChannelId, HashSet<ChannelId>> = HashMap::default();
1094
1095 for (child, parent) in expected {
1096 let entry = expected_map.entry(*child).or_default();
1097 if let Some(parent) = parent {
1098 entry.insert(*parent);
1099 }
1100 }
1101
1102 pretty_assertions::assert_eq!(actual_map, expected_map)
1103}