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