channel_tests.rs

   1use crate::{
   2    db::{self, UserId},
   3    rpc::RECONNECT_TIMEOUT,
   4    tests::{room_participants, RoomParticipants, TestServer},
   5};
   6use call::ActiveCall;
   7use channel::{ChannelId, ChannelMembership, ChannelStore};
   8use client::User;
   9use futures::future::try_join_all;
  10use gpui::{executor::Deterministic, ModelHandle, TestAppContext};
  11use rpc::{
  12    proto::{self, ChannelRole},
  13    RECEIVE_TIMEOUT,
  14};
  15use std::sync::Arc;
  16
  17#[gpui::test]
  18async fn test_core_channels(
  19    deterministic: Arc<Deterministic>,
  20    cx_a: &mut TestAppContext,
  21    cx_b: &mut TestAppContext,
  22) {
  23    deterministic.forbid_parking();
  24    let mut server = TestServer::start(&deterministic).await;
  25    let client_a = server.create_client(cx_a, "user_a").await;
  26    let client_b = server.create_client(cx_b, "user_b").await;
  27
  28    let channel_a_id = client_a
  29        .channel_store()
  30        .update(cx_a, |channel_store, cx| {
  31            channel_store.create_channel("channel-a", None, cx)
  32        })
  33        .await
  34        .unwrap();
  35    let channel_b_id = client_a
  36        .channel_store()
  37        .update(cx_a, |channel_store, cx| {
  38            channel_store.create_channel("channel-b", Some(channel_a_id), cx)
  39        })
  40        .await
  41        .unwrap();
  42
  43    deterministic.run_until_parked();
  44    assert_channels(
  45        client_a.channel_store(),
  46        cx_a,
  47        &[
  48            ExpectedChannel {
  49                id: channel_a_id,
  50                name: "channel-a".to_string(),
  51                depth: 0,
  52                role: ChannelRole::Admin,
  53            },
  54            ExpectedChannel {
  55                id: channel_b_id,
  56                name: "channel-b".to_string(),
  57                depth: 1,
  58                role: ChannelRole::Admin,
  59            },
  60        ],
  61    );
  62
  63    client_b.channel_store().read_with(cx_b, |channels, _| {
  64        assert!(channels.ordered_channels().collect::<Vec<_>>().is_empty())
  65    });
  66
  67    // Invite client B to channel A as client A.
  68    client_a
  69        .channel_store()
  70        .update(cx_a, |store, cx| {
  71            assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
  72
  73            let invite = store.invite_member(
  74                channel_a_id,
  75                client_b.user_id().unwrap(),
  76                proto::ChannelRole::Member,
  77                cx,
  78            );
  79
  80            // Make sure we're synchronously storing the pending invite
  81            assert!(store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
  82            invite
  83        })
  84        .await
  85        .unwrap();
  86
  87    // Client A sees that B has been invited.
  88    deterministic.run_until_parked();
  89    assert_channel_invitations(
  90        client_b.channel_store(),
  91        cx_b,
  92        &[ExpectedChannel {
  93            id: channel_a_id,
  94            name: "channel-a".to_string(),
  95            depth: 0,
  96            role: ChannelRole::Member,
  97        }],
  98    );
  99
 100    let members = client_a
 101        .channel_store()
 102        .update(cx_a, |store, cx| {
 103            assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
 104            store.get_channel_member_details(channel_a_id, cx)
 105        })
 106        .await
 107        .unwrap();
 108    assert_members_eq(
 109        &members,
 110        &[
 111            (
 112                client_a.user_id().unwrap(),
 113                proto::ChannelRole::Admin,
 114                proto::channel_member::Kind::Member,
 115            ),
 116            (
 117                client_b.user_id().unwrap(),
 118                proto::ChannelRole::Member,
 119                proto::channel_member::Kind::Invitee,
 120            ),
 121        ],
 122    );
 123
 124    // Client B accepts the invitation.
 125    client_b
 126        .channel_store()
 127        .update(cx_b, |channels, cx| {
 128            channels.respond_to_channel_invite(channel_a_id, true, cx)
 129        })
 130        .await
 131        .unwrap();
 132    deterministic.run_until_parked();
 133
 134    // Client B now sees that they are a member of channel A and its existing subchannels.
 135    assert_channel_invitations(client_b.channel_store(), cx_b, &[]);
 136    assert_channels(
 137        client_b.channel_store(),
 138        cx_b,
 139        &[
 140            ExpectedChannel {
 141                id: channel_a_id,
 142                name: "channel-a".to_string(),
 143                role: ChannelRole::Member,
 144                depth: 0,
 145            },
 146            ExpectedChannel {
 147                id: channel_b_id,
 148                name: "channel-b".to_string(),
 149                role: ChannelRole::Member,
 150                depth: 1,
 151            },
 152        ],
 153    );
 154
 155    let channel_c_id = client_a
 156        .channel_store()
 157        .update(cx_a, |channel_store, cx| {
 158            channel_store.create_channel("channel-c", Some(channel_b_id), cx)
 159        })
 160        .await
 161        .unwrap();
 162
 163    deterministic.run_until_parked();
 164    assert_channels(
 165        client_b.channel_store(),
 166        cx_b,
 167        &[
 168            ExpectedChannel {
 169                id: channel_a_id,
 170                name: "channel-a".to_string(),
 171                role: ChannelRole::Member,
 172                depth: 0,
 173            },
 174            ExpectedChannel {
 175                id: channel_b_id,
 176                name: "channel-b".to_string(),
 177                role: ChannelRole::Member,
 178                depth: 1,
 179            },
 180            ExpectedChannel {
 181                id: channel_c_id,
 182                name: "channel-c".to_string(),
 183                role: ChannelRole::Member,
 184                depth: 2,
 185            },
 186        ],
 187    );
 188
 189    // Update client B's membership to channel A to be an admin.
 190    client_a
 191        .channel_store()
 192        .update(cx_a, |store, cx| {
 193            store.set_member_role(
 194                channel_a_id,
 195                client_b.user_id().unwrap(),
 196                proto::ChannelRole::Admin,
 197                cx,
 198            )
 199        })
 200        .await
 201        .unwrap();
 202    deterministic.run_until_parked();
 203
 204    // Observe that client B is now an admin of channel A, and that
 205    // their admin priveleges extend to subchannels of channel A.
 206    assert_channel_invitations(client_b.channel_store(), cx_b, &[]);
 207    assert_channels(
 208        client_b.channel_store(),
 209        cx_b,
 210        &[
 211            ExpectedChannel {
 212                id: channel_a_id,
 213                name: "channel-a".to_string(),
 214                depth: 0,
 215                role: ChannelRole::Admin,
 216            },
 217            ExpectedChannel {
 218                id: channel_b_id,
 219                name: "channel-b".to_string(),
 220                depth: 1,
 221                role: ChannelRole::Admin,
 222            },
 223            ExpectedChannel {
 224                id: channel_c_id,
 225                name: "channel-c".to_string(),
 226                depth: 2,
 227                role: ChannelRole::Admin,
 228            },
 229        ],
 230    );
 231
 232    // Client A deletes the channel, deletion also deletes subchannels.
 233    client_a
 234        .channel_store()
 235        .update(cx_a, |channel_store, _| {
 236            channel_store.remove_channel(channel_b_id)
 237        })
 238        .await
 239        .unwrap();
 240
 241    deterministic.run_until_parked();
 242    assert_channels(
 243        client_a.channel_store(),
 244        cx_a,
 245        &[ExpectedChannel {
 246            id: channel_a_id,
 247            name: "channel-a".to_string(),
 248            depth: 0,
 249            role: ChannelRole::Admin,
 250        }],
 251    );
 252    assert_channels(
 253        client_b.channel_store(),
 254        cx_b,
 255        &[ExpectedChannel {
 256            id: channel_a_id,
 257            name: "channel-a".to_string(),
 258            depth: 0,
 259            role: ChannelRole::Admin,
 260        }],
 261    );
 262
 263    // Remove client B
 264    client_a
 265        .channel_store()
 266        .update(cx_a, |channel_store, cx| {
 267            channel_store.remove_member(channel_a_id, client_b.user_id().unwrap(), cx)
 268        })
 269        .await
 270        .unwrap();
 271
 272    deterministic.run_until_parked();
 273
 274    // Client A still has their channel
 275    assert_channels(
 276        client_a.channel_store(),
 277        cx_a,
 278        &[ExpectedChannel {
 279            id: channel_a_id,
 280            name: "channel-a".to_string(),
 281            depth: 0,
 282            role: ChannelRole::Admin,
 283        }],
 284    );
 285
 286    // Client B no longer has access to the channel
 287    assert_channels(client_b.channel_store(), cx_b, &[]);
 288
 289    server.forbid_connections();
 290    server.disconnect_client(client_a.peer_id().unwrap());
 291    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
 292
 293    server
 294        .app_state
 295        .db
 296        .rename_channel(
 297            db::ChannelId::from_proto(channel_a_id),
 298            UserId::from_proto(client_a.id()),
 299            "channel-a-renamed",
 300        )
 301        .await
 302        .unwrap();
 303
 304    server.allow_connections();
 305    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
 306    assert_channels(
 307        client_a.channel_store(),
 308        cx_a,
 309        &[ExpectedChannel {
 310            id: channel_a_id,
 311            name: "channel-a-renamed".to_string(),
 312            depth: 0,
 313            role: ChannelRole::Admin,
 314        }],
 315    );
 316}
 317
 318#[track_caller]
 319fn assert_participants_eq(participants: &[Arc<User>], expected_partitipants: &[u64]) {
 320    assert_eq!(
 321        participants.iter().map(|p| p.id).collect::<Vec<_>>(),
 322        expected_partitipants
 323    );
 324}
 325
 326#[track_caller]
 327fn assert_members_eq(
 328    members: &[ChannelMembership],
 329    expected_members: &[(u64, proto::ChannelRole, proto::channel_member::Kind)],
 330) {
 331    assert_eq!(
 332        members
 333            .iter()
 334            .map(|member| (member.user.id, member.role, member.kind))
 335            .collect::<Vec<_>>(),
 336        expected_members
 337    );
 338}
 339
 340#[gpui::test]
 341async fn test_joining_channel_ancestor_member(
 342    deterministic: Arc<Deterministic>,
 343    cx_a: &mut TestAppContext,
 344    cx_b: &mut TestAppContext,
 345) {
 346    deterministic.forbid_parking();
 347    let mut server = TestServer::start(&deterministic).await;
 348
 349    let client_a = server.create_client(cx_a, "user_a").await;
 350    let client_b = server.create_client(cx_b, "user_b").await;
 351
 352    let parent_id = server
 353        .make_channel("parent", None, (&client_a, cx_a), &mut [(&client_b, cx_b)])
 354        .await;
 355
 356    let sub_id = client_a
 357        .channel_store()
 358        .update(cx_a, |channel_store, cx| {
 359            channel_store.create_channel("sub_channel", Some(parent_id), cx)
 360        })
 361        .await
 362        .unwrap();
 363
 364    let active_call_b = cx_b.read(ActiveCall::global);
 365
 366    assert!(active_call_b
 367        .update(cx_b, |active_call, cx| active_call.join_channel(sub_id, cx))
 368        .await
 369        .is_ok());
 370}
 371
 372#[gpui::test]
 373async fn test_channel_room(
 374    deterministic: Arc<Deterministic>,
 375    cx_a: &mut TestAppContext,
 376    cx_b: &mut TestAppContext,
 377    cx_c: &mut TestAppContext,
 378) {
 379    deterministic.forbid_parking();
 380    let mut server = TestServer::start(&deterministic).await;
 381    let client_a = server.create_client(cx_a, "user_a").await;
 382    let client_b = server.create_client(cx_b, "user_b").await;
 383    let client_c = server.create_client(cx_c, "user_c").await;
 384
 385    let zed_id = server
 386        .make_channel(
 387            "zed",
 388            None,
 389            (&client_a, cx_a),
 390            &mut [(&client_b, cx_b), (&client_c, cx_c)],
 391        )
 392        .await;
 393
 394    let active_call_a = cx_a.read(ActiveCall::global);
 395    let active_call_b = cx_b.read(ActiveCall::global);
 396
 397    active_call_a
 398        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
 399        .await
 400        .unwrap();
 401
 402    // Give everyone a chance to observe user A joining
 403    deterministic.run_until_parked();
 404    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 405    room_a.read_with(cx_a, |room, _| assert!(room.is_connected()));
 406
 407    client_a.channel_store().read_with(cx_a, |channels, _| {
 408        assert_participants_eq(
 409            channels.channel_participants(zed_id),
 410            &[client_a.user_id().unwrap()],
 411        );
 412    });
 413
 414    assert_channels(
 415        client_b.channel_store(),
 416        cx_b,
 417        &[ExpectedChannel {
 418            id: zed_id,
 419            name: "zed".to_string(),
 420            depth: 0,
 421            role: ChannelRole::Member,
 422        }],
 423    );
 424    client_b.channel_store().read_with(cx_b, |channels, _| {
 425        assert_participants_eq(
 426            channels.channel_participants(zed_id),
 427            &[client_a.user_id().unwrap()],
 428        );
 429    });
 430
 431    client_c.channel_store().read_with(cx_c, |channels, _| {
 432        assert_participants_eq(
 433            channels.channel_participants(zed_id),
 434            &[client_a.user_id().unwrap()],
 435        );
 436    });
 437
 438    active_call_b
 439        .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
 440        .await
 441        .unwrap();
 442
 443    deterministic.run_until_parked();
 444
 445    client_a.channel_store().read_with(cx_a, |channels, _| {
 446        assert_participants_eq(
 447            channels.channel_participants(zed_id),
 448            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 449        );
 450    });
 451
 452    client_b.channel_store().read_with(cx_b, |channels, _| {
 453        assert_participants_eq(
 454            channels.channel_participants(zed_id),
 455            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 456        );
 457    });
 458
 459    client_c.channel_store().read_with(cx_c, |channels, _| {
 460        assert_participants_eq(
 461            channels.channel_participants(zed_id),
 462            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 463        );
 464    });
 465
 466    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 467    room_a.read_with(cx_a, |room, _| assert!(room.is_connected()));
 468    assert_eq!(
 469        room_participants(&room_a, cx_a),
 470        RoomParticipants {
 471            remote: vec!["user_b".to_string()],
 472            pending: vec![]
 473        }
 474    );
 475
 476    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 477    room_b.read_with(cx_b, |room, _| assert!(room.is_connected()));
 478    assert_eq!(
 479        room_participants(&room_b, cx_b),
 480        RoomParticipants {
 481            remote: vec!["user_a".to_string()],
 482            pending: vec![]
 483        }
 484    );
 485
 486    // Make sure that leaving and rejoining works
 487
 488    active_call_a
 489        .update(cx_a, |active_call, cx| active_call.hang_up(cx))
 490        .await
 491        .unwrap();
 492
 493    deterministic.run_until_parked();
 494
 495    client_a.channel_store().read_with(cx_a, |channels, _| {
 496        assert_participants_eq(
 497            channels.channel_participants(zed_id),
 498            &[client_b.user_id().unwrap()],
 499        );
 500    });
 501
 502    client_b.channel_store().read_with(cx_b, |channels, _| {
 503        assert_participants_eq(
 504            channels.channel_participants(zed_id),
 505            &[client_b.user_id().unwrap()],
 506        );
 507    });
 508
 509    client_c.channel_store().read_with(cx_c, |channels, _| {
 510        assert_participants_eq(
 511            channels.channel_participants(zed_id),
 512            &[client_b.user_id().unwrap()],
 513        );
 514    });
 515
 516    active_call_b
 517        .update(cx_b, |active_call, cx| active_call.hang_up(cx))
 518        .await
 519        .unwrap();
 520
 521    deterministic.run_until_parked();
 522
 523    client_a.channel_store().read_with(cx_a, |channels, _| {
 524        assert_participants_eq(channels.channel_participants(zed_id), &[]);
 525    });
 526
 527    client_b.channel_store().read_with(cx_b, |channels, _| {
 528        assert_participants_eq(channels.channel_participants(zed_id), &[]);
 529    });
 530
 531    client_c.channel_store().read_with(cx_c, |channels, _| {
 532        assert_participants_eq(channels.channel_participants(zed_id), &[]);
 533    });
 534
 535    active_call_a
 536        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
 537        .await
 538        .unwrap();
 539
 540    active_call_b
 541        .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
 542        .await
 543        .unwrap();
 544
 545    deterministic.run_until_parked();
 546
 547    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 548    room_a.read_with(cx_a, |room, _| assert!(room.is_connected()));
 549    assert_eq!(
 550        room_participants(&room_a, cx_a),
 551        RoomParticipants {
 552            remote: vec!["user_b".to_string()],
 553            pending: vec![]
 554        }
 555    );
 556
 557    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 558    room_b.read_with(cx_b, |room, _| assert!(room.is_connected()));
 559    assert_eq!(
 560        room_participants(&room_b, cx_b),
 561        RoomParticipants {
 562            remote: vec!["user_a".to_string()],
 563            pending: vec![]
 564        }
 565    );
 566}
 567
 568#[gpui::test]
 569async fn test_channel_jumping(deterministic: Arc<Deterministic>, cx_a: &mut TestAppContext) {
 570    deterministic.forbid_parking();
 571    let mut server = TestServer::start(&deterministic).await;
 572    let client_a = server.create_client(cx_a, "user_a").await;
 573
 574    let zed_id = server
 575        .make_channel("zed", None, (&client_a, cx_a), &mut [])
 576        .await;
 577    let rust_id = server
 578        .make_channel("rust", None, (&client_a, cx_a), &mut [])
 579        .await;
 580
 581    let active_call_a = cx_a.read(ActiveCall::global);
 582
 583    active_call_a
 584        .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
 585        .await
 586        .unwrap();
 587
 588    // Give everything a chance to observe user A joining
 589    deterministic.run_until_parked();
 590
 591    client_a.channel_store().read_with(cx_a, |channels, _| {
 592        assert_participants_eq(
 593            channels.channel_participants(zed_id),
 594            &[client_a.user_id().unwrap()],
 595        );
 596        assert_participants_eq(channels.channel_participants(rust_id), &[]);
 597    });
 598
 599    active_call_a
 600        .update(cx_a, |active_call, cx| {
 601            active_call.join_channel(rust_id, cx)
 602        })
 603        .await
 604        .unwrap();
 605
 606    deterministic.run_until_parked();
 607
 608    client_a.channel_store().read_with(cx_a, |channels, _| {
 609        assert_participants_eq(channels.channel_participants(zed_id), &[]);
 610        assert_participants_eq(
 611            channels.channel_participants(rust_id),
 612            &[client_a.user_id().unwrap()],
 613        );
 614    });
 615}
 616
 617#[gpui::test]
 618async fn test_permissions_update_while_invited(
 619    deterministic: Arc<Deterministic>,
 620    cx_a: &mut TestAppContext,
 621    cx_b: &mut TestAppContext,
 622) {
 623    deterministic.forbid_parking();
 624    let mut server = TestServer::start(&deterministic).await;
 625    let client_a = server.create_client(cx_a, "user_a").await;
 626    let client_b = server.create_client(cx_b, "user_b").await;
 627
 628    let rust_id = server
 629        .make_channel("rust", None, (&client_a, cx_a), &mut [])
 630        .await;
 631
 632    client_a
 633        .channel_store()
 634        .update(cx_a, |channel_store, cx| {
 635            channel_store.invite_member(
 636                rust_id,
 637                client_b.user_id().unwrap(),
 638                proto::ChannelRole::Member,
 639                cx,
 640            )
 641        })
 642        .await
 643        .unwrap();
 644
 645    deterministic.run_until_parked();
 646
 647    assert_channel_invitations(
 648        client_b.channel_store(),
 649        cx_b,
 650        &[ExpectedChannel {
 651            depth: 0,
 652            id: rust_id,
 653            name: "rust".to_string(),
 654            role: ChannelRole::Member,
 655        }],
 656    );
 657    assert_channels(client_b.channel_store(), cx_b, &[]);
 658
 659    // Update B's invite before they've accepted it
 660    client_a
 661        .channel_store()
 662        .update(cx_a, |channel_store, cx| {
 663            channel_store.set_member_role(
 664                rust_id,
 665                client_b.user_id().unwrap(),
 666                proto::ChannelRole::Admin,
 667                cx,
 668            )
 669        })
 670        .await
 671        .unwrap();
 672
 673    deterministic.run_until_parked();
 674
 675    assert_channel_invitations(
 676        client_b.channel_store(),
 677        cx_b,
 678        &[ExpectedChannel {
 679            depth: 0,
 680            id: rust_id,
 681            name: "rust".to_string(),
 682            role: ChannelRole::Member,
 683        }],
 684    );
 685    assert_channels(client_b.channel_store(), cx_b, &[]);
 686}
 687
 688#[gpui::test]
 689async fn test_channel_rename(
 690    deterministic: Arc<Deterministic>,
 691    cx_a: &mut TestAppContext,
 692    cx_b: &mut TestAppContext,
 693) {
 694    deterministic.forbid_parking();
 695    let mut server = TestServer::start(&deterministic).await;
 696    let client_a = server.create_client(cx_a, "user_a").await;
 697    let client_b = server.create_client(cx_b, "user_b").await;
 698
 699    let rust_id = server
 700        .make_channel("rust", None, (&client_a, cx_a), &mut [(&client_b, cx_b)])
 701        .await;
 702
 703    // Rename the channel
 704    client_a
 705        .channel_store()
 706        .update(cx_a, |channel_store, cx| {
 707            channel_store.rename(rust_id, "#rust-archive", cx)
 708        })
 709        .await
 710        .unwrap();
 711
 712    deterministic.run_until_parked();
 713
 714    // Client A sees the channel with its new name.
 715    assert_channels(
 716        client_a.channel_store(),
 717        cx_a,
 718        &[ExpectedChannel {
 719            depth: 0,
 720            id: rust_id,
 721            name: "rust-archive".to_string(),
 722            role: ChannelRole::Admin,
 723        }],
 724    );
 725
 726    // Client B sees the channel with its new name.
 727    assert_channels(
 728        client_b.channel_store(),
 729        cx_b,
 730        &[ExpectedChannel {
 731            depth: 0,
 732            id: rust_id,
 733            name: "rust-archive".to_string(),
 734            role: ChannelRole::Member,
 735        }],
 736    );
 737}
 738
 739#[gpui::test]
 740async fn test_call_from_channel(
 741    deterministic: Arc<Deterministic>,
 742    cx_a: &mut TestAppContext,
 743    cx_b: &mut TestAppContext,
 744    cx_c: &mut TestAppContext,
 745) {
 746    deterministic.forbid_parking();
 747    let mut server = TestServer::start(&deterministic).await;
 748    let client_a = server.create_client(cx_a, "user_a").await;
 749    let client_b = server.create_client(cx_b, "user_b").await;
 750    let client_c = server.create_client(cx_c, "user_c").await;
 751    server
 752        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
 753        .await;
 754
 755    let channel_id = server
 756        .make_channel(
 757            "x",
 758            None,
 759            (&client_a, cx_a),
 760            &mut [(&client_b, cx_b), (&client_c, cx_c)],
 761        )
 762        .await;
 763
 764    let active_call_a = cx_a.read(ActiveCall::global);
 765    let active_call_b = cx_b.read(ActiveCall::global);
 766
 767    active_call_a
 768        .update(cx_a, |call, cx| call.join_channel(channel_id, cx))
 769        .await
 770        .unwrap();
 771
 772    // Client A calls client B while in the channel.
 773    active_call_a
 774        .update(cx_a, |call, cx| {
 775            call.invite(client_b.user_id().unwrap(), None, cx)
 776        })
 777        .await
 778        .unwrap();
 779
 780    // Client B accepts the call.
 781    deterministic.run_until_parked();
 782    active_call_b
 783        .update(cx_b, |call, cx| call.accept_incoming(cx))
 784        .await
 785        .unwrap();
 786
 787    // Client B sees that they are now in the channel
 788    deterministic.run_until_parked();
 789    active_call_b.read_with(cx_b, |call, cx| {
 790        assert_eq!(call.channel_id(cx), Some(channel_id));
 791    });
 792    client_b.channel_store().read_with(cx_b, |channels, _| {
 793        assert_participants_eq(
 794            channels.channel_participants(channel_id),
 795            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 796        );
 797    });
 798
 799    // Clients A and C also see that client B is in the channel.
 800    client_a.channel_store().read_with(cx_a, |channels, _| {
 801        assert_participants_eq(
 802            channels.channel_participants(channel_id),
 803            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 804        );
 805    });
 806    client_c.channel_store().read_with(cx_c, |channels, _| {
 807        assert_participants_eq(
 808            channels.channel_participants(channel_id),
 809            &[client_a.user_id().unwrap(), client_b.user_id().unwrap()],
 810        );
 811    });
 812}
 813
 814#[gpui::test]
 815async fn test_lost_channel_creation(
 816    deterministic: Arc<Deterministic>,
 817    cx_a: &mut TestAppContext,
 818    cx_b: &mut TestAppContext,
 819) {
 820    deterministic.forbid_parking();
 821    let mut server = TestServer::start(&deterministic).await;
 822    let client_a = server.create_client(cx_a, "user_a").await;
 823    let client_b = server.create_client(cx_b, "user_b").await;
 824
 825    server
 826        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
 827        .await;
 828
 829    let channel_id = server
 830        .make_channel("x", None, (&client_a, cx_a), &mut [])
 831        .await;
 832
 833    // Invite a member
 834    client_a
 835        .channel_store()
 836        .update(cx_a, |channel_store, cx| {
 837            channel_store.invite_member(
 838                channel_id,
 839                client_b.user_id().unwrap(),
 840                proto::ChannelRole::Member,
 841                cx,
 842            )
 843        })
 844        .await
 845        .unwrap();
 846
 847    deterministic.run_until_parked();
 848
 849    // Sanity check, B has the invitation
 850    assert_channel_invitations(
 851        client_b.channel_store(),
 852        cx_b,
 853        &[ExpectedChannel {
 854            depth: 0,
 855            id: channel_id,
 856            name: "x".to_string(),
 857            role: ChannelRole::Member,
 858        }],
 859    );
 860
 861    // A creates a subchannel while the invite is still pending.
 862    let subchannel_id = client_a
 863        .channel_store()
 864        .update(cx_a, |channel_store, cx| {
 865            channel_store.create_channel("subchannel", Some(channel_id), cx)
 866        })
 867        .await
 868        .unwrap();
 869
 870    deterministic.run_until_parked();
 871
 872    // Make sure A sees their new channel
 873    assert_channels(
 874        client_a.channel_store(),
 875        cx_a,
 876        &[
 877            ExpectedChannel {
 878                depth: 0,
 879                id: channel_id,
 880                name: "x".to_string(),
 881                role: ChannelRole::Admin,
 882            },
 883            ExpectedChannel {
 884                depth: 1,
 885                id: subchannel_id,
 886                name: "subchannel".to_string(),
 887                role: ChannelRole::Admin,
 888            },
 889        ],
 890    );
 891
 892    // Client B accepts the invite
 893    client_b
 894        .channel_store()
 895        .update(cx_b, |channel_store, cx| {
 896            channel_store.respond_to_channel_invite(channel_id, true, cx)
 897        })
 898        .await
 899        .unwrap();
 900
 901    deterministic.run_until_parked();
 902
 903    // Client B should now see the channel
 904    assert_channels(
 905        client_b.channel_store(),
 906        cx_b,
 907        &[
 908            ExpectedChannel {
 909                depth: 0,
 910                id: channel_id,
 911                name: "x".to_string(),
 912                role: ChannelRole::Member,
 913            },
 914            ExpectedChannel {
 915                depth: 1,
 916                id: subchannel_id,
 917                name: "subchannel".to_string(),
 918                role: ChannelRole::Member,
 919            },
 920        ],
 921    );
 922}
 923
 924#[gpui::test]
 925async fn test_channel_link_notifications(
 926    deterministic: Arc<Deterministic>,
 927    cx_a: &mut TestAppContext,
 928    cx_b: &mut TestAppContext,
 929    cx_c: &mut TestAppContext,
 930) {
 931    deterministic.forbid_parking();
 932
 933    let mut server = TestServer::start(&deterministic).await;
 934    let client_a = server.create_client(cx_a, "user_a").await;
 935    let client_b = server.create_client(cx_b, "user_b").await;
 936    let client_c = server.create_client(cx_c, "user_c").await;
 937
 938    let user_b = client_b.user_id().unwrap();
 939    let user_c = client_c.user_id().unwrap();
 940
 941    let channels = server
 942        .make_channel_tree(&[("zed", None)], (&client_a, cx_a))
 943        .await;
 944    let zed_channel = channels[0];
 945
 946    try_join_all(client_a.channel_store().update(cx_a, |channel_store, cx| {
 947        [
 948            channel_store.set_channel_visibility(zed_channel, proto::ChannelVisibility::Public, cx),
 949            channel_store.invite_member(zed_channel, user_b, proto::ChannelRole::Member, cx),
 950            channel_store.invite_member(zed_channel, user_c, proto::ChannelRole::Guest, cx),
 951        ]
 952    }))
 953    .await
 954    .unwrap();
 955
 956    deterministic.run_until_parked();
 957
 958    client_b
 959        .channel_store()
 960        .update(cx_b, |channel_store, cx| {
 961            channel_store.respond_to_channel_invite(zed_channel, true, cx)
 962        })
 963        .await
 964        .unwrap();
 965
 966    client_c
 967        .channel_store()
 968        .update(cx_c, |channel_store, cx| {
 969            channel_store.respond_to_channel_invite(zed_channel, true, cx)
 970        })
 971        .await
 972        .unwrap();
 973
 974    deterministic.run_until_parked();
 975
 976    // we have an admin (a), member (b) and guest (c) all part of the zed channel.
 977
 978    // create a new private channel, make it public, and move it under the previous one, and verify it shows for b and not c
 979    let active_channel = client_a
 980        .channel_store()
 981        .update(cx_a, |channel_store, cx| {
 982            channel_store.create_channel("active", Some(zed_channel), cx)
 983        })
 984        .await
 985        .unwrap();
 986
 987    // the new channel shows for b and not c
 988    assert_channels_list_shape(
 989        client_a.channel_store(),
 990        cx_a,
 991        &[(zed_channel, 0), (active_channel, 1)],
 992    );
 993    assert_channels_list_shape(
 994        client_b.channel_store(),
 995        cx_b,
 996        &[(zed_channel, 0), (active_channel, 1)],
 997    );
 998    assert_channels_list_shape(client_c.channel_store(), cx_c, &[(zed_channel, 0)]);
 999
1000    let vim_channel = client_a
1001        .channel_store()
1002        .update(cx_a, |channel_store, cx| {
1003            channel_store.create_channel("vim", None, cx)
1004        })
1005        .await
1006        .unwrap();
1007
1008    client_a
1009        .channel_store()
1010        .update(cx_a, |channel_store, cx| {
1011            channel_store.set_channel_visibility(vim_channel, proto::ChannelVisibility::Public, cx)
1012        })
1013        .await
1014        .unwrap();
1015
1016    client_a
1017        .channel_store()
1018        .update(cx_a, |channel_store, cx| {
1019            channel_store.move_channel(vim_channel, Some(active_channel), cx)
1020        })
1021        .await
1022        .unwrap();
1023
1024    deterministic.run_until_parked();
1025
1026    // the new channel shows for b and c
1027    assert_channels_list_shape(
1028        client_a.channel_store(),
1029        cx_a,
1030        &[(zed_channel, 0), (active_channel, 1), (vim_channel, 2)],
1031    );
1032    assert_channels_list_shape(
1033        client_b.channel_store(),
1034        cx_b,
1035        &[(zed_channel, 0), (active_channel, 1), (vim_channel, 2)],
1036    );
1037    assert_channels_list_shape(
1038        client_c.channel_store(),
1039        cx_c,
1040        &[(zed_channel, 0), (vim_channel, 1)],
1041    );
1042
1043    let helix_channel = client_a
1044        .channel_store()
1045        .update(cx_a, |channel_store, cx| {
1046            channel_store.create_channel("helix", None, cx)
1047        })
1048        .await
1049        .unwrap();
1050
1051    client_a
1052        .channel_store()
1053        .update(cx_a, |channel_store, cx| {
1054            channel_store.move_channel(helix_channel, Some(vim_channel), cx)
1055        })
1056        .await
1057        .unwrap();
1058
1059    client_a
1060        .channel_store()
1061        .update(cx_a, |channel_store, cx| {
1062            channel_store.set_channel_visibility(
1063                helix_channel,
1064                proto::ChannelVisibility::Public,
1065                cx,
1066            )
1067        })
1068        .await
1069        .unwrap();
1070
1071    // the new channel shows for b and c
1072    assert_channels_list_shape(
1073        client_b.channel_store(),
1074        cx_b,
1075        &[
1076            (zed_channel, 0),
1077            (active_channel, 1),
1078            (vim_channel, 2),
1079            (helix_channel, 3),
1080        ],
1081    );
1082    assert_channels_list_shape(
1083        client_c.channel_store(),
1084        cx_c,
1085        &[(zed_channel, 0), (vim_channel, 1), (helix_channel, 2)],
1086    );
1087
1088    client_a
1089        .channel_store()
1090        .update(cx_a, |channel_store, cx| {
1091            channel_store.set_channel_visibility(vim_channel, proto::ChannelVisibility::Members, cx)
1092        })
1093        .await
1094        .unwrap();
1095
1096    // the members-only channel is still shown for c, but hidden for b
1097    assert_channels_list_shape(
1098        client_b.channel_store(),
1099        cx_b,
1100        &[
1101            (zed_channel, 0),
1102            (active_channel, 1),
1103            (vim_channel, 2),
1104            (helix_channel, 3),
1105        ],
1106    );
1107    client_b
1108        .channel_store()
1109        .read_with(cx_b, |channel_store, _| {
1110            assert_eq!(
1111                channel_store
1112                    .channel_for_id(vim_channel)
1113                    .unwrap()
1114                    .visibility,
1115                proto::ChannelVisibility::Members
1116            )
1117        });
1118
1119    assert_channels_list_shape(client_c.channel_store(), cx_c, &[(zed_channel, 0)]);
1120}
1121
1122#[gpui::test]
1123async fn test_channel_membership_notifications(
1124    deterministic: Arc<Deterministic>,
1125    cx_a: &mut TestAppContext,
1126    cx_b: &mut TestAppContext,
1127) {
1128    deterministic.forbid_parking();
1129
1130    deterministic.forbid_parking();
1131
1132    let mut server = TestServer::start(&deterministic).await;
1133    let client_a = server.create_client(cx_a, "user_a").await;
1134    let client_b = server.create_client(cx_b, "user_c").await;
1135
1136    let user_b = client_b.user_id().unwrap();
1137
1138    let channels = server
1139        .make_channel_tree(
1140            &[
1141                ("zed", None),
1142                ("active", Some("zed")),
1143                ("vim", Some("active")),
1144            ],
1145            (&client_a, cx_a),
1146        )
1147        .await;
1148    let zed_channel = channels[0];
1149    let _active_channel = channels[1];
1150    let vim_channel = channels[2];
1151
1152    try_join_all(client_a.channel_store().update(cx_a, |channel_store, cx| {
1153        [
1154            channel_store.set_channel_visibility(zed_channel, proto::ChannelVisibility::Public, cx),
1155            channel_store.set_channel_visibility(vim_channel, proto::ChannelVisibility::Public, cx),
1156            channel_store.invite_member(vim_channel, user_b, proto::ChannelRole::Member, cx),
1157            channel_store.invite_member(zed_channel, user_b, proto::ChannelRole::Guest, cx),
1158        ]
1159    }))
1160    .await
1161    .unwrap();
1162
1163    deterministic.run_until_parked();
1164
1165    client_b
1166        .channel_store()
1167        .update(cx_b, |channel_store, cx| {
1168            channel_store.respond_to_channel_invite(zed_channel, true, cx)
1169        })
1170        .await
1171        .unwrap();
1172
1173    client_b
1174        .channel_store()
1175        .update(cx_b, |channel_store, cx| {
1176            channel_store.respond_to_channel_invite(vim_channel, true, cx)
1177        })
1178        .await
1179        .unwrap();
1180
1181    deterministic.run_until_parked();
1182
1183    // we have an admin (a), and a guest (b) with access to all of zed, and membership in vim.
1184    assert_channels(
1185        client_b.channel_store(),
1186        cx_b,
1187        &[
1188            ExpectedChannel {
1189                depth: 0,
1190                id: zed_channel,
1191                name: "zed".to_string(),
1192                role: ChannelRole::Guest,
1193            },
1194            ExpectedChannel {
1195                depth: 1,
1196                id: vim_channel,
1197                name: "vim".to_string(),
1198                role: ChannelRole::Member,
1199            },
1200        ],
1201    );
1202
1203    client_a
1204        .channel_store()
1205        .update(cx_a, |channel_store, cx| {
1206            channel_store.remove_member(vim_channel, user_b, cx)
1207        })
1208        .await
1209        .unwrap();
1210
1211    deterministic.run_until_parked();
1212
1213    assert_channels(
1214        client_b.channel_store(),
1215        cx_b,
1216        &[
1217            ExpectedChannel {
1218                depth: 0,
1219                id: zed_channel,
1220                name: "zed".to_string(),
1221                role: ChannelRole::Guest,
1222            },
1223            ExpectedChannel {
1224                depth: 1,
1225                id: vim_channel,
1226                name: "vim".to_string(),
1227                role: ChannelRole::Guest,
1228            },
1229        ],
1230    )
1231}
1232
1233#[gpui::test]
1234async fn test_guest_access(
1235    deterministic: Arc<Deterministic>,
1236    cx_a: &mut TestAppContext,
1237    cx_b: &mut TestAppContext,
1238) {
1239    deterministic.forbid_parking();
1240
1241    let mut server = TestServer::start(&deterministic).await;
1242    let client_a = server.create_client(cx_a, "user_a").await;
1243    let client_b = server.create_client(cx_b, "user_b").await;
1244
1245    let channels = server
1246        .make_channel_tree(
1247            &[("channel-a", None), ("channel-b", Some("channel-a"))],
1248            (&client_a, cx_a),
1249        )
1250        .await;
1251    let channel_a = channels[0];
1252    let channel_b = channels[1];
1253
1254    let active_call_b = cx_b.read(ActiveCall::global);
1255
1256    // Non-members should not be allowed to join
1257    assert!(active_call_b
1258        .update(cx_b, |call, cx| call.join_channel(channel_a, cx))
1259        .await
1260        .is_err());
1261
1262    // Make channels A and B public
1263    client_a
1264        .channel_store()
1265        .update(cx_a, |channel_store, cx| {
1266            channel_store.set_channel_visibility(channel_a, proto::ChannelVisibility::Public, cx)
1267        })
1268        .await
1269        .unwrap();
1270    client_a
1271        .channel_store()
1272        .update(cx_a, |channel_store, cx| {
1273            channel_store.set_channel_visibility(channel_b, proto::ChannelVisibility::Public, cx)
1274        })
1275        .await
1276        .unwrap();
1277
1278    // Client B joins channel A as a guest
1279    active_call_b
1280        .update(cx_b, |call, cx| call.join_channel(channel_a, cx))
1281        .await
1282        .unwrap();
1283
1284    deterministic.run_until_parked();
1285    assert_channels_list_shape(
1286        client_a.channel_store(),
1287        cx_a,
1288        &[(channel_a, 0), (channel_b, 1)],
1289    );
1290    assert_channels_list_shape(
1291        client_b.channel_store(),
1292        cx_b,
1293        &[(channel_a, 0), (channel_b, 1)],
1294    );
1295
1296    client_a.channel_store().update(cx_a, |channel_store, _| {
1297        let participants = channel_store.channel_participants(channel_a);
1298        assert_eq!(participants.len(), 1);
1299        assert_eq!(participants[0].id, client_b.user_id().unwrap());
1300    });
1301
1302    client_a
1303        .channel_store()
1304        .update(cx_a, |channel_store, cx| {
1305            channel_store.set_channel_visibility(channel_a, proto::ChannelVisibility::Members, cx)
1306        })
1307        .await
1308        .unwrap();
1309
1310    assert_channels_list_shape(client_b.channel_store(), cx_b, &[]);
1311
1312    active_call_b
1313        .update(cx_b, |call, cx| call.join_channel(channel_b, cx))
1314        .await
1315        .unwrap();
1316
1317    deterministic.run_until_parked();
1318    assert_channels_list_shape(client_b.channel_store(), cx_b, &[(channel_b, 0)]);
1319}
1320
1321#[gpui::test]
1322async fn test_invite_access(
1323    deterministic: Arc<Deterministic>,
1324    cx_a: &mut TestAppContext,
1325    cx_b: &mut TestAppContext,
1326) {
1327    deterministic.forbid_parking();
1328
1329    let mut server = TestServer::start(&deterministic).await;
1330    let client_a = server.create_client(cx_a, "user_a").await;
1331    let client_b = server.create_client(cx_b, "user_b").await;
1332
1333    let channels = server
1334        .make_channel_tree(
1335            &[("channel-a", None), ("channel-b", Some("channel-a"))],
1336            (&client_a, cx_a),
1337        )
1338        .await;
1339    let channel_a_id = channels[0];
1340    let channel_b_id = channels[0];
1341
1342    let active_call_b = cx_b.read(ActiveCall::global);
1343
1344    // should not be allowed to join
1345    assert!(active_call_b
1346        .update(cx_b, |call, cx| call.join_channel(channel_b_id, cx))
1347        .await
1348        .is_err());
1349
1350    client_a
1351        .channel_store()
1352        .update(cx_a, |channel_store, cx| {
1353            channel_store.invite_member(
1354                channel_a_id,
1355                client_b.user_id().unwrap(),
1356                ChannelRole::Member,
1357                cx,
1358            )
1359        })
1360        .await
1361        .unwrap();
1362
1363    active_call_b
1364        .update(cx_b, |call, cx| call.join_channel(channel_b_id, cx))
1365        .await
1366        .unwrap();
1367
1368    deterministic.run_until_parked();
1369
1370    client_b.channel_store().update(cx_b, |channel_store, _| {
1371        assert!(channel_store.channel_for_id(channel_b_id).is_some());
1372        assert!(channel_store.channel_for_id(channel_a_id).is_some());
1373    });
1374
1375    client_a.channel_store().update(cx_a, |channel_store, _| {
1376        let participants = channel_store.channel_participants(channel_b_id);
1377        assert_eq!(participants.len(), 1);
1378        assert_eq!(participants[0].id, client_b.user_id().unwrap());
1379    })
1380}
1381
1382#[gpui::test]
1383async fn test_channel_moving(
1384    deterministic: Arc<Deterministic>,
1385    cx_a: &mut TestAppContext,
1386    _cx_b: &mut TestAppContext,
1387    _cx_c: &mut TestAppContext,
1388) {
1389    deterministic.forbid_parking();
1390    let mut server = TestServer::start(&deterministic).await;
1391    let client_a = server.create_client(cx_a, "user_a").await;
1392    // let client_b = server.create_client(cx_b, "user_b").await;
1393    // let client_c = server.create_client(cx_c, "user_c").await;
1394
1395    let channels = server
1396        .make_channel_tree(
1397            &[
1398                ("channel-a", None),
1399                ("channel-b", Some("channel-a")),
1400                ("channel-c", Some("channel-b")),
1401                ("channel-d", Some("channel-c")),
1402            ],
1403            (&client_a, cx_a),
1404        )
1405        .await;
1406    let channel_a_id = channels[0];
1407    let channel_b_id = channels[1];
1408    let channel_c_id = channels[2];
1409    let channel_d_id = channels[3];
1410
1411    // Current shape:
1412    // a - b - c - d
1413    assert_channels_list_shape(
1414        client_a.channel_store(),
1415        cx_a,
1416        &[
1417            (channel_a_id, 0),
1418            (channel_b_id, 1),
1419            (channel_c_id, 2),
1420            (channel_d_id, 3),
1421        ],
1422    );
1423
1424    client_a
1425        .channel_store()
1426        .update(cx_a, |channel_store, cx| {
1427            channel_store.move_channel(channel_d_id, Some(channel_b_id), cx)
1428        })
1429        .await
1430        .unwrap();
1431
1432    // Current shape:
1433    //       /- d
1434    // a - b -- c
1435    assert_channels_list_shape(
1436        client_a.channel_store(),
1437        cx_a,
1438        &[
1439            (channel_a_id, 0),
1440            (channel_b_id, 1),
1441            (channel_c_id, 2),
1442            (channel_d_id, 2),
1443        ],
1444    );
1445}
1446
1447#[derive(Debug, PartialEq)]
1448struct ExpectedChannel {
1449    depth: usize,
1450    id: ChannelId,
1451    name: String,
1452    role: ChannelRole,
1453}
1454
1455#[track_caller]
1456fn assert_channel_invitations(
1457    channel_store: &ModelHandle<ChannelStore>,
1458    cx: &TestAppContext,
1459    expected_channels: &[ExpectedChannel],
1460) {
1461    let actual = channel_store.read_with(cx, |store, _| {
1462        store
1463            .channel_invitations()
1464            .iter()
1465            .map(|channel| ExpectedChannel {
1466                depth: 0,
1467                name: channel.name.clone(),
1468                id: channel.id,
1469                role: channel.role,
1470            })
1471            .collect::<Vec<_>>()
1472    });
1473    assert_eq!(actual, expected_channels);
1474}
1475
1476#[track_caller]
1477fn assert_channels(
1478    channel_store: &ModelHandle<ChannelStore>,
1479    cx: &TestAppContext,
1480    expected_channels: &[ExpectedChannel],
1481) {
1482    let actual = channel_store.read_with(cx, |store, _| {
1483        store
1484            .ordered_channels()
1485            .map(|(depth, channel)| ExpectedChannel {
1486                depth,
1487                name: channel.name.clone(),
1488                id: channel.id,
1489                role: channel.role,
1490            })
1491            .collect::<Vec<_>>()
1492    });
1493    pretty_assertions::assert_eq!(actual, expected_channels);
1494}
1495
1496#[track_caller]
1497fn assert_channels_list_shape(
1498    channel_store: &ModelHandle<ChannelStore>,
1499    cx: &TestAppContext,
1500    expected_channels: &[(u64, usize)],
1501) {
1502    cx.foreground().run_until_parked();
1503
1504    let actual = channel_store.read_with(cx, |store, _| {
1505        store
1506            .ordered_channels()
1507            .map(|(depth, channel)| (channel.id, depth))
1508            .collect::<Vec<_>>()
1509    });
1510    pretty_assertions::assert_eq!(actual, expected_channels);
1511}