Add channel moving test

Mikayla created

Change summary

crates/collab/src/db/queries/channels.rs    |  10 
crates/collab/src/db/tests.rs               |   1 
crates/collab/src/db/tests/channel_tests.rs | 559 +++++++++++++++++++++++
crates/collab/src/db/tests/db_tests.rs      |   4 
4 files changed, 572 insertions(+), 2 deletions(-)

Detailed changes

crates/collab/src/db/queries/channels.rs 🔗

@@ -703,6 +703,16 @@ impl Database {
         })
         .await
     }
+
+    pub async fn move_channel(
+        &self,
+        user: UserId,
+        from: ChannelId,
+        to: Option<ChannelId>,
+        link: bool,
+    ) -> Result<()> {
+        self.transaction(|tx| async move { todo!() }).await
+    }
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]

crates/collab/src/db/tests/channel_tests.rs 🔗

@@ -0,0 +1,559 @@
+use rpc::{proto, ConnectionId};
+
+use crate::{
+    db::{Channel, Database, NewUserParams},
+    test_both_dbs,
+};
+use std::sync::Arc;
+
+test_both_dbs!(test_channels, test_channels_postgres, test_channels_sqlite);
+
+async fn test_channels(db: &Arc<Database>) {
+    let a_id = db
+        .create_user(
+            "user1@example.com",
+            false,
+            NewUserParams {
+                github_login: "user1".into(),
+                github_user_id: 5,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let b_id = db
+        .create_user(
+            "user2@example.com",
+            false,
+            NewUserParams {
+                github_login: "user2".into(),
+                github_user_id: 6,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let zed_id = db.create_root_channel("zed", "1", a_id).await.unwrap();
+
+    // Make sure that people cannot read channels they haven't been invited to
+    assert!(db.get_channel(zed_id, b_id).await.unwrap().is_none());
+
+    db.invite_channel_member(zed_id, b_id, a_id, false)
+        .await
+        .unwrap();
+
+    db.respond_to_channel_invite(zed_id, b_id, true)
+        .await
+        .unwrap();
+
+    let crdb_id = db
+        .create_channel("crdb", Some(zed_id), "2", a_id)
+        .await
+        .unwrap();
+    let livestreaming_id = db
+        .create_channel("livestreaming", Some(zed_id), "3", a_id)
+        .await
+        .unwrap();
+    let replace_id = db
+        .create_channel("replace", Some(zed_id), "4", a_id)
+        .await
+        .unwrap();
+
+    let mut members = db.get_channel_members(replace_id).await.unwrap();
+    members.sort();
+    assert_eq!(members, &[a_id, b_id]);
+
+    let rust_id = db.create_root_channel("rust", "5", a_id).await.unwrap();
+    let cargo_id = db
+        .create_channel("cargo", Some(rust_id), "6", a_id)
+        .await
+        .unwrap();
+
+    let cargo_ra_id = db
+        .create_channel("cargo-ra", Some(cargo_id), "7", a_id)
+        .await
+        .unwrap();
+
+    let result = db.get_channels_for_user(a_id).await.unwrap();
+    assert_eq!(
+        result.channels,
+        vec![
+            Channel {
+                id: zed_id,
+                name: "zed".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: livestreaming_id,
+                name: "livestreaming".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: replace_id,
+                name: "replace".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: rust_id,
+                name: "rust".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: cargo_id,
+                name: "cargo".to_string(),
+                parent_id: Some(rust_id),
+            },
+            Channel {
+                id: cargo_ra_id,
+                name: "cargo-ra".to_string(),
+                parent_id: Some(cargo_id),
+            }
+        ]
+    );
+
+    let result = db.get_channels_for_user(b_id).await.unwrap();
+    assert_eq!(
+        result.channels,
+        vec![
+            Channel {
+                id: zed_id,
+                name: "zed".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: livestreaming_id,
+                name: "livestreaming".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: replace_id,
+                name: "replace".to_string(),
+                parent_id: Some(zed_id),
+            },
+        ]
+    );
+
+    // Update member permissions
+    let set_subchannel_admin = db.set_channel_member_admin(crdb_id, a_id, b_id, true).await;
+    assert!(set_subchannel_admin.is_err());
+    let set_channel_admin = db.set_channel_member_admin(zed_id, a_id, b_id, true).await;
+    assert!(set_channel_admin.is_ok());
+
+    let result = db.get_channels_for_user(b_id).await.unwrap();
+    assert_eq!(
+        result.channels,
+        vec![
+            Channel {
+                id: zed_id,
+                name: "zed".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: livestreaming_id,
+                name: "livestreaming".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: replace_id,
+                name: "replace".to_string(),
+                parent_id: Some(zed_id),
+            },
+        ]
+    );
+
+    // Remove a single channel
+    db.remove_channel(crdb_id, a_id).await.unwrap();
+    assert!(db.get_channel(crdb_id, a_id).await.unwrap().is_none());
+
+    // Remove a channel tree
+    let (mut channel_ids, user_ids) = db.remove_channel(rust_id, a_id).await.unwrap();
+    channel_ids.sort();
+    assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
+    assert_eq!(user_ids, &[a_id]);
+
+    assert!(db.get_channel(rust_id, a_id).await.unwrap().is_none());
+    assert!(db.get_channel(cargo_id, a_id).await.unwrap().is_none());
+    assert!(db.get_channel(cargo_ra_id, a_id).await.unwrap().is_none());
+}
+
+test_both_dbs!(
+    test_joining_channels,
+    test_joining_channels_postgres,
+    test_joining_channels_sqlite
+);
+
+async fn test_joining_channels(db: &Arc<Database>) {
+    let owner_id = db.create_server("test").await.unwrap().0 as u32;
+
+    let user_1 = db
+        .create_user(
+            "user1@example.com",
+            false,
+            NewUserParams {
+                github_login: "user1".into(),
+                github_user_id: 5,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+    let user_2 = db
+        .create_user(
+            "user2@example.com",
+            false,
+            NewUserParams {
+                github_login: "user2".into(),
+                github_user_id: 6,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let channel_1 = db
+        .create_root_channel("channel_1", "1", user_1)
+        .await
+        .unwrap();
+    let room_1 = db.room_id_for_channel(channel_1).await.unwrap();
+
+    // can join a room with membership to its channel
+    let joined_room = db
+        .join_room(room_1, user_1, ConnectionId { owner_id, id: 1 })
+        .await
+        .unwrap();
+    assert_eq!(joined_room.room.participants.len(), 1);
+
+    drop(joined_room);
+    // cannot join a room without membership to its channel
+    assert!(db
+        .join_room(room_1, user_2, ConnectionId { owner_id, id: 1 })
+        .await
+        .is_err());
+}
+
+test_both_dbs!(
+    test_channel_invites,
+    test_channel_invites_postgres,
+    test_channel_invites_sqlite
+);
+
+async fn test_channel_invites(db: &Arc<Database>) {
+    db.create_server("test").await.unwrap();
+
+    let user_1 = db
+        .create_user(
+            "user1@example.com",
+            false,
+            NewUserParams {
+                github_login: "user1".into(),
+                github_user_id: 5,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+    let user_2 = db
+        .create_user(
+            "user2@example.com",
+            false,
+            NewUserParams {
+                github_login: "user2".into(),
+                github_user_id: 6,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let user_3 = db
+        .create_user(
+            "user3@example.com",
+            false,
+            NewUserParams {
+                github_login: "user3".into(),
+                github_user_id: 7,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let channel_1_1 = db
+        .create_root_channel("channel_1", "1", user_1)
+        .await
+        .unwrap();
+
+    let channel_1_2 = db
+        .create_root_channel("channel_2", "2", user_1)
+        .await
+        .unwrap();
+
+    db.invite_channel_member(channel_1_1, user_2, user_1, false)
+        .await
+        .unwrap();
+    db.invite_channel_member(channel_1_2, user_2, user_1, false)
+        .await
+        .unwrap();
+    db.invite_channel_member(channel_1_1, user_3, user_1, true)
+        .await
+        .unwrap();
+
+    let user_2_invites = db
+        .get_channel_invites_for_user(user_2) // -> [channel_1_1, channel_1_2]
+        .await
+        .unwrap()
+        .into_iter()
+        .map(|channel| channel.id)
+        .collect::<Vec<_>>();
+
+    assert_eq!(user_2_invites, &[channel_1_1, channel_1_2]);
+
+    let user_3_invites = db
+        .get_channel_invites_for_user(user_3) // -> [channel_1_1]
+        .await
+        .unwrap()
+        .into_iter()
+        .map(|channel| channel.id)
+        .collect::<Vec<_>>();
+
+    assert_eq!(user_3_invites, &[channel_1_1]);
+
+    let members = db
+        .get_channel_member_details(channel_1_1, user_1)
+        .await
+        .unwrap();
+    assert_eq!(
+        members,
+        &[
+            proto::ChannelMember {
+                user_id: user_1.to_proto(),
+                kind: proto::channel_member::Kind::Member.into(),
+                admin: true,
+            },
+            proto::ChannelMember {
+                user_id: user_2.to_proto(),
+                kind: proto::channel_member::Kind::Invitee.into(),
+                admin: false,
+            },
+            proto::ChannelMember {
+                user_id: user_3.to_proto(),
+                kind: proto::channel_member::Kind::Invitee.into(),
+                admin: true,
+            },
+        ]
+    );
+
+    db.respond_to_channel_invite(channel_1_1, user_2, true)
+        .await
+        .unwrap();
+
+    let channel_1_3 = db
+        .create_channel("channel_3", Some(channel_1_1), "1", user_1)
+        .await
+        .unwrap();
+
+    let members = db
+        .get_channel_member_details(channel_1_3, user_1)
+        .await
+        .unwrap();
+    assert_eq!(
+        members,
+        &[
+            proto::ChannelMember {
+                user_id: user_1.to_proto(),
+                kind: proto::channel_member::Kind::Member.into(),
+                admin: true,
+            },
+            proto::ChannelMember {
+                user_id: user_2.to_proto(),
+                kind: proto::channel_member::Kind::AncestorMember.into(),
+                admin: false,
+            },
+        ]
+    );
+}
+
+test_both_dbs!(
+    test_channel_renames,
+    test_channel_renames_postgres,
+    test_channel_renames_sqlite
+);
+
+async fn test_channel_renames(db: &Arc<Database>) {
+    db.create_server("test").await.unwrap();
+
+    let user_1 = db
+        .create_user(
+            "user1@example.com",
+            false,
+            NewUserParams {
+                github_login: "user1".into(),
+                github_user_id: 5,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let user_2 = db
+        .create_user(
+            "user2@example.com",
+            false,
+            NewUserParams {
+                github_login: "user2".into(),
+                github_user_id: 6,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let zed_id = db.create_root_channel("zed", "1", user_1).await.unwrap();
+
+    db.rename_channel(zed_id, user_1, "#zed-archive")
+        .await
+        .unwrap();
+
+    let zed_archive_id = zed_id;
+
+    let (channel, _) = db
+        .get_channel(zed_archive_id, user_1)
+        .await
+        .unwrap()
+        .unwrap();
+    assert_eq!(channel.name, "zed-archive");
+
+    let non_permissioned_rename = db
+        .rename_channel(zed_archive_id, user_2, "hacked-lol")
+        .await;
+    assert!(non_permissioned_rename.is_err());
+
+    let bad_name_rename = db.rename_channel(zed_id, user_1, "#").await;
+    assert!(bad_name_rename.is_err())
+}
+
+test_both_dbs!(
+    test_channels_moving,
+    test_channels_moving_postgres,
+    test_channels_moving_sqlite
+);
+
+async fn test_channels_moving(db: &Arc<Database>) {
+    let a_id = db
+        .create_user(
+            "user1@example.com",
+            false,
+            NewUserParams {
+                github_login: "user1".into(),
+                github_user_id: 5,
+                invite_count: 0,
+            },
+        )
+        .await
+        .unwrap()
+        .user_id;
+
+    let zed_id = db.create_root_channel("zed", "1", a_id).await.unwrap();
+
+    let crdb_id = db
+        .create_channel("crdb", Some(zed_id), "2", a_id)
+        .await
+        .unwrap();
+
+    let livestreaming_id = db
+        .create_channel("livestreaming", Some(crdb_id), "3", a_id)
+        .await
+        .unwrap();
+
+    // sanity check
+    let result = db.get_channels_for_user(a_id).await.unwrap();
+    assert_eq!(
+        result.channels,
+        vec![
+            Channel {
+                id: zed_id,
+                name: "zed".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: livestreaming_id,
+                name: "livestreaming".to_string(),
+                parent_id: Some(crdb_id),
+            },
+        ]
+    );
+
+    // Move channel up
+    db.move_channel(a_id, livestreaming_id, Some(zed_id), false)
+        .await
+        .unwrap();
+
+    // Attempt to make a cycle
+    assert!(db
+        .move_channel(a_id, zed_id, Some(livestreaming_id), false)
+        .await
+        .is_err());
+
+    // Make a link
+    db.move_channel(a_id, crdb_id, Some(livestreaming_id), true)
+        .await
+        .unwrap();
+
+    let result = db.get_channels_for_user(a_id).await.unwrap();
+    assert_eq!(
+        result.channels,
+        vec![
+            Channel {
+                id: zed_id,
+                name: "zed".to_string(),
+                parent_id: None,
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(zed_id),
+            },
+            Channel {
+                id: crdb_id,
+                name: "crdb".to_string(),
+                parent_id: Some(livestreaming_id),
+            },
+            Channel {
+                id: livestreaming_id,
+                name: "livestreaming".to_string(),
+                parent_id: Some(zed_id),
+            },
+        ]
+    );
+}

crates/collab/src/db/tests/db_tests.rs 🔗

@@ -794,11 +794,11 @@ async fn test_joining_channels(db: &Arc<Database>) {
                 github_login: "user2".into(),
                 github_user_id: 6,
                 invite_count: 0,
+
             },
         )
         .await
-        .unwrap()
-        .user_id;
+        .unwrap()        .user_id;
 
     let channel_1 = db
         .create_root_channel("channel_1", "1", user_1)