channel_tests.rs

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