channel_tests.rs

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