1use crate::{
2 db::{
3 tests::{channel_tree, new_test_connection, new_test_user, TEST_RELEASE_CHANNEL},
4 Channel, ChannelId, ChannelRole, Database, NewUserParams, RoomId,
5 },
6 test_both_dbs,
7};
8use rpc::{
9 proto::{self},
10 ConnectionId,
11};
12use std::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 mut members = db
44 .transaction(|tx| async move {
45 let channel = db.get_channel_internal(replace_id, &*tx).await?;
46 Ok(db.get_channel_participants(&channel, &*tx).await?)
47 })
48 .await
49 .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.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_eq!(
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_eq!(
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_eq!(
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, user_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 assert_eq!(user_ids, &[a_id]);
116
117 assert!(db.get_channel(rust_id, a_id).await.is_err());
118 assert!(db.get_channel(cargo_id, a_id).await.is_err());
119 assert!(db.get_channel(cargo_ra_id, a_id).await.is_err());
120}
121
122test_both_dbs!(
123 test_joining_channels,
124 test_joining_channels_postgres,
125 test_joining_channels_sqlite
126);
127
128async fn test_joining_channels(db: &Arc<Database>) {
129 let owner_id = db.create_server("test").await.unwrap().0 as u32;
130
131 let user_1 = new_test_user(db, "user1@example.com").await;
132 let user_2 = new_test_user(db, "user2@example.com").await;
133
134 let channel_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
135
136 // can join a room with membership to its channel
137 let (joined_room, _, _) = db
138 .join_channel(
139 channel_1,
140 user_1,
141 false,
142 ConnectionId { owner_id, id: 1 },
143 TEST_RELEASE_CHANNEL,
144 )
145 .await
146 .unwrap();
147 assert_eq!(joined_room.room.participants.len(), 1);
148
149 let room_id = RoomId::from_proto(joined_room.room.id);
150 drop(joined_room);
151 // cannot join a room without membership to its channel
152 assert!(db
153 .join_room(
154 room_id,
155 user_2,
156 ConnectionId { owner_id, id: 1 },
157 TEST_RELEASE_CHANNEL
158 )
159 .await
160 .is_err());
161}
162
163test_both_dbs!(
164 test_channel_invites,
165 test_channel_invites_postgres,
166 test_channel_invites_sqlite
167);
168
169async fn test_channel_invites(db: &Arc<Database>) {
170 db.create_server("test").await.unwrap();
171
172 let user_1 = new_test_user(db, "user1@example.com").await;
173 let user_2 = new_test_user(db, "user2@example.com").await;
174 let user_3 = new_test_user(db, "user3@example.com").await;
175
176 let channel_1_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
177
178 let channel_1_2 = db.create_root_channel("channel_2", user_1).await.unwrap();
179
180 db.invite_channel_member(channel_1_1, user_2, user_1, ChannelRole::Member)
181 .await
182 .unwrap();
183 db.invite_channel_member(channel_1_2, user_2, user_1, ChannelRole::Member)
184 .await
185 .unwrap();
186 db.invite_channel_member(channel_1_1, user_3, user_1, ChannelRole::Admin)
187 .await
188 .unwrap();
189
190 let user_2_invites = db
191 .get_channel_invites_for_user(user_2) // -> [channel_1_1, channel_1_2]
192 .await
193 .unwrap()
194 .into_iter()
195 .map(|channel| channel.id)
196 .collect::<Vec<_>>();
197
198 assert_eq!(user_2_invites, &[channel_1_1, channel_1_2]);
199
200 let user_3_invites = db
201 .get_channel_invites_for_user(user_3) // -> [channel_1_1]
202 .await
203 .unwrap()
204 .into_iter()
205 .map(|channel| channel.id)
206 .collect::<Vec<_>>();
207
208 assert_eq!(user_3_invites, &[channel_1_1]);
209
210 let mut members = db
211 .get_channel_participant_details(channel_1_1, user_1)
212 .await
213 .unwrap();
214
215 members.sort_by_key(|member| member.user_id);
216 assert_eq!(
217 members,
218 &[
219 proto::ChannelMember {
220 user_id: user_1.to_proto(),
221 kind: proto::channel_member::Kind::Member.into(),
222 role: proto::ChannelRole::Admin.into(),
223 },
224 proto::ChannelMember {
225 user_id: user_2.to_proto(),
226 kind: proto::channel_member::Kind::Invitee.into(),
227 role: proto::ChannelRole::Member.into(),
228 },
229 proto::ChannelMember {
230 user_id: user_3.to_proto(),
231 kind: proto::channel_member::Kind::Invitee.into(),
232 role: proto::ChannelRole::Admin.into(),
233 },
234 ]
235 );
236
237 db.respond_to_channel_invite(channel_1_1, user_2, true)
238 .await
239 .unwrap();
240
241 let channel_1_3 = db
242 .create_sub_channel("channel_3", channel_1_1, user_1)
243 .await
244 .unwrap();
245
246 let members = db
247 .get_channel_participant_details(channel_1_3, user_1)
248 .await
249 .unwrap();
250 assert_eq!(
251 members,
252 &[
253 proto::ChannelMember {
254 user_id: user_1.to_proto(),
255 kind: proto::channel_member::Kind::Member.into(),
256 role: proto::ChannelRole::Admin.into(),
257 },
258 proto::ChannelMember {
259 user_id: user_2.to_proto(),
260 kind: proto::channel_member::Kind::Member.into(),
261 role: proto::ChannelRole::Member.into(),
262 },
263 proto::ChannelMember {
264 user_id: user_3.to_proto(),
265 kind: proto::channel_member::Kind::Invitee.into(),
266 role: proto::ChannelRole::Admin.into(),
267 },
268 ]
269 );
270}
271
272test_both_dbs!(
273 test_channel_renames,
274 test_channel_renames_postgres,
275 test_channel_renames_sqlite
276);
277
278async fn test_channel_renames(db: &Arc<Database>) {
279 db.create_server("test").await.unwrap();
280
281 let user_1 = db
282 .create_user(
283 "user1@example.com",
284 false,
285 NewUserParams {
286 github_login: "user1".into(),
287 github_user_id: 5,
288 },
289 )
290 .await
291 .unwrap()
292 .user_id;
293
294 let user_2 = db
295 .create_user(
296 "user2@example.com",
297 false,
298 NewUserParams {
299 github_login: "user2".into(),
300 github_user_id: 6,
301 },
302 )
303 .await
304 .unwrap()
305 .user_id;
306
307 let zed_id = db.create_root_channel("zed", user_1).await.unwrap();
308
309 db.rename_channel(zed_id, user_1, "#zed-archive")
310 .await
311 .unwrap();
312
313 let channel = db.get_channel(zed_id, user_1).await.unwrap();
314 assert_eq!(channel.name, "zed-archive");
315
316 let non_permissioned_rename = db.rename_channel(zed_id, user_2, "hacked-lol").await;
317 assert!(non_permissioned_rename.is_err());
318
319 let bad_name_rename = db.rename_channel(zed_id, user_1, "#").await;
320 assert!(bad_name_rename.is_err())
321}
322
323test_both_dbs!(
324 test_db_channel_moving,
325 test_channels_moving_postgres,
326 test_channels_moving_sqlite
327);
328
329async fn test_db_channel_moving(db: &Arc<Database>) {
330 let a_id = db
331 .create_user(
332 "user1@example.com",
333 false,
334 NewUserParams {
335 github_login: "user1".into(),
336 github_user_id: 5,
337 },
338 )
339 .await
340 .unwrap()
341 .user_id;
342
343 let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
344
345 let crdb_id = db.create_sub_channel("crdb", zed_id, a_id).await.unwrap();
346
347 let gpui2_id = db.create_sub_channel("gpui2", zed_id, a_id).await.unwrap();
348
349 let livestreaming_id = db
350 .create_sub_channel("livestreaming", crdb_id, a_id)
351 .await
352 .unwrap();
353
354 let livestreaming_dag_id = db
355 .create_sub_channel("livestreaming_dag", livestreaming_id, a_id)
356 .await
357 .unwrap();
358
359 // ========================================================================
360 // sanity check
361 // Initial DAG:
362 // /- gpui2
363 // zed -- crdb - livestreaming - livestreaming_dag
364 let result = db.get_channels_for_user(a_id).await.unwrap();
365 assert_channel_tree(
366 result.channels,
367 &[
368 (zed_id, &[]),
369 (crdb_id, &[zed_id]),
370 (livestreaming_id, &[zed_id, crdb_id]),
371 (livestreaming_dag_id, &[zed_id, crdb_id, livestreaming_id]),
372 (gpui2_id, &[zed_id]),
373 ],
374 );
375}
376
377test_both_dbs!(
378 test_db_channel_moving_bugs,
379 test_db_channel_moving_bugs_postgres,
380 test_db_channel_moving_bugs_sqlite
381);
382
383async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
384 let user_id = db
385 .create_user(
386 "user1@example.com",
387 false,
388 NewUserParams {
389 github_login: "user1".into(),
390 github_user_id: 5,
391 },
392 )
393 .await
394 .unwrap()
395 .user_id;
396
397 let zed_id = db.create_root_channel("zed", user_id).await.unwrap();
398
399 let projects_id = db
400 .create_sub_channel("projects", zed_id, user_id)
401 .await
402 .unwrap();
403
404 let livestreaming_id = db
405 .create_sub_channel("livestreaming", projects_id, user_id)
406 .await
407 .unwrap();
408
409 let result = db.get_channels_for_user(user_id).await.unwrap();
410 assert_channel_tree(
411 result.channels,
412 &[
413 (zed_id, &[]),
414 (projects_id, &[zed_id]),
415 (livestreaming_id, &[zed_id, projects_id]),
416 ],
417 );
418
419 // Can't move a channel into its ancestor
420 db.move_channel(projects_id, livestreaming_id, user_id)
421 .await
422 .unwrap_err();
423 let result = db.get_channels_for_user(user_id).await.unwrap();
424 assert_channel_tree(
425 result.channels,
426 &[
427 (zed_id, &[]),
428 (projects_id, &[zed_id]),
429 (livestreaming_id, &[zed_id, projects_id]),
430 ],
431 );
432}
433
434test_both_dbs!(
435 test_user_is_channel_participant,
436 test_user_is_channel_participant_postgres,
437 test_user_is_channel_participant_sqlite
438);
439
440async fn test_user_is_channel_participant(db: &Arc<Database>) {
441 let admin = new_test_user(db, "admin@example.com").await;
442 let member = new_test_user(db, "member@example.com").await;
443 let guest = new_test_user(db, "guest@example.com").await;
444
445 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
446 let internal_channel_id = db
447 .create_sub_channel("active", zed_channel, admin)
448 .await
449 .unwrap();
450 let public_channel_id = db
451 .create_sub_channel("vim", zed_channel, admin)
452 .await
453 .unwrap();
454
455 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
456 .await
457 .unwrap();
458 db.set_channel_visibility(
459 public_channel_id,
460 crate::db::ChannelVisibility::Public,
461 admin,
462 )
463 .await
464 .unwrap();
465 db.invite_channel_member(zed_channel, member, admin, ChannelRole::Member)
466 .await
467 .unwrap();
468 db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
469 .await
470 .unwrap();
471
472 db.respond_to_channel_invite(zed_channel, member, true)
473 .await
474 .unwrap();
475
476 db.transaction(|tx| async move {
477 db.check_user_is_channel_participant(
478 &db.get_channel_internal(public_channel_id, &*tx).await?,
479 admin,
480 &*tx,
481 )
482 .await
483 })
484 .await
485 .unwrap();
486 db.transaction(|tx| async move {
487 db.check_user_is_channel_participant(
488 &db.get_channel_internal(public_channel_id, &*tx).await?,
489 member,
490 &*tx,
491 )
492 .await
493 })
494 .await
495 .unwrap();
496
497 let mut members = db
498 .get_channel_participant_details(public_channel_id, admin)
499 .await
500 .unwrap();
501
502 members.sort_by_key(|member| member.user_id);
503
504 assert_eq!(
505 members,
506 &[
507 proto::ChannelMember {
508 user_id: admin.to_proto(),
509 kind: proto::channel_member::Kind::Member.into(),
510 role: proto::ChannelRole::Admin.into(),
511 },
512 proto::ChannelMember {
513 user_id: member.to_proto(),
514 kind: proto::channel_member::Kind::Member.into(),
515 role: proto::ChannelRole::Member.into(),
516 },
517 proto::ChannelMember {
518 user_id: guest.to_proto(),
519 kind: proto::channel_member::Kind::Invitee.into(),
520 role: proto::ChannelRole::Guest.into(),
521 },
522 ]
523 );
524
525 db.respond_to_channel_invite(zed_channel, guest, true)
526 .await
527 .unwrap();
528
529 db.transaction(|tx| async move {
530 db.check_user_is_channel_participant(
531 &db.get_channel_internal(public_channel_id, &*tx).await?,
532 guest,
533 &*tx,
534 )
535 .await
536 })
537 .await
538 .unwrap();
539
540 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
541 assert_channel_tree(
542 channels,
543 &[(zed_channel, &[]), (public_channel_id, &[zed_channel])],
544 );
545 let channels = db.get_channels_for_user(member).await.unwrap().channels;
546 assert_channel_tree(
547 channels,
548 &[
549 (zed_channel, &[]),
550 (internal_channel_id, &[zed_channel]),
551 (public_channel_id, &[zed_channel]),
552 ],
553 );
554
555 db.set_channel_member_role(zed_channel, admin, guest, ChannelRole::Banned)
556 .await
557 .unwrap();
558 assert!(db
559 .transaction(|tx| async move {
560 db.check_user_is_channel_participant(
561 &db.get_channel_internal(public_channel_id, &*tx)
562 .await
563 .unwrap(),
564 guest,
565 &*tx,
566 )
567 .await
568 })
569 .await
570 .is_err());
571
572 let mut members = db
573 .get_channel_participant_details(public_channel_id, admin)
574 .await
575 .unwrap();
576
577 members.sort_by_key(|member| member.user_id);
578
579 assert_eq!(
580 members,
581 &[
582 proto::ChannelMember {
583 user_id: admin.to_proto(),
584 kind: proto::channel_member::Kind::Member.into(),
585 role: proto::ChannelRole::Admin.into(),
586 },
587 proto::ChannelMember {
588 user_id: member.to_proto(),
589 kind: proto::channel_member::Kind::Member.into(),
590 role: proto::ChannelRole::Member.into(),
591 },
592 proto::ChannelMember {
593 user_id: guest.to_proto(),
594 kind: proto::channel_member::Kind::Member.into(),
595 role: proto::ChannelRole::Banned.into(),
596 },
597 ]
598 );
599
600 db.remove_channel_member(zed_channel, guest, admin)
601 .await
602 .unwrap();
603
604 db.invite_channel_member(zed_channel, guest, admin, ChannelRole::Guest)
605 .await
606 .unwrap();
607
608 // currently people invited to parent channels are not shown here
609 let mut members = db
610 .get_channel_participant_details(public_channel_id, admin)
611 .await
612 .unwrap();
613
614 members.sort_by_key(|member| member.user_id);
615
616 assert_eq!(
617 members,
618 &[
619 proto::ChannelMember {
620 user_id: admin.to_proto(),
621 kind: proto::channel_member::Kind::Member.into(),
622 role: proto::ChannelRole::Admin.into(),
623 },
624 proto::ChannelMember {
625 user_id: member.to_proto(),
626 kind: proto::channel_member::Kind::Member.into(),
627 role: proto::ChannelRole::Member.into(),
628 },
629 proto::ChannelMember {
630 user_id: guest.to_proto(),
631 kind: proto::channel_member::Kind::Invitee.into(),
632 role: proto::ChannelRole::Guest.into(),
633 },
634 ]
635 );
636
637 db.respond_to_channel_invite(zed_channel, guest, true)
638 .await
639 .unwrap();
640
641 db.transaction(|tx| async move {
642 db.check_user_is_channel_participant(
643 &db.get_channel_internal(zed_channel, &*tx).await.unwrap(),
644 guest,
645 &*tx,
646 )
647 .await
648 })
649 .await
650 .unwrap();
651 assert!(db
652 .transaction(|tx| async move {
653 db.check_user_is_channel_participant(
654 &db.get_channel_internal(internal_channel_id, &*tx)
655 .await
656 .unwrap(),
657 guest,
658 &*tx,
659 )
660 .await
661 })
662 .await
663 .is_err(),);
664
665 db.transaction(|tx| async move {
666 db.check_user_is_channel_participant(
667 &db.get_channel_internal(public_channel_id, &*tx)
668 .await
669 .unwrap(),
670 guest,
671 &*tx,
672 )
673 .await
674 })
675 .await
676 .unwrap();
677
678 let mut members = db
679 .get_channel_participant_details(public_channel_id, admin)
680 .await
681 .unwrap();
682
683 members.sort_by_key(|member| member.user_id);
684
685 assert_eq!(
686 members,
687 &[
688 proto::ChannelMember {
689 user_id: admin.to_proto(),
690 kind: proto::channel_member::Kind::Member.into(),
691 role: proto::ChannelRole::Admin.into(),
692 },
693 proto::ChannelMember {
694 user_id: member.to_proto(),
695 kind: proto::channel_member::Kind::Member.into(),
696 role: proto::ChannelRole::Member.into(),
697 },
698 proto::ChannelMember {
699 user_id: guest.to_proto(),
700 kind: proto::channel_member::Kind::Member.into(),
701 role: proto::ChannelRole::Guest.into(),
702 },
703 ]
704 );
705
706 let channels = db.get_channels_for_user(guest).await.unwrap().channels;
707 assert_channel_tree(
708 channels,
709 &[(zed_channel, &[]), (public_channel_id, &[zed_channel])],
710 )
711}
712
713test_both_dbs!(
714 test_guest_access,
715 test_guest_access_postgres,
716 test_guest_access_sqlite
717);
718
719async fn test_guest_access(db: &Arc<Database>) {
720 let server = db.create_server("test").await.unwrap();
721
722 let admin = new_test_user(db, "admin@example.com").await;
723 let guest = new_test_user(db, "guest@example.com").await;
724 let guest_connection = new_test_connection(server);
725
726 let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
727 db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
728 .await
729 .unwrap();
730
731 assert!(db
732 .join_channel_chat(zed_channel, guest_connection, guest)
733 .await
734 .is_err());
735
736 db.join_channel(
737 zed_channel,
738 guest,
739 false,
740 guest_connection,
741 TEST_RELEASE_CHANNEL,
742 )
743 .await
744 .unwrap();
745
746 assert!(db
747 .join_channel_chat(zed_channel, guest_connection, guest)
748 .await
749 .is_ok())
750}
751
752#[track_caller]
753fn assert_channel_tree(actual: Vec<Channel>, expected: &[(ChannelId, &[ChannelId])]) {
754 let actual = actual
755 .iter()
756 .map(|channel| (channel.id, channel.parent_path.as_slice()))
757 .collect::<Vec<_>>();
758 pretty_assertions::assert_eq!(
759 actual,
760 expected.to_vec(),
761 "wrong channel ids and parent paths"
762 );
763}