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