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