channel_tests.rs

   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}