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