integration_tests.rs

   1use crate::{
   2    rpc::{CLEANUP_TIMEOUT, RECONNECT_TIMEOUT},
   3    tests::{TestClient, TestServer},
   4};
   5use call::{room, ActiveCall, ParticipantLocation, Room};
   6use client::{User, RECEIVE_TIMEOUT};
   7use collections::HashSet;
   8use editor::{
   9    ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo,
  10    Rename, ToOffset, ToggleCodeActions, Undo,
  11};
  12use fs::{FakeFs, Fs as _, LineEnding, RemoveOptions};
  13use futures::StreamExt as _;
  14use gpui::{
  15    executor::Deterministic, geometry::vector::vec2f, test::EmptyView, ModelHandle, TestAppContext,
  16    ViewHandle,
  17};
  18use language::{
  19    tree_sitter_rust, Anchor, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language,
  20    LanguageConfig, OffsetRangeExt, Point, Rope,
  21};
  22use live_kit_client::MacOSDisplay;
  23use project::{search::SearchQuery, DiagnosticSummary, Project, ProjectPath};
  24use rand::prelude::*;
  25use serde_json::json;
  26use settings::{Formatter, Settings};
  27use std::{
  28    cell::{Cell, RefCell},
  29    env, future, mem,
  30    path::{Path, PathBuf},
  31    rc::Rc,
  32    sync::Arc,
  33};
  34use unindent::Unindent as _;
  35use workspace::{
  36    item::ItemHandle as _, shared_screen::SharedScreen, SplitDirection, ToggleFollow, Workspace,
  37};
  38
  39#[ctor::ctor]
  40fn init_logger() {
  41    if std::env::var("RUST_LOG").is_ok() {
  42        env_logger::init();
  43    }
  44}
  45
  46#[gpui::test(iterations = 10)]
  47async fn test_basic_calls(
  48    deterministic: Arc<Deterministic>,
  49    cx_a: &mut TestAppContext,
  50    cx_b: &mut TestAppContext,
  51    cx_b2: &mut TestAppContext,
  52    cx_c: &mut TestAppContext,
  53) {
  54    deterministic.forbid_parking();
  55    let mut server = TestServer::start(&deterministic).await;
  56
  57    let client_a = server.create_client(cx_a, "user_a").await;
  58    let client_b = server.create_client(cx_b, "user_b").await;
  59    let client_c = server.create_client(cx_c, "user_c").await;
  60    server
  61        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
  62        .await;
  63
  64    let active_call_a = cx_a.read(ActiveCall::global);
  65    let active_call_b = cx_b.read(ActiveCall::global);
  66    let active_call_c = cx_c.read(ActiveCall::global);
  67
  68    // Call user B from client A.
  69    active_call_a
  70        .update(cx_a, |call, cx| {
  71            call.invite(client_b.user_id().unwrap(), None, cx)
  72        })
  73        .await
  74        .unwrap();
  75    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
  76    deterministic.run_until_parked();
  77    assert_eq!(
  78        room_participants(&room_a, cx_a),
  79        RoomParticipants {
  80            remote: Default::default(),
  81            pending: vec!["user_b".to_string()]
  82        }
  83    );
  84
  85    // User B receives the call.
  86    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
  87    let call_b = incoming_call_b.next().await.unwrap().unwrap();
  88    assert_eq!(call_b.calling_user.github_login, "user_a");
  89
  90    // User B connects via another client and also receives a ring on the newly-connected client.
  91    let _client_b2 = server.create_client(cx_b2, "user_b").await;
  92    let active_call_b2 = cx_b2.read(ActiveCall::global);
  93    let mut incoming_call_b2 = active_call_b2.read_with(cx_b2, |call, _| call.incoming());
  94    deterministic.run_until_parked();
  95    let call_b2 = incoming_call_b2.next().await.unwrap().unwrap();
  96    assert_eq!(call_b2.calling_user.github_login, "user_a");
  97
  98    // User B joins the room using the first client.
  99    active_call_b
 100        .update(cx_b, |call, cx| call.accept_incoming(cx))
 101        .await
 102        .unwrap();
 103    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 104    assert!(incoming_call_b.next().await.unwrap().is_none());
 105
 106    deterministic.run_until_parked();
 107    assert_eq!(
 108        room_participants(&room_a, cx_a),
 109        RoomParticipants {
 110            remote: vec!["user_b".to_string()],
 111            pending: Default::default()
 112        }
 113    );
 114    assert_eq!(
 115        room_participants(&room_b, cx_b),
 116        RoomParticipants {
 117            remote: vec!["user_a".to_string()],
 118            pending: Default::default()
 119        }
 120    );
 121
 122    // Call user C from client B.
 123    let mut incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
 124    active_call_b
 125        .update(cx_b, |call, cx| {
 126            call.invite(client_c.user_id().unwrap(), None, cx)
 127        })
 128        .await
 129        .unwrap();
 130
 131    deterministic.run_until_parked();
 132    assert_eq!(
 133        room_participants(&room_a, cx_a),
 134        RoomParticipants {
 135            remote: vec!["user_b".to_string()],
 136            pending: vec!["user_c".to_string()]
 137        }
 138    );
 139    assert_eq!(
 140        room_participants(&room_b, cx_b),
 141        RoomParticipants {
 142            remote: vec!["user_a".to_string()],
 143            pending: vec!["user_c".to_string()]
 144        }
 145    );
 146
 147    // User C receives the call, but declines it.
 148    let call_c = incoming_call_c.next().await.unwrap().unwrap();
 149    assert_eq!(call_c.calling_user.github_login, "user_b");
 150    active_call_c.update(cx_c, |call, _| call.decline_incoming().unwrap());
 151    assert!(incoming_call_c.next().await.unwrap().is_none());
 152
 153    deterministic.run_until_parked();
 154    assert_eq!(
 155        room_participants(&room_a, cx_a),
 156        RoomParticipants {
 157            remote: vec!["user_b".to_string()],
 158            pending: Default::default()
 159        }
 160    );
 161    assert_eq!(
 162        room_participants(&room_b, cx_b),
 163        RoomParticipants {
 164            remote: vec!["user_a".to_string()],
 165            pending: Default::default()
 166        }
 167    );
 168
 169    // Call user C again from user A.
 170    active_call_a
 171        .update(cx_a, |call, cx| {
 172            call.invite(client_c.user_id().unwrap(), None, cx)
 173        })
 174        .await
 175        .unwrap();
 176
 177    deterministic.run_until_parked();
 178    assert_eq!(
 179        room_participants(&room_a, cx_a),
 180        RoomParticipants {
 181            remote: vec!["user_b".to_string()],
 182            pending: vec!["user_c".to_string()]
 183        }
 184    );
 185    assert_eq!(
 186        room_participants(&room_b, cx_b),
 187        RoomParticipants {
 188            remote: vec!["user_a".to_string()],
 189            pending: vec!["user_c".to_string()]
 190        }
 191    );
 192
 193    // User C accepts the call.
 194    let call_c = incoming_call_c.next().await.unwrap().unwrap();
 195    assert_eq!(call_c.calling_user.github_login, "user_a");
 196    active_call_c
 197        .update(cx_c, |call, cx| call.accept_incoming(cx))
 198        .await
 199        .unwrap();
 200    assert!(incoming_call_c.next().await.unwrap().is_none());
 201    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 202
 203    deterministic.run_until_parked();
 204    assert_eq!(
 205        room_participants(&room_a, cx_a),
 206        RoomParticipants {
 207            remote: vec!["user_b".to_string(), "user_c".to_string()],
 208            pending: Default::default()
 209        }
 210    );
 211    assert_eq!(
 212        room_participants(&room_b, cx_b),
 213        RoomParticipants {
 214            remote: vec!["user_a".to_string(), "user_c".to_string()],
 215            pending: Default::default()
 216        }
 217    );
 218    assert_eq!(
 219        room_participants(&room_c, cx_c),
 220        RoomParticipants {
 221            remote: vec!["user_a".to_string(), "user_b".to_string()],
 222            pending: Default::default()
 223        }
 224    );
 225
 226    // User A shares their screen
 227    let display = MacOSDisplay::new();
 228    let events_b = active_call_events(cx_b);
 229    let events_c = active_call_events(cx_c);
 230    active_call_a
 231        .update(cx_a, |call, cx| {
 232            call.room().unwrap().update(cx, |room, cx| {
 233                room.set_display_sources(vec![display.clone()]);
 234                room.share_screen(cx)
 235            })
 236        })
 237        .await
 238        .unwrap();
 239
 240    deterministic.run_until_parked();
 241
 242    // User B observes the remote screen sharing track.
 243    assert_eq!(events_b.borrow().len(), 1);
 244    let event_b = events_b.borrow().first().unwrap().clone();
 245    if let call::room::Event::RemoteVideoTracksChanged { participant_id } = event_b {
 246        assert_eq!(participant_id, client_a.peer_id().unwrap());
 247        room_b.read_with(cx_b, |room, _| {
 248            assert_eq!(
 249                room.remote_participants()[&client_a.user_id().unwrap()]
 250                    .tracks
 251                    .len(),
 252                1
 253            );
 254        });
 255    } else {
 256        panic!("unexpected event")
 257    }
 258
 259    // User C observes the remote screen sharing track.
 260    assert_eq!(events_c.borrow().len(), 1);
 261    let event_c = events_c.borrow().first().unwrap().clone();
 262    if let call::room::Event::RemoteVideoTracksChanged { participant_id } = event_c {
 263        assert_eq!(participant_id, client_a.peer_id().unwrap());
 264        room_c.read_with(cx_c, |room, _| {
 265            assert_eq!(
 266                room.remote_participants()[&client_a.user_id().unwrap()]
 267                    .tracks
 268                    .len(),
 269                1
 270            );
 271        });
 272    } else {
 273        panic!("unexpected event")
 274    }
 275
 276    // User A leaves the room.
 277    active_call_a
 278        .update(cx_a, |call, cx| {
 279            let hang_up = call.hang_up(cx);
 280            assert!(call.room().is_none());
 281            hang_up
 282        })
 283        .await
 284        .unwrap();
 285    deterministic.run_until_parked();
 286    assert_eq!(
 287        room_participants(&room_a, cx_a),
 288        RoomParticipants {
 289            remote: Default::default(),
 290            pending: Default::default()
 291        }
 292    );
 293    assert_eq!(
 294        room_participants(&room_b, cx_b),
 295        RoomParticipants {
 296            remote: vec!["user_c".to_string()],
 297            pending: Default::default()
 298        }
 299    );
 300    assert_eq!(
 301        room_participants(&room_c, cx_c),
 302        RoomParticipants {
 303            remote: vec!["user_b".to_string()],
 304            pending: Default::default()
 305        }
 306    );
 307
 308    // User B gets disconnected from the LiveKit server, which causes them
 309    // to automatically leave the room. User C leaves the room as well because
 310    // nobody else is in there.
 311    server
 312        .test_live_kit_server
 313        .disconnect_client(client_b.user_id().unwrap().to_string())
 314        .await;
 315    deterministic.run_until_parked();
 316    active_call_b.read_with(cx_b, |call, _| assert!(call.room().is_none()));
 317    active_call_c.read_with(cx_c, |call, _| assert!(call.room().is_none()));
 318    assert_eq!(
 319        room_participants(&room_a, cx_a),
 320        RoomParticipants {
 321            remote: Default::default(),
 322            pending: Default::default()
 323        }
 324    );
 325    assert_eq!(
 326        room_participants(&room_b, cx_b),
 327        RoomParticipants {
 328            remote: Default::default(),
 329            pending: Default::default()
 330        }
 331    );
 332    assert_eq!(
 333        room_participants(&room_c, cx_c),
 334        RoomParticipants {
 335            remote: Default::default(),
 336            pending: Default::default()
 337        }
 338    );
 339}
 340
 341#[gpui::test(iterations = 10)]
 342async fn test_calling_multiple_users_simultaneously(
 343    deterministic: Arc<Deterministic>,
 344    cx_a: &mut TestAppContext,
 345    cx_b: &mut TestAppContext,
 346    cx_c: &mut TestAppContext,
 347    cx_d: &mut TestAppContext,
 348) {
 349    deterministic.forbid_parking();
 350    let mut server = TestServer::start(&deterministic).await;
 351
 352    let client_a = server.create_client(cx_a, "user_a").await;
 353    let client_b = server.create_client(cx_b, "user_b").await;
 354    let client_c = server.create_client(cx_c, "user_c").await;
 355    let client_d = server.create_client(cx_d, "user_d").await;
 356    server
 357        .make_contacts(&mut [
 358            (&client_a, cx_a),
 359            (&client_b, cx_b),
 360            (&client_c, cx_c),
 361            (&client_d, cx_d),
 362        ])
 363        .await;
 364
 365    let active_call_a = cx_a.read(ActiveCall::global);
 366    let active_call_b = cx_b.read(ActiveCall::global);
 367    let active_call_c = cx_c.read(ActiveCall::global);
 368    let active_call_d = cx_d.read(ActiveCall::global);
 369
 370    // Simultaneously call user B and user C from client A.
 371    let b_invite = active_call_a.update(cx_a, |call, cx| {
 372        call.invite(client_b.user_id().unwrap(), None, cx)
 373    });
 374    let c_invite = active_call_a.update(cx_a, |call, cx| {
 375        call.invite(client_c.user_id().unwrap(), None, cx)
 376    });
 377    b_invite.await.unwrap();
 378    c_invite.await.unwrap();
 379
 380    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 381    deterministic.run_until_parked();
 382    assert_eq!(
 383        room_participants(&room_a, cx_a),
 384        RoomParticipants {
 385            remote: Default::default(),
 386            pending: vec!["user_b".to_string(), "user_c".to_string()]
 387        }
 388    );
 389
 390    // Call client D from client A.
 391    active_call_a
 392        .update(cx_a, |call, cx| {
 393            call.invite(client_d.user_id().unwrap(), None, cx)
 394        })
 395        .await
 396        .unwrap();
 397    deterministic.run_until_parked();
 398    assert_eq!(
 399        room_participants(&room_a, cx_a),
 400        RoomParticipants {
 401            remote: Default::default(),
 402            pending: vec![
 403                "user_b".to_string(),
 404                "user_c".to_string(),
 405                "user_d".to_string()
 406            ]
 407        }
 408    );
 409
 410    // Accept the call on all clients simultaneously.
 411    let accept_b = active_call_b.update(cx_b, |call, cx| call.accept_incoming(cx));
 412    let accept_c = active_call_c.update(cx_c, |call, cx| call.accept_incoming(cx));
 413    let accept_d = active_call_d.update(cx_d, |call, cx| call.accept_incoming(cx));
 414    accept_b.await.unwrap();
 415    accept_c.await.unwrap();
 416    accept_d.await.unwrap();
 417
 418    deterministic.run_until_parked();
 419
 420    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 421    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 422    let room_d = active_call_d.read_with(cx_d, |call, _| call.room().unwrap().clone());
 423    assert_eq!(
 424        room_participants(&room_a, cx_a),
 425        RoomParticipants {
 426            remote: vec![
 427                "user_b".to_string(),
 428                "user_c".to_string(),
 429                "user_d".to_string(),
 430            ],
 431            pending: Default::default()
 432        }
 433    );
 434    assert_eq!(
 435        room_participants(&room_b, cx_b),
 436        RoomParticipants {
 437            remote: vec![
 438                "user_a".to_string(),
 439                "user_c".to_string(),
 440                "user_d".to_string(),
 441            ],
 442            pending: Default::default()
 443        }
 444    );
 445    assert_eq!(
 446        room_participants(&room_c, cx_c),
 447        RoomParticipants {
 448            remote: vec![
 449                "user_a".to_string(),
 450                "user_b".to_string(),
 451                "user_d".to_string(),
 452            ],
 453            pending: Default::default()
 454        }
 455    );
 456    assert_eq!(
 457        room_participants(&room_d, cx_d),
 458        RoomParticipants {
 459            remote: vec![
 460                "user_a".to_string(),
 461                "user_b".to_string(),
 462                "user_c".to_string(),
 463            ],
 464            pending: Default::default()
 465        }
 466    );
 467}
 468
 469#[gpui::test(iterations = 10)]
 470async fn test_room_uniqueness(
 471    deterministic: Arc<Deterministic>,
 472    cx_a: &mut TestAppContext,
 473    cx_a2: &mut TestAppContext,
 474    cx_b: &mut TestAppContext,
 475    cx_b2: &mut TestAppContext,
 476    cx_c: &mut TestAppContext,
 477) {
 478    deterministic.forbid_parking();
 479    let mut server = TestServer::start(&deterministic).await;
 480    let client_a = server.create_client(cx_a, "user_a").await;
 481    let _client_a2 = server.create_client(cx_a2, "user_a").await;
 482    let client_b = server.create_client(cx_b, "user_b").await;
 483    let _client_b2 = server.create_client(cx_b2, "user_b").await;
 484    let client_c = server.create_client(cx_c, "user_c").await;
 485    server
 486        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
 487        .await;
 488
 489    let active_call_a = cx_a.read(ActiveCall::global);
 490    let active_call_a2 = cx_a2.read(ActiveCall::global);
 491    let active_call_b = cx_b.read(ActiveCall::global);
 492    let active_call_b2 = cx_b2.read(ActiveCall::global);
 493    let active_call_c = cx_c.read(ActiveCall::global);
 494
 495    // Call user B from client A.
 496    active_call_a
 497        .update(cx_a, |call, cx| {
 498            call.invite(client_b.user_id().unwrap(), None, cx)
 499        })
 500        .await
 501        .unwrap();
 502
 503    // Ensure a new room can't be created given user A just created one.
 504    active_call_a2
 505        .update(cx_a2, |call, cx| {
 506            call.invite(client_c.user_id().unwrap(), None, cx)
 507        })
 508        .await
 509        .unwrap_err();
 510    active_call_a2.read_with(cx_a2, |call, _| assert!(call.room().is_none()));
 511
 512    // User B receives the call from user A.
 513    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 514    let call_b1 = incoming_call_b.next().await.unwrap().unwrap();
 515    assert_eq!(call_b1.calling_user.github_login, "user_a");
 516
 517    // Ensure calling users A and B from client C fails.
 518    active_call_c
 519        .update(cx_c, |call, cx| {
 520            call.invite(client_a.user_id().unwrap(), None, cx)
 521        })
 522        .await
 523        .unwrap_err();
 524    active_call_c
 525        .update(cx_c, |call, cx| {
 526            call.invite(client_b.user_id().unwrap(), None, cx)
 527        })
 528        .await
 529        .unwrap_err();
 530
 531    // Ensure User B can't create a room while they still have an incoming call.
 532    active_call_b2
 533        .update(cx_b2, |call, cx| {
 534            call.invite(client_c.user_id().unwrap(), None, cx)
 535        })
 536        .await
 537        .unwrap_err();
 538    active_call_b2.read_with(cx_b2, |call, _| assert!(call.room().is_none()));
 539
 540    // User B joins the room and calling them after they've joined still fails.
 541    active_call_b
 542        .update(cx_b, |call, cx| call.accept_incoming(cx))
 543        .await
 544        .unwrap();
 545    active_call_c
 546        .update(cx_c, |call, cx| {
 547            call.invite(client_b.user_id().unwrap(), None, cx)
 548        })
 549        .await
 550        .unwrap_err();
 551
 552    // Ensure User B can't create a room while they belong to another room.
 553    active_call_b2
 554        .update(cx_b2, |call, cx| {
 555            call.invite(client_c.user_id().unwrap(), None, cx)
 556        })
 557        .await
 558        .unwrap_err();
 559    active_call_b2.read_with(cx_b2, |call, _| assert!(call.room().is_none()));
 560
 561    // Client C can successfully call client B after client B leaves the room.
 562    active_call_b
 563        .update(cx_b, |call, cx| call.hang_up(cx))
 564        .await
 565        .unwrap();
 566    deterministic.run_until_parked();
 567    active_call_c
 568        .update(cx_c, |call, cx| {
 569            call.invite(client_b.user_id().unwrap(), None, cx)
 570        })
 571        .await
 572        .unwrap();
 573    deterministic.run_until_parked();
 574    let call_b2 = incoming_call_b.next().await.unwrap().unwrap();
 575    assert_eq!(call_b2.calling_user.github_login, "user_c");
 576}
 577
 578#[gpui::test(iterations = 10)]
 579async fn test_client_disconnecting_from_room(
 580    deterministic: Arc<Deterministic>,
 581    cx_a: &mut TestAppContext,
 582    cx_b: &mut TestAppContext,
 583) {
 584    deterministic.forbid_parking();
 585    let mut server = TestServer::start(&deterministic).await;
 586    let client_a = server.create_client(cx_a, "user_a").await;
 587    let client_b = server.create_client(cx_b, "user_b").await;
 588    server
 589        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
 590        .await;
 591
 592    let active_call_a = cx_a.read(ActiveCall::global);
 593    let active_call_b = cx_b.read(ActiveCall::global);
 594
 595    // Call user B from client A.
 596    active_call_a
 597        .update(cx_a, |call, cx| {
 598            call.invite(client_b.user_id().unwrap(), None, cx)
 599        })
 600        .await
 601        .unwrap();
 602    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 603
 604    // User B receives the call and joins the room.
 605    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 606    incoming_call_b.next().await.unwrap().unwrap();
 607    active_call_b
 608        .update(cx_b, |call, cx| call.accept_incoming(cx))
 609        .await
 610        .unwrap();
 611    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 612    deterministic.run_until_parked();
 613    assert_eq!(
 614        room_participants(&room_a, cx_a),
 615        RoomParticipants {
 616            remote: vec!["user_b".to_string()],
 617            pending: Default::default()
 618        }
 619    );
 620    assert_eq!(
 621        room_participants(&room_b, cx_b),
 622        RoomParticipants {
 623            remote: vec!["user_a".to_string()],
 624            pending: Default::default()
 625        }
 626    );
 627
 628    // User A automatically reconnects to the room upon disconnection.
 629    server.disconnect_client(client_a.peer_id().unwrap());
 630    deterministic.advance_clock(RECEIVE_TIMEOUT);
 631    deterministic.run_until_parked();
 632    assert_eq!(
 633        room_participants(&room_a, cx_a),
 634        RoomParticipants {
 635            remote: vec!["user_b".to_string()],
 636            pending: Default::default()
 637        }
 638    );
 639    assert_eq!(
 640        room_participants(&room_b, cx_b),
 641        RoomParticipants {
 642            remote: vec!["user_a".to_string()],
 643            pending: Default::default()
 644        }
 645    );
 646
 647    // When user A disconnects, both client A and B clear their room on the active call.
 648    server.forbid_connections();
 649    server.disconnect_client(client_a.peer_id().unwrap());
 650    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
 651    active_call_a.read_with(cx_a, |call, _| assert!(call.room().is_none()));
 652    active_call_b.read_with(cx_b, |call, _| assert!(call.room().is_none()));
 653    assert_eq!(
 654        room_participants(&room_a, cx_a),
 655        RoomParticipants {
 656            remote: Default::default(),
 657            pending: Default::default()
 658        }
 659    );
 660    assert_eq!(
 661        room_participants(&room_b, cx_b),
 662        RoomParticipants {
 663            remote: Default::default(),
 664            pending: Default::default()
 665        }
 666    );
 667
 668    // Allow user A to reconnect to the server.
 669    server.allow_connections();
 670    deterministic.advance_clock(RECEIVE_TIMEOUT);
 671
 672    // Call user B again from client A.
 673    active_call_a
 674        .update(cx_a, |call, cx| {
 675            call.invite(client_b.user_id().unwrap(), None, cx)
 676        })
 677        .await
 678        .unwrap();
 679    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 680
 681    // User B receives the call and joins the room.
 682    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 683    incoming_call_b.next().await.unwrap().unwrap();
 684    active_call_b
 685        .update(cx_b, |call, cx| call.accept_incoming(cx))
 686        .await
 687        .unwrap();
 688    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 689    deterministic.run_until_parked();
 690    assert_eq!(
 691        room_participants(&room_a, cx_a),
 692        RoomParticipants {
 693            remote: vec!["user_b".to_string()],
 694            pending: Default::default()
 695        }
 696    );
 697    assert_eq!(
 698        room_participants(&room_b, cx_b),
 699        RoomParticipants {
 700            remote: vec!["user_a".to_string()],
 701            pending: Default::default()
 702        }
 703    );
 704
 705    // User B gets disconnected from the LiveKit server, which causes it
 706    // to automatically leave the room.
 707    server
 708        .test_live_kit_server
 709        .disconnect_client(client_b.user_id().unwrap().to_string())
 710        .await;
 711    deterministic.run_until_parked();
 712    active_call_a.update(cx_a, |call, _| assert!(call.room().is_none()));
 713    active_call_b.update(cx_b, |call, _| assert!(call.room().is_none()));
 714    assert_eq!(
 715        room_participants(&room_a, cx_a),
 716        RoomParticipants {
 717            remote: Default::default(),
 718            pending: Default::default()
 719        }
 720    );
 721    assert_eq!(
 722        room_participants(&room_b, cx_b),
 723        RoomParticipants {
 724            remote: Default::default(),
 725            pending: Default::default()
 726        }
 727    );
 728}
 729
 730#[gpui::test(iterations = 10)]
 731async fn test_server_restarts(
 732    deterministic: Arc<Deterministic>,
 733    cx_a: &mut TestAppContext,
 734    cx_b: &mut TestAppContext,
 735    cx_c: &mut TestAppContext,
 736    cx_d: &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    client_a
 742        .fs
 743        .insert_tree("/a", json!({ "a.txt": "a-contents" }))
 744        .await;
 745
 746    // Invite client B to collaborate on a project
 747    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
 748
 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    let client_d = server.create_client(cx_d, "user_d").await;
 752    server
 753        .make_contacts(&mut [
 754            (&client_a, cx_a),
 755            (&client_b, cx_b),
 756            (&client_c, cx_c),
 757            (&client_d, cx_d),
 758        ])
 759        .await;
 760
 761    let active_call_a = cx_a.read(ActiveCall::global);
 762    let active_call_b = cx_b.read(ActiveCall::global);
 763    let active_call_c = cx_c.read(ActiveCall::global);
 764    let active_call_d = cx_d.read(ActiveCall::global);
 765
 766    // User A calls users B, C, and D.
 767    active_call_a
 768        .update(cx_a, |call, cx| {
 769            call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
 770        })
 771        .await
 772        .unwrap();
 773    active_call_a
 774        .update(cx_a, |call, cx| {
 775            call.invite(client_c.user_id().unwrap(), Some(project_a.clone()), cx)
 776        })
 777        .await
 778        .unwrap();
 779    active_call_a
 780        .update(cx_a, |call, cx| {
 781            call.invite(client_d.user_id().unwrap(), Some(project_a.clone()), cx)
 782        })
 783        .await
 784        .unwrap();
 785    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 786
 787    // User B receives the call and joins the room.
 788    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 789    assert!(incoming_call_b.next().await.unwrap().is_some());
 790    active_call_b
 791        .update(cx_b, |call, cx| call.accept_incoming(cx))
 792        .await
 793        .unwrap();
 794    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 795
 796    // User C receives the call and joins the room.
 797    let mut incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
 798    assert!(incoming_call_c.next().await.unwrap().is_some());
 799    active_call_c
 800        .update(cx_c, |call, cx| call.accept_incoming(cx))
 801        .await
 802        .unwrap();
 803    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 804
 805    // User D receives the call but doesn't join the room yet.
 806    let mut incoming_call_d = active_call_d.read_with(cx_d, |call, _| call.incoming());
 807    assert!(incoming_call_d.next().await.unwrap().is_some());
 808
 809    deterministic.run_until_parked();
 810    assert_eq!(
 811        room_participants(&room_a, cx_a),
 812        RoomParticipants {
 813            remote: vec!["user_b".to_string(), "user_c".to_string()],
 814            pending: vec!["user_d".to_string()]
 815        }
 816    );
 817    assert_eq!(
 818        room_participants(&room_b, cx_b),
 819        RoomParticipants {
 820            remote: vec!["user_a".to_string(), "user_c".to_string()],
 821            pending: vec!["user_d".to_string()]
 822        }
 823    );
 824    assert_eq!(
 825        room_participants(&room_c, cx_c),
 826        RoomParticipants {
 827            remote: vec!["user_a".to_string(), "user_b".to_string()],
 828            pending: vec!["user_d".to_string()]
 829        }
 830    );
 831
 832    // The server is torn down.
 833    server.reset().await;
 834
 835    // Users A and B reconnect to the call. User C has troubles reconnecting, so it leaves the room.
 836    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
 837    deterministic.advance_clock(RECONNECT_TIMEOUT);
 838    assert_eq!(
 839        room_participants(&room_a, cx_a),
 840        RoomParticipants {
 841            remote: vec!["user_b".to_string(), "user_c".to_string()],
 842            pending: vec!["user_d".to_string()]
 843        }
 844    );
 845    assert_eq!(
 846        room_participants(&room_b, cx_b),
 847        RoomParticipants {
 848            remote: vec!["user_a".to_string(), "user_c".to_string()],
 849            pending: vec!["user_d".to_string()]
 850        }
 851    );
 852    assert_eq!(
 853        room_participants(&room_c, cx_c),
 854        RoomParticipants {
 855            remote: vec![],
 856            pending: vec![]
 857        }
 858    );
 859
 860    // User D is notified again of the incoming call and accepts it.
 861    assert!(incoming_call_d.next().await.unwrap().is_some());
 862    active_call_d
 863        .update(cx_d, |call, cx| call.accept_incoming(cx))
 864        .await
 865        .unwrap();
 866    deterministic.run_until_parked();
 867    let room_d = active_call_d.read_with(cx_d, |call, _| call.room().unwrap().clone());
 868    assert_eq!(
 869        room_participants(&room_a, cx_a),
 870        RoomParticipants {
 871            remote: vec![
 872                "user_b".to_string(),
 873                "user_c".to_string(),
 874                "user_d".to_string(),
 875            ],
 876            pending: vec![]
 877        }
 878    );
 879    assert_eq!(
 880        room_participants(&room_b, cx_b),
 881        RoomParticipants {
 882            remote: vec![
 883                "user_a".to_string(),
 884                "user_c".to_string(),
 885                "user_d".to_string(),
 886            ],
 887            pending: vec![]
 888        }
 889    );
 890    assert_eq!(
 891        room_participants(&room_c, cx_c),
 892        RoomParticipants {
 893            remote: vec![],
 894            pending: vec![]
 895        }
 896    );
 897    assert_eq!(
 898        room_participants(&room_d, cx_d),
 899        RoomParticipants {
 900            remote: vec![
 901                "user_a".to_string(),
 902                "user_b".to_string(),
 903                "user_c".to_string(),
 904            ],
 905            pending: vec![]
 906        }
 907    );
 908
 909    // The server finishes restarting, cleaning up stale connections.
 910    server.start().await.unwrap();
 911    deterministic.advance_clock(CLEANUP_TIMEOUT);
 912    assert_eq!(
 913        room_participants(&room_a, cx_a),
 914        RoomParticipants {
 915            remote: vec!["user_b".to_string(), "user_d".to_string()],
 916            pending: vec![]
 917        }
 918    );
 919    assert_eq!(
 920        room_participants(&room_b, cx_b),
 921        RoomParticipants {
 922            remote: vec!["user_a".to_string(), "user_d".to_string()],
 923            pending: vec![]
 924        }
 925    );
 926    assert_eq!(
 927        room_participants(&room_c, cx_c),
 928        RoomParticipants {
 929            remote: vec![],
 930            pending: vec![]
 931        }
 932    );
 933    assert_eq!(
 934        room_participants(&room_d, cx_d),
 935        RoomParticipants {
 936            remote: vec!["user_a".to_string(), "user_b".to_string()],
 937            pending: vec![]
 938        }
 939    );
 940
 941    // User D hangs up.
 942    active_call_d
 943        .update(cx_d, |call, cx| call.hang_up(cx))
 944        .await
 945        .unwrap();
 946    deterministic.run_until_parked();
 947    assert_eq!(
 948        room_participants(&room_a, cx_a),
 949        RoomParticipants {
 950            remote: vec!["user_b".to_string()],
 951            pending: vec![]
 952        }
 953    );
 954    assert_eq!(
 955        room_participants(&room_b, cx_b),
 956        RoomParticipants {
 957            remote: vec!["user_a".to_string()],
 958            pending: vec![]
 959        }
 960    );
 961    assert_eq!(
 962        room_participants(&room_c, cx_c),
 963        RoomParticipants {
 964            remote: vec![],
 965            pending: vec![]
 966        }
 967    );
 968    assert_eq!(
 969        room_participants(&room_d, cx_d),
 970        RoomParticipants {
 971            remote: vec![],
 972            pending: vec![]
 973        }
 974    );
 975
 976    // User B calls user D again.
 977    active_call_b
 978        .update(cx_b, |call, cx| {
 979            call.invite(client_d.user_id().unwrap(), None, cx)
 980        })
 981        .await
 982        .unwrap();
 983
 984    // User D receives the call but doesn't join the room yet.
 985    let mut incoming_call_d = active_call_d.read_with(cx_d, |call, _| call.incoming());
 986    assert!(incoming_call_d.next().await.unwrap().is_some());
 987    deterministic.run_until_parked();
 988    assert_eq!(
 989        room_participants(&room_a, cx_a),
 990        RoomParticipants {
 991            remote: vec!["user_b".to_string()],
 992            pending: vec!["user_d".to_string()]
 993        }
 994    );
 995    assert_eq!(
 996        room_participants(&room_b, cx_b),
 997        RoomParticipants {
 998            remote: vec!["user_a".to_string()],
 999            pending: vec!["user_d".to_string()]
1000        }
1001    );
1002
1003    // The server is torn down.
1004    server.reset().await;
1005
1006    // Users A and B have troubles reconnecting, so they leave the room.
1007    client_a.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1008    client_b.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1009    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1010    deterministic.advance_clock(RECONNECT_TIMEOUT);
1011    assert_eq!(
1012        room_participants(&room_a, cx_a),
1013        RoomParticipants {
1014            remote: vec![],
1015            pending: vec![]
1016        }
1017    );
1018    assert_eq!(
1019        room_participants(&room_b, cx_b),
1020        RoomParticipants {
1021            remote: vec![],
1022            pending: vec![]
1023        }
1024    );
1025
1026    // User D is notified again of the incoming call but doesn't accept it.
1027    assert!(incoming_call_d.next().await.unwrap().is_some());
1028
1029    // The server finishes restarting, cleaning up stale connections and canceling the
1030    // call to user D because the room has become empty.
1031    server.start().await.unwrap();
1032    deterministic.advance_clock(CLEANUP_TIMEOUT);
1033    assert!(incoming_call_d.next().await.unwrap().is_none());
1034}
1035
1036#[gpui::test(iterations = 10)]
1037async fn test_calls_on_multiple_connections(
1038    deterministic: Arc<Deterministic>,
1039    cx_a: &mut TestAppContext,
1040    cx_b1: &mut TestAppContext,
1041    cx_b2: &mut TestAppContext,
1042) {
1043    deterministic.forbid_parking();
1044    let mut server = TestServer::start(&deterministic).await;
1045    let client_a = server.create_client(cx_a, "user_a").await;
1046    let client_b1 = server.create_client(cx_b1, "user_b").await;
1047    let client_b2 = server.create_client(cx_b2, "user_b").await;
1048    server
1049        .make_contacts(&mut [(&client_a, cx_a), (&client_b1, cx_b1)])
1050        .await;
1051
1052    let active_call_a = cx_a.read(ActiveCall::global);
1053    let active_call_b1 = cx_b1.read(ActiveCall::global);
1054    let active_call_b2 = cx_b2.read(ActiveCall::global);
1055    let mut incoming_call_b1 = active_call_b1.read_with(cx_b1, |call, _| call.incoming());
1056    let mut incoming_call_b2 = active_call_b2.read_with(cx_b2, |call, _| call.incoming());
1057    assert!(incoming_call_b1.next().await.unwrap().is_none());
1058    assert!(incoming_call_b2.next().await.unwrap().is_none());
1059
1060    // Call user B from client A, ensuring both clients for user B ring.
1061    active_call_a
1062        .update(cx_a, |call, cx| {
1063            call.invite(client_b1.user_id().unwrap(), None, cx)
1064        })
1065        .await
1066        .unwrap();
1067    deterministic.run_until_parked();
1068    assert!(incoming_call_b1.next().await.unwrap().is_some());
1069    assert!(incoming_call_b2.next().await.unwrap().is_some());
1070
1071    // User B declines the call on one of the two connections, causing both connections
1072    // to stop ringing.
1073    active_call_b2.update(cx_b2, |call, _| call.decline_incoming().unwrap());
1074    deterministic.run_until_parked();
1075    assert!(incoming_call_b1.next().await.unwrap().is_none());
1076    assert!(incoming_call_b2.next().await.unwrap().is_none());
1077
1078    // Call user B again from client A.
1079    active_call_a
1080        .update(cx_a, |call, cx| {
1081            call.invite(client_b1.user_id().unwrap(), None, cx)
1082        })
1083        .await
1084        .unwrap();
1085    deterministic.run_until_parked();
1086    assert!(incoming_call_b1.next().await.unwrap().is_some());
1087    assert!(incoming_call_b2.next().await.unwrap().is_some());
1088
1089    // User B accepts the call on one of the two connections, causing both connections
1090    // to stop ringing.
1091    active_call_b2
1092        .update(cx_b2, |call, cx| call.accept_incoming(cx))
1093        .await
1094        .unwrap();
1095    deterministic.run_until_parked();
1096    assert!(incoming_call_b1.next().await.unwrap().is_none());
1097    assert!(incoming_call_b2.next().await.unwrap().is_none());
1098
1099    // User B disconnects the client that is not on the call. Everything should be fine.
1100    client_b1.disconnect(&cx_b1.to_async());
1101    deterministic.advance_clock(RECEIVE_TIMEOUT);
1102    client_b1
1103        .authenticate_and_connect(false, &cx_b1.to_async())
1104        .await
1105        .unwrap();
1106
1107    // User B hangs up, and user A calls them again.
1108    active_call_b2
1109        .update(cx_b2, |call, cx| call.hang_up(cx))
1110        .await
1111        .unwrap();
1112    deterministic.run_until_parked();
1113    active_call_a
1114        .update(cx_a, |call, cx| {
1115            call.invite(client_b1.user_id().unwrap(), None, cx)
1116        })
1117        .await
1118        .unwrap();
1119    deterministic.run_until_parked();
1120    assert!(incoming_call_b1.next().await.unwrap().is_some());
1121    assert!(incoming_call_b2.next().await.unwrap().is_some());
1122
1123    // User A cancels the call, causing both connections to stop ringing.
1124    active_call_a
1125        .update(cx_a, |call, cx| {
1126            call.cancel_invite(client_b1.user_id().unwrap(), cx)
1127        })
1128        .await
1129        .unwrap();
1130    deterministic.run_until_parked();
1131    assert!(incoming_call_b1.next().await.unwrap().is_none());
1132    assert!(incoming_call_b2.next().await.unwrap().is_none());
1133
1134    // User A calls user B again.
1135    active_call_a
1136        .update(cx_a, |call, cx| {
1137            call.invite(client_b1.user_id().unwrap(), None, cx)
1138        })
1139        .await
1140        .unwrap();
1141    deterministic.run_until_parked();
1142    assert!(incoming_call_b1.next().await.unwrap().is_some());
1143    assert!(incoming_call_b2.next().await.unwrap().is_some());
1144
1145    // User A hangs up, causing both connections to stop ringing.
1146    active_call_a
1147        .update(cx_a, |call, cx| call.hang_up(cx))
1148        .await
1149        .unwrap();
1150    deterministic.run_until_parked();
1151    assert!(incoming_call_b1.next().await.unwrap().is_none());
1152    assert!(incoming_call_b2.next().await.unwrap().is_none());
1153
1154    // User A calls user B again.
1155    active_call_a
1156        .update(cx_a, |call, cx| {
1157            call.invite(client_b1.user_id().unwrap(), None, cx)
1158        })
1159        .await
1160        .unwrap();
1161    deterministic.run_until_parked();
1162    assert!(incoming_call_b1.next().await.unwrap().is_some());
1163    assert!(incoming_call_b2.next().await.unwrap().is_some());
1164
1165    // User A disconnects, causing both connections to stop ringing.
1166    server.forbid_connections();
1167    server.disconnect_client(client_a.peer_id().unwrap());
1168    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1169    assert!(incoming_call_b1.next().await.unwrap().is_none());
1170    assert!(incoming_call_b2.next().await.unwrap().is_none());
1171
1172    // User A reconnects automatically, then calls user B again.
1173    server.allow_connections();
1174    deterministic.advance_clock(RECEIVE_TIMEOUT);
1175    active_call_a
1176        .update(cx_a, |call, cx| {
1177            call.invite(client_b1.user_id().unwrap(), None, cx)
1178        })
1179        .await
1180        .unwrap();
1181    deterministic.run_until_parked();
1182    assert!(incoming_call_b1.next().await.unwrap().is_some());
1183    assert!(incoming_call_b2.next().await.unwrap().is_some());
1184
1185    // User B disconnects all clients, causing user A to no longer see a pending call for them.
1186    server.forbid_connections();
1187    server.disconnect_client(client_b1.peer_id().unwrap());
1188    server.disconnect_client(client_b2.peer_id().unwrap());
1189    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1190    active_call_a.read_with(cx_a, |call, _| assert!(call.room().is_none()));
1191}
1192
1193#[gpui::test(iterations = 10)]
1194async fn test_share_project(
1195    deterministic: Arc<Deterministic>,
1196    cx_a: &mut TestAppContext,
1197    cx_b: &mut TestAppContext,
1198    cx_c: &mut TestAppContext,
1199) {
1200    deterministic.forbid_parking();
1201    let (_, window_b) = cx_b.add_window(|_| EmptyView);
1202    let mut server = TestServer::start(&deterministic).await;
1203    let client_a = server.create_client(cx_a, "user_a").await;
1204    let client_b = server.create_client(cx_b, "user_b").await;
1205    let client_c = server.create_client(cx_c, "user_c").await;
1206    server
1207        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1208        .await;
1209    let active_call_a = cx_a.read(ActiveCall::global);
1210    let active_call_b = cx_b.read(ActiveCall::global);
1211    let active_call_c = cx_c.read(ActiveCall::global);
1212
1213    client_a
1214        .fs
1215        .insert_tree(
1216            "/a",
1217            json!({
1218                ".gitignore": "ignored-dir",
1219                "a.txt": "a-contents",
1220                "b.txt": "b-contents",
1221                "ignored-dir": {
1222                    "c.txt": "",
1223                    "d.txt": "",
1224                }
1225            }),
1226        )
1227        .await;
1228
1229    // Invite client B to collaborate on a project
1230    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1231    active_call_a
1232        .update(cx_a, |call, cx| {
1233            call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
1234        })
1235        .await
1236        .unwrap();
1237
1238    // Join that project as client B
1239    let incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
1240    deterministic.run_until_parked();
1241    let call = incoming_call_b.borrow().clone().unwrap();
1242    assert_eq!(call.calling_user.github_login, "user_a");
1243    let initial_project = call.initial_project.unwrap();
1244    active_call_b
1245        .update(cx_b, |call, cx| call.accept_incoming(cx))
1246        .await
1247        .unwrap();
1248    let client_b_peer_id = client_b.peer_id().unwrap();
1249    let project_b = client_b
1250        .build_remote_project(initial_project.id, cx_b)
1251        .await;
1252    let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
1253
1254    deterministic.run_until_parked();
1255    project_a.read_with(cx_a, |project, _| {
1256        let client_b_collaborator = project.collaborators().get(&client_b_peer_id).unwrap();
1257        assert_eq!(client_b_collaborator.replica_id, replica_id_b);
1258    });
1259    project_b.read_with(cx_b, |project, cx| {
1260        let worktree = project.worktrees(cx).next().unwrap().read(cx);
1261        assert_eq!(
1262            worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
1263            [
1264                Path::new(".gitignore"),
1265                Path::new("a.txt"),
1266                Path::new("b.txt"),
1267                Path::new("ignored-dir"),
1268                Path::new("ignored-dir/c.txt"),
1269                Path::new("ignored-dir/d.txt"),
1270            ]
1271        );
1272    });
1273
1274    // Open the same file as client B and client A.
1275    let buffer_b = project_b
1276        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
1277        .await
1278        .unwrap();
1279    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "b-contents"));
1280    project_a.read_with(cx_a, |project, cx| {
1281        assert!(project.has_open_buffer((worktree_id, "b.txt"), cx))
1282    });
1283    let buffer_a = project_a
1284        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
1285        .await
1286        .unwrap();
1287
1288    let editor_b = cx_b.add_view(&window_b, |cx| Editor::for_buffer(buffer_b, None, cx));
1289
1290    // Client A sees client B's selection
1291    deterministic.run_until_parked();
1292    buffer_a.read_with(cx_a, |buffer, _| {
1293        buffer
1294            .snapshot()
1295            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1296            .count()
1297            == 1
1298    });
1299
1300    // Edit the buffer as client B and see that edit as client A.
1301    editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
1302    deterministic.run_until_parked();
1303    buffer_a.read_with(cx_a, |buffer, _| {
1304        assert_eq!(buffer.text(), "ok, b-contents")
1305    });
1306
1307    // Client B can invite client C on a project shared by client A.
1308    active_call_b
1309        .update(cx_b, |call, cx| {
1310            call.invite(client_c.user_id().unwrap(), Some(project_b.clone()), cx)
1311        })
1312        .await
1313        .unwrap();
1314
1315    let incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
1316    deterministic.run_until_parked();
1317    let call = incoming_call_c.borrow().clone().unwrap();
1318    assert_eq!(call.calling_user.github_login, "user_b");
1319    let initial_project = call.initial_project.unwrap();
1320    active_call_c
1321        .update(cx_c, |call, cx| call.accept_incoming(cx))
1322        .await
1323        .unwrap();
1324    let _project_c = client_c
1325        .build_remote_project(initial_project.id, cx_c)
1326        .await;
1327
1328    // Client B closes the editor, and client A sees client B's selections removed.
1329    cx_b.update(move |_| drop(editor_b));
1330    deterministic.run_until_parked();
1331    buffer_a.read_with(cx_a, |buffer, _| {
1332        buffer
1333            .snapshot()
1334            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1335            .count()
1336            == 0
1337    });
1338}
1339
1340#[gpui::test(iterations = 10)]
1341async fn test_unshare_project(
1342    deterministic: Arc<Deterministic>,
1343    cx_a: &mut TestAppContext,
1344    cx_b: &mut TestAppContext,
1345    cx_c: &mut TestAppContext,
1346) {
1347    deterministic.forbid_parking();
1348    let mut server = TestServer::start(&deterministic).await;
1349    let client_a = server.create_client(cx_a, "user_a").await;
1350    let client_b = server.create_client(cx_b, "user_b").await;
1351    let client_c = server.create_client(cx_c, "user_c").await;
1352    server
1353        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1354        .await;
1355
1356    let active_call_a = cx_a.read(ActiveCall::global);
1357    let active_call_b = cx_b.read(ActiveCall::global);
1358
1359    client_a
1360        .fs
1361        .insert_tree(
1362            "/a",
1363            json!({
1364                "a.txt": "a-contents",
1365                "b.txt": "b-contents",
1366            }),
1367        )
1368        .await;
1369
1370    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1371    let project_id = active_call_a
1372        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1373        .await
1374        .unwrap();
1375    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1376    let project_b = client_b.build_remote_project(project_id, cx_b).await;
1377    deterministic.run_until_parked();
1378    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1379
1380    project_b
1381        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
1382        .await
1383        .unwrap();
1384
1385    // When client B leaves the room, the project becomes read-only.
1386    active_call_b
1387        .update(cx_b, |call, cx| call.hang_up(cx))
1388        .await
1389        .unwrap();
1390    deterministic.run_until_parked();
1391    assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
1392
1393    // Client C opens the project.
1394    let project_c = client_c.build_remote_project(project_id, cx_c).await;
1395
1396    // When client A unshares the project, client C's project becomes read-only.
1397    project_a
1398        .update(cx_a, |project, cx| project.unshare(cx))
1399        .unwrap();
1400    deterministic.run_until_parked();
1401    assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
1402    assert!(project_c.read_with(cx_c, |project, _| project.is_read_only()));
1403
1404    // Client C can open the project again after client A re-shares.
1405    let project_id = active_call_a
1406        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1407        .await
1408        .unwrap();
1409    let project_c2 = client_c.build_remote_project(project_id, cx_c).await;
1410    deterministic.run_until_parked();
1411    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1412    project_c2
1413        .update(cx_c, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
1414        .await
1415        .unwrap();
1416
1417    // When client A (the host) leaves the room, the project gets unshared and guests are notified.
1418    active_call_a
1419        .update(cx_a, |call, cx| call.hang_up(cx))
1420        .await
1421        .unwrap();
1422    deterministic.run_until_parked();
1423    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1424    project_c2.read_with(cx_c, |project, _| {
1425        assert!(project.is_read_only());
1426        assert!(project.collaborators().is_empty());
1427    });
1428}
1429
1430#[gpui::test(iterations = 10)]
1431async fn test_host_disconnect(
1432    deterministic: Arc<Deterministic>,
1433    cx_a: &mut TestAppContext,
1434    cx_b: &mut TestAppContext,
1435    cx_c: &mut TestAppContext,
1436) {
1437    cx_b.update(editor::init);
1438    deterministic.forbid_parking();
1439    let mut server = TestServer::start(&deterministic).await;
1440    let client_a = server.create_client(cx_a, "user_a").await;
1441    let client_b = server.create_client(cx_b, "user_b").await;
1442    let client_c = server.create_client(cx_c, "user_c").await;
1443    server
1444        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1445        .await;
1446
1447    client_a
1448        .fs
1449        .insert_tree(
1450            "/a",
1451            json!({
1452                "a.txt": "a-contents",
1453                "b.txt": "b-contents",
1454            }),
1455        )
1456        .await;
1457
1458    let active_call_a = cx_a.read(ActiveCall::global);
1459    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1460    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1461    let project_id = active_call_a
1462        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1463        .await
1464        .unwrap();
1465
1466    let project_b = client_b.build_remote_project(project_id, cx_b).await;
1467    deterministic.run_until_parked();
1468    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1469
1470    let (_, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
1471    let editor_b = workspace_b
1472        .update(cx_b, |workspace, cx| {
1473            workspace.open_path((worktree_id, "b.txt"), None, true, cx)
1474        })
1475        .await
1476        .unwrap()
1477        .downcast::<Editor>()
1478        .unwrap();
1479    cx_b.read(|cx| {
1480        assert_eq!(
1481            cx.focused_view_id(workspace_b.window_id()),
1482            Some(editor_b.id())
1483        );
1484    });
1485    editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
1486    assert!(cx_b.is_window_edited(workspace_b.window_id()));
1487
1488    // Drop client A's connection. Collaborators should disappear and the project should not be shown as shared.
1489    server.forbid_connections();
1490    server.disconnect_client(client_a.peer_id().unwrap());
1491    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1492    project_a.read_with(cx_a, |project, _| project.collaborators().is_empty());
1493    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1494    project_b.read_with(cx_b, |project, _| project.is_read_only());
1495    assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
1496
1497    // Ensure client B's edited state is reset and that the whole window is blurred.
1498    cx_b.read(|cx| {
1499        assert_eq!(cx.focused_view_id(workspace_b.window_id()), None);
1500    });
1501    assert!(!cx_b.is_window_edited(workspace_b.window_id()));
1502
1503    // Ensure client B is not prompted to save edits when closing window after disconnecting.
1504    let can_close = workspace_b
1505        .update(cx_b, |workspace, cx| workspace.prepare_to_close(true, cx))
1506        .await
1507        .unwrap();
1508    assert!(can_close);
1509
1510    // Allow client A to reconnect to the server.
1511    server.allow_connections();
1512    deterministic.advance_clock(RECEIVE_TIMEOUT);
1513
1514    // Client B calls client A again after they reconnected.
1515    let active_call_b = cx_b.read(ActiveCall::global);
1516    active_call_b
1517        .update(cx_b, |call, cx| {
1518            call.invite(client_a.user_id().unwrap(), None, cx)
1519        })
1520        .await
1521        .unwrap();
1522    deterministic.run_until_parked();
1523    active_call_a
1524        .update(cx_a, |call, cx| call.accept_incoming(cx))
1525        .await
1526        .unwrap();
1527
1528    active_call_a
1529        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1530        .await
1531        .unwrap();
1532
1533    // Drop client A's connection again. We should still unshare it successfully.
1534    server.forbid_connections();
1535    server.disconnect_client(client_a.peer_id().unwrap());
1536    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1537    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1538}
1539
1540#[gpui::test(iterations = 10)]
1541async fn test_project_reconnect(
1542    deterministic: Arc<Deterministic>,
1543    cx_a: &mut TestAppContext,
1544    cx_b: &mut TestAppContext,
1545) {
1546    cx_b.update(editor::init);
1547    deterministic.forbid_parking();
1548    let mut server = TestServer::start(&deterministic).await;
1549    let client_a = server.create_client(cx_a, "user_a").await;
1550    let client_b = server.create_client(cx_b, "user_b").await;
1551    server
1552        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
1553        .await;
1554
1555    client_a
1556        .fs
1557        .insert_tree(
1558            "/root-1",
1559            json!({
1560                "dir1": {
1561                    "a.txt": "a",
1562                    "b.txt": "b",
1563                    "subdir1": {
1564                        "c.txt": "c",
1565                        "d.txt": "d",
1566                        "e.txt": "e",
1567                    }
1568                },
1569                "dir2": {
1570                    "v.txt": "v",
1571                },
1572                "dir3": {
1573                    "w.txt": "w",
1574                    "x.txt": "x",
1575                    "y.txt": "y",
1576                },
1577                "dir4": {
1578                    "z.txt": "z",
1579                },
1580            }),
1581        )
1582        .await;
1583    client_a
1584        .fs
1585        .insert_tree(
1586            "/root-2",
1587            json!({
1588                "2.txt": "2",
1589            }),
1590        )
1591        .await;
1592    client_a
1593        .fs
1594        .insert_tree(
1595            "/root-3",
1596            json!({
1597                "3.txt": "3",
1598            }),
1599        )
1600        .await;
1601
1602    let active_call_a = cx_a.read(ActiveCall::global);
1603    let (project_a1, _) = client_a.build_local_project("/root-1/dir1", cx_a).await;
1604    let (project_a2, _) = client_a.build_local_project("/root-2", cx_a).await;
1605    let (project_a3, _) = client_a.build_local_project("/root-3", cx_a).await;
1606    let worktree_a1 =
1607        project_a1.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1608    let project1_id = active_call_a
1609        .update(cx_a, |call, cx| call.share_project(project_a1.clone(), cx))
1610        .await
1611        .unwrap();
1612    let project2_id = active_call_a
1613        .update(cx_a, |call, cx| call.share_project(project_a2.clone(), cx))
1614        .await
1615        .unwrap();
1616    let project3_id = active_call_a
1617        .update(cx_a, |call, cx| call.share_project(project_a3.clone(), cx))
1618        .await
1619        .unwrap();
1620
1621    let project_b1 = client_b.build_remote_project(project1_id, cx_b).await;
1622    let project_b2 = client_b.build_remote_project(project2_id, cx_b).await;
1623    let project_b3 = client_b.build_remote_project(project3_id, cx_b).await;
1624    deterministic.run_until_parked();
1625
1626    let worktree1_id = worktree_a1.read_with(cx_a, |worktree, _| {
1627        assert!(worktree.as_local().unwrap().is_shared());
1628        worktree.id()
1629    });
1630    let (worktree_a2, _) = project_a1
1631        .update(cx_a, |p, cx| {
1632            p.find_or_create_local_worktree("/root-1/dir2", true, cx)
1633        })
1634        .await
1635        .unwrap();
1636    worktree_a2
1637        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
1638        .await;
1639    let worktree2_id = worktree_a2.read_with(cx_a, |tree, _| {
1640        assert!(tree.as_local().unwrap().is_shared());
1641        tree.id()
1642    });
1643    deterministic.run_until_parked();
1644    project_b1.read_with(cx_b, |project, cx| {
1645        assert!(project.worktree_for_id(worktree2_id, cx).is_some())
1646    });
1647
1648    let buffer_a1 = project_a1
1649        .update(cx_a, |p, cx| p.open_buffer((worktree1_id, "a.txt"), cx))
1650        .await
1651        .unwrap();
1652    let buffer_b1 = project_b1
1653        .update(cx_b, |p, cx| p.open_buffer((worktree1_id, "a.txt"), cx))
1654        .await
1655        .unwrap();
1656
1657    // Drop client A's connection.
1658    server.forbid_connections();
1659    server.disconnect_client(client_a.peer_id().unwrap());
1660    deterministic.advance_clock(RECEIVE_TIMEOUT);
1661    project_a1.read_with(cx_a, |project, _| {
1662        assert!(project.is_shared());
1663        assert_eq!(project.collaborators().len(), 1);
1664    });
1665    project_b1.read_with(cx_b, |project, _| {
1666        assert!(!project.is_read_only());
1667        assert_eq!(project.collaborators().len(), 1);
1668    });
1669    worktree_a1.read_with(cx_a, |tree, _| {
1670        assert!(tree.as_local().unwrap().is_shared())
1671    });
1672
1673    // While client A is disconnected, add and remove files from client A's project.
1674    client_a
1675        .fs
1676        .insert_tree(
1677            "/root-1/dir1/subdir2",
1678            json!({
1679                "f.txt": "f-contents",
1680                "g.txt": "g-contents",
1681                "h.txt": "h-contents",
1682                "i.txt": "i-contents",
1683            }),
1684        )
1685        .await;
1686    client_a
1687        .fs
1688        .remove_dir(
1689            "/root-1/dir1/subdir1".as_ref(),
1690            RemoveOptions {
1691                recursive: true,
1692                ..Default::default()
1693            },
1694        )
1695        .await
1696        .unwrap();
1697
1698    // While client A is disconnected, add and remove worktrees from client A's project.
1699    project_a1
1700        .update(cx_a, |project, cx| {
1701            project.remove_worktree(worktree2_id, cx)
1702        })
1703        .await;
1704    let (worktree_a3, _) = project_a1
1705        .update(cx_a, |p, cx| {
1706            p.find_or_create_local_worktree("/root-1/dir3", true, cx)
1707        })
1708        .await
1709        .unwrap();
1710    worktree_a3
1711        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
1712        .await;
1713    let worktree3_id = worktree_a3.read_with(cx_a, |tree, _| {
1714        assert!(!tree.as_local().unwrap().is_shared());
1715        tree.id()
1716    });
1717    deterministic.run_until_parked();
1718
1719    // While client A is disconnected, close project 2
1720    cx_a.update(|_| drop(project_a2));
1721
1722    // While client A is disconnected, mutate a buffer on both the host and the guest.
1723    buffer_a1.update(cx_a, |buf, cx| buf.edit([(0..0, "W")], None, cx));
1724    buffer_b1.update(cx_b, |buf, cx| buf.edit([(1..1, "Z")], None, cx));
1725    deterministic.run_until_parked();
1726
1727    // Client A reconnects. Their project is re-shared, and client B re-joins it.
1728    server.allow_connections();
1729    client_a
1730        .authenticate_and_connect(false, &cx_a.to_async())
1731        .await
1732        .unwrap();
1733    deterministic.run_until_parked();
1734    project_a1.read_with(cx_a, |project, cx| {
1735        assert!(project.is_shared());
1736        assert!(worktree_a1.read(cx).as_local().unwrap().is_shared());
1737        assert_eq!(
1738            worktree_a1
1739                .read(cx)
1740                .snapshot()
1741                .paths()
1742                .map(|p| p.to_str().unwrap())
1743                .collect::<Vec<_>>(),
1744            vec![
1745                "a.txt",
1746                "b.txt",
1747                "subdir2",
1748                "subdir2/f.txt",
1749                "subdir2/g.txt",
1750                "subdir2/h.txt",
1751                "subdir2/i.txt"
1752            ]
1753        );
1754        assert!(worktree_a3.read(cx).as_local().unwrap().is_shared());
1755        assert_eq!(
1756            worktree_a3
1757                .read(cx)
1758                .snapshot()
1759                .paths()
1760                .map(|p| p.to_str().unwrap())
1761                .collect::<Vec<_>>(),
1762            vec!["w.txt", "x.txt", "y.txt"]
1763        );
1764    });
1765    project_b1.read_with(cx_b, |project, cx| {
1766        assert!(!project.is_read_only());
1767        assert_eq!(
1768            project
1769                .worktree_for_id(worktree1_id, cx)
1770                .unwrap()
1771                .read(cx)
1772                .snapshot()
1773                .paths()
1774                .map(|p| p.to_str().unwrap())
1775                .collect::<Vec<_>>(),
1776            vec![
1777                "a.txt",
1778                "b.txt",
1779                "subdir2",
1780                "subdir2/f.txt",
1781                "subdir2/g.txt",
1782                "subdir2/h.txt",
1783                "subdir2/i.txt"
1784            ]
1785        );
1786        assert!(project.worktree_for_id(worktree2_id, cx).is_none());
1787        assert_eq!(
1788            project
1789                .worktree_for_id(worktree3_id, cx)
1790                .unwrap()
1791                .read(cx)
1792                .snapshot()
1793                .paths()
1794                .map(|p| p.to_str().unwrap())
1795                .collect::<Vec<_>>(),
1796            vec!["w.txt", "x.txt", "y.txt"]
1797        );
1798    });
1799    project_b2.read_with(cx_b, |project, _| assert!(project.is_read_only()));
1800    project_b3.read_with(cx_b, |project, _| assert!(!project.is_read_only()));
1801    buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WaZ"));
1802    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "WaZ"));
1803
1804    // Drop client B's connection.
1805    server.forbid_connections();
1806    server.disconnect_client(client_b.peer_id().unwrap());
1807    deterministic.advance_clock(RECEIVE_TIMEOUT);
1808
1809    // While client B is disconnected, add and remove files from client A's project
1810    client_a
1811        .fs
1812        .insert_file("/root-1/dir1/subdir2/j.txt", "j-contents".into())
1813        .await;
1814    client_a
1815        .fs
1816        .remove_file("/root-1/dir1/subdir2/i.txt".as_ref(), Default::default())
1817        .await
1818        .unwrap();
1819
1820    // While client B is disconnected, add and remove worktrees from client A's project.
1821    let (worktree_a4, _) = project_a1
1822        .update(cx_a, |p, cx| {
1823            p.find_or_create_local_worktree("/root-1/dir4", true, cx)
1824        })
1825        .await
1826        .unwrap();
1827    worktree_a4
1828        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
1829        .await;
1830    let worktree4_id = worktree_a4.read_with(cx_a, |tree, _| {
1831        assert!(tree.as_local().unwrap().is_shared());
1832        tree.id()
1833    });
1834    project_a1
1835        .update(cx_a, |project, cx| {
1836            project.remove_worktree(worktree3_id, cx)
1837        })
1838        .await;
1839    deterministic.run_until_parked();
1840
1841    // While client B is disconnected, mutate a buffer on both the host and the guest.
1842    buffer_a1.update(cx_a, |buf, cx| buf.edit([(1..1, "X")], None, cx));
1843    buffer_b1.update(cx_b, |buf, cx| buf.edit([(2..2, "Y")], None, cx));
1844    deterministic.run_until_parked();
1845
1846    // While disconnected, close project 3
1847    cx_a.update(|_| drop(project_a3));
1848
1849    // Client B reconnects. They re-join the room and the remaining shared project.
1850    server.allow_connections();
1851    client_b
1852        .authenticate_and_connect(false, &cx_b.to_async())
1853        .await
1854        .unwrap();
1855    deterministic.run_until_parked();
1856    project_b1.read_with(cx_b, |project, cx| {
1857        assert!(!project.is_read_only());
1858        assert_eq!(
1859            project
1860                .worktree_for_id(worktree1_id, cx)
1861                .unwrap()
1862                .read(cx)
1863                .snapshot()
1864                .paths()
1865                .map(|p| p.to_str().unwrap())
1866                .collect::<Vec<_>>(),
1867            vec![
1868                "a.txt",
1869                "b.txt",
1870                "subdir2",
1871                "subdir2/f.txt",
1872                "subdir2/g.txt",
1873                "subdir2/h.txt",
1874                "subdir2/j.txt"
1875            ]
1876        );
1877        assert!(project.worktree_for_id(worktree2_id, cx).is_none());
1878        assert_eq!(
1879            project
1880                .worktree_for_id(worktree4_id, cx)
1881                .unwrap()
1882                .read(cx)
1883                .snapshot()
1884                .paths()
1885                .map(|p| p.to_str().unwrap())
1886                .collect::<Vec<_>>(),
1887            vec!["z.txt"]
1888        );
1889    });
1890    project_b3.read_with(cx_b, |project, _| assert!(project.is_read_only()));
1891    buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WXaYZ"));
1892    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "WXaYZ"));
1893}
1894
1895#[gpui::test(iterations = 10)]
1896async fn test_active_call_events(
1897    deterministic: Arc<Deterministic>,
1898    cx_a: &mut TestAppContext,
1899    cx_b: &mut TestAppContext,
1900) {
1901    deterministic.forbid_parking();
1902    let mut server = TestServer::start(&deterministic).await;
1903    let client_a = server.create_client(cx_a, "user_a").await;
1904    let client_b = server.create_client(cx_b, "user_b").await;
1905    client_a.fs.insert_tree("/a", json!({})).await;
1906    client_b.fs.insert_tree("/b", json!({})).await;
1907
1908    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
1909    let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
1910
1911    server
1912        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
1913        .await;
1914    let active_call_a = cx_a.read(ActiveCall::global);
1915    let active_call_b = cx_b.read(ActiveCall::global);
1916
1917    let events_a = active_call_events(cx_a);
1918    let events_b = active_call_events(cx_b);
1919
1920    let project_a_id = active_call_a
1921        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1922        .await
1923        .unwrap();
1924    deterministic.run_until_parked();
1925    assert_eq!(mem::take(&mut *events_a.borrow_mut()), vec![]);
1926    assert_eq!(
1927        mem::take(&mut *events_b.borrow_mut()),
1928        vec![room::Event::RemoteProjectShared {
1929            owner: Arc::new(User {
1930                id: client_a.user_id().unwrap(),
1931                github_login: "user_a".to_string(),
1932                avatar: None,
1933            }),
1934            project_id: project_a_id,
1935            worktree_root_names: vec!["a".to_string()],
1936        }]
1937    );
1938
1939    let project_b_id = active_call_b
1940        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
1941        .await
1942        .unwrap();
1943    deterministic.run_until_parked();
1944    assert_eq!(
1945        mem::take(&mut *events_a.borrow_mut()),
1946        vec![room::Event::RemoteProjectShared {
1947            owner: Arc::new(User {
1948                id: client_b.user_id().unwrap(),
1949                github_login: "user_b".to_string(),
1950                avatar: None,
1951            }),
1952            project_id: project_b_id,
1953            worktree_root_names: vec!["b".to_string()]
1954        }]
1955    );
1956    assert_eq!(mem::take(&mut *events_b.borrow_mut()), vec![]);
1957
1958    // Sharing a project twice is idempotent.
1959    let project_b_id_2 = active_call_b
1960        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
1961        .await
1962        .unwrap();
1963    assert_eq!(project_b_id_2, project_b_id);
1964    deterministic.run_until_parked();
1965    assert_eq!(mem::take(&mut *events_a.borrow_mut()), vec![]);
1966    assert_eq!(mem::take(&mut *events_b.borrow_mut()), vec![]);
1967}
1968
1969fn active_call_events(cx: &mut TestAppContext) -> Rc<RefCell<Vec<room::Event>>> {
1970    let events = Rc::new(RefCell::new(Vec::new()));
1971    let active_call = cx.read(ActiveCall::global);
1972    cx.update({
1973        let events = events.clone();
1974        |cx| {
1975            cx.subscribe(&active_call, move |_, event, _| {
1976                events.borrow_mut().push(event.clone())
1977            })
1978            .detach()
1979        }
1980    });
1981    events
1982}
1983
1984#[gpui::test(iterations = 10)]
1985async fn test_room_location(
1986    deterministic: Arc<Deterministic>,
1987    cx_a: &mut TestAppContext,
1988    cx_b: &mut TestAppContext,
1989) {
1990    deterministic.forbid_parking();
1991    let mut server = TestServer::start(&deterministic).await;
1992    let client_a = server.create_client(cx_a, "user_a").await;
1993    let client_b = server.create_client(cx_b, "user_b").await;
1994    client_a.fs.insert_tree("/a", json!({})).await;
1995    client_b.fs.insert_tree("/b", json!({})).await;
1996
1997    let active_call_a = cx_a.read(ActiveCall::global);
1998    let active_call_b = cx_b.read(ActiveCall::global);
1999
2000    let a_notified = Rc::new(Cell::new(false));
2001    cx_a.update({
2002        let notified = a_notified.clone();
2003        |cx| {
2004            cx.observe(&active_call_a, move |_, _| notified.set(true))
2005                .detach()
2006        }
2007    });
2008
2009    let b_notified = Rc::new(Cell::new(false));
2010    cx_b.update({
2011        let b_notified = b_notified.clone();
2012        |cx| {
2013            cx.observe(&active_call_b, move |_, _| b_notified.set(true))
2014                .detach()
2015        }
2016    });
2017
2018    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
2019    active_call_a
2020        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
2021        .await
2022        .unwrap();
2023    let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
2024
2025    server
2026        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2027        .await;
2028    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
2029    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
2030    deterministic.run_until_parked();
2031    assert!(a_notified.take());
2032    assert_eq!(
2033        participant_locations(&room_a, cx_a),
2034        vec![("user_b".to_string(), ParticipantLocation::External)]
2035    );
2036    assert!(b_notified.take());
2037    assert_eq!(
2038        participant_locations(&room_b, cx_b),
2039        vec![("user_a".to_string(), ParticipantLocation::UnsharedProject)]
2040    );
2041
2042    let project_a_id = active_call_a
2043        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2044        .await
2045        .unwrap();
2046    deterministic.run_until_parked();
2047    assert!(a_notified.take());
2048    assert_eq!(
2049        participant_locations(&room_a, cx_a),
2050        vec![("user_b".to_string(), ParticipantLocation::External)]
2051    );
2052    assert!(b_notified.take());
2053    assert_eq!(
2054        participant_locations(&room_b, cx_b),
2055        vec![(
2056            "user_a".to_string(),
2057            ParticipantLocation::SharedProject {
2058                project_id: project_a_id
2059            }
2060        )]
2061    );
2062
2063    let project_b_id = active_call_b
2064        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
2065        .await
2066        .unwrap();
2067    deterministic.run_until_parked();
2068    assert!(a_notified.take());
2069    assert_eq!(
2070        participant_locations(&room_a, cx_a),
2071        vec![("user_b".to_string(), ParticipantLocation::External)]
2072    );
2073    assert!(b_notified.take());
2074    assert_eq!(
2075        participant_locations(&room_b, cx_b),
2076        vec![(
2077            "user_a".to_string(),
2078            ParticipantLocation::SharedProject {
2079                project_id: project_a_id
2080            }
2081        )]
2082    );
2083
2084    active_call_b
2085        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
2086        .await
2087        .unwrap();
2088    deterministic.run_until_parked();
2089    assert!(a_notified.take());
2090    assert_eq!(
2091        participant_locations(&room_a, cx_a),
2092        vec![(
2093            "user_b".to_string(),
2094            ParticipantLocation::SharedProject {
2095                project_id: project_b_id
2096            }
2097        )]
2098    );
2099    assert!(b_notified.take());
2100    assert_eq!(
2101        participant_locations(&room_b, cx_b),
2102        vec![(
2103            "user_a".to_string(),
2104            ParticipantLocation::SharedProject {
2105                project_id: project_a_id
2106            }
2107        )]
2108    );
2109
2110    active_call_b
2111        .update(cx_b, |call, cx| call.set_location(None, cx))
2112        .await
2113        .unwrap();
2114    deterministic.run_until_parked();
2115    assert!(a_notified.take());
2116    assert_eq!(
2117        participant_locations(&room_a, cx_a),
2118        vec![("user_b".to_string(), ParticipantLocation::External)]
2119    );
2120    assert!(b_notified.take());
2121    assert_eq!(
2122        participant_locations(&room_b, cx_b),
2123        vec![(
2124            "user_a".to_string(),
2125            ParticipantLocation::SharedProject {
2126                project_id: project_a_id
2127            }
2128        )]
2129    );
2130
2131    fn participant_locations(
2132        room: &ModelHandle<Room>,
2133        cx: &TestAppContext,
2134    ) -> Vec<(String, ParticipantLocation)> {
2135        room.read_with(cx, |room, _| {
2136            room.remote_participants()
2137                .values()
2138                .map(|participant| {
2139                    (
2140                        participant.user.github_login.to_string(),
2141                        participant.location,
2142                    )
2143                })
2144                .collect()
2145        })
2146    }
2147}
2148
2149#[gpui::test(iterations = 10)]
2150async fn test_propagate_saves_and_fs_changes(
2151    deterministic: Arc<Deterministic>,
2152    cx_a: &mut TestAppContext,
2153    cx_b: &mut TestAppContext,
2154    cx_c: &mut TestAppContext,
2155) {
2156    deterministic.forbid_parking();
2157    let mut server = TestServer::start(&deterministic).await;
2158    let client_a = server.create_client(cx_a, "user_a").await;
2159    let client_b = server.create_client(cx_b, "user_b").await;
2160    let client_c = server.create_client(cx_c, "user_c").await;
2161
2162    server
2163        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
2164        .await;
2165    let active_call_a = cx_a.read(ActiveCall::global);
2166
2167    let rust = Arc::new(Language::new(
2168        LanguageConfig {
2169            name: "Rust".into(),
2170            path_suffixes: vec!["rs".to_string()],
2171            ..Default::default()
2172        },
2173        Some(tree_sitter_rust::language()),
2174    ));
2175    let javascript = Arc::new(Language::new(
2176        LanguageConfig {
2177            name: "JavaScript".into(),
2178            path_suffixes: vec!["js".to_string()],
2179            ..Default::default()
2180        },
2181        Some(tree_sitter_rust::language()),
2182    ));
2183    for client in [&client_a, &client_b, &client_c] {
2184        client.language_registry.add(rust.clone());
2185        client.language_registry.add(javascript.clone());
2186    }
2187
2188    client_a
2189        .fs
2190        .insert_tree(
2191            "/a",
2192            json!({
2193                "file1.rs": "",
2194                "file2": ""
2195            }),
2196        )
2197        .await;
2198    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
2199    let worktree_a = project_a.read_with(cx_a, |p, cx| p.worktrees(cx).next().unwrap());
2200    let project_id = active_call_a
2201        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2202        .await
2203        .unwrap();
2204
2205    // Join that worktree as clients B and C.
2206    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2207    let project_c = client_c.build_remote_project(project_id, cx_c).await;
2208    let worktree_b = project_b.read_with(cx_b, |p, cx| p.worktrees(cx).next().unwrap());
2209    let worktree_c = project_c.read_with(cx_c, |p, cx| p.worktrees(cx).next().unwrap());
2210
2211    // Open and edit a buffer as both guests B and C.
2212    let buffer_b = project_b
2213        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2214        .await
2215        .unwrap();
2216    let buffer_c = project_c
2217        .update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2218        .await
2219        .unwrap();
2220    buffer_b.read_with(cx_b, |buffer, _| {
2221        assert_eq!(&*buffer.language().unwrap().name(), "Rust");
2222    });
2223    buffer_c.read_with(cx_c, |buffer, _| {
2224        assert_eq!(&*buffer.language().unwrap().name(), "Rust");
2225    });
2226    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "i-am-b, ")], None, cx));
2227    buffer_c.update(cx_c, |buf, cx| buf.edit([(0..0, "i-am-c, ")], None, cx));
2228
2229    // Open and edit that buffer as the host.
2230    let buffer_a = project_a
2231        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2232        .await
2233        .unwrap();
2234
2235    deterministic.run_until_parked();
2236    buffer_a.read_with(cx_a, |buf, _| assert_eq!(buf.text(), "i-am-c, i-am-b, "));
2237    buffer_a.update(cx_a, |buf, cx| {
2238        buf.edit([(buf.len()..buf.len(), "i-am-a")], None, cx)
2239    });
2240
2241    deterministic.run_until_parked();
2242    buffer_a.read_with(cx_a, |buf, _| {
2243        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2244    });
2245    buffer_b.read_with(cx_b, |buf, _| {
2246        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2247    });
2248    buffer_c.read_with(cx_c, |buf, _| {
2249        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2250    });
2251
2252    // Edit the buffer as the host and concurrently save as guest B.
2253    let save_b = project_b.update(cx_b, |project, cx| {
2254        project.save_buffer(buffer_b.clone(), cx)
2255    });
2256    buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
2257    save_b.await.unwrap();
2258    assert_eq!(
2259        client_a.fs.load("/a/file1.rs".as_ref()).await.unwrap(),
2260        "hi-a, i-am-c, i-am-b, i-am-a"
2261    );
2262
2263    deterministic.run_until_parked();
2264    buffer_a.read_with(cx_a, |buf, _| assert!(!buf.is_dirty()));
2265    buffer_b.read_with(cx_b, |buf, _| assert!(!buf.is_dirty()));
2266    buffer_c.read_with(cx_c, |buf, _| assert!(!buf.is_dirty()));
2267
2268    // Make changes on host's file system, see those changes on guest worktrees.
2269    client_a
2270        .fs
2271        .rename(
2272            "/a/file1.rs".as_ref(),
2273            "/a/file1.js".as_ref(),
2274            Default::default(),
2275        )
2276        .await
2277        .unwrap();
2278    client_a
2279        .fs
2280        .rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
2281        .await
2282        .unwrap();
2283    client_a.fs.insert_file("/a/file4", "4".into()).await;
2284    deterministic.run_until_parked();
2285
2286    worktree_a.read_with(cx_a, |tree, _| {
2287        assert_eq!(
2288            tree.paths()
2289                .map(|p| p.to_string_lossy())
2290                .collect::<Vec<_>>(),
2291            ["file1.js", "file3", "file4"]
2292        )
2293    });
2294    worktree_b.read_with(cx_b, |tree, _| {
2295        assert_eq!(
2296            tree.paths()
2297                .map(|p| p.to_string_lossy())
2298                .collect::<Vec<_>>(),
2299            ["file1.js", "file3", "file4"]
2300        )
2301    });
2302    worktree_c.read_with(cx_c, |tree, _| {
2303        assert_eq!(
2304            tree.paths()
2305                .map(|p| p.to_string_lossy())
2306                .collect::<Vec<_>>(),
2307            ["file1.js", "file3", "file4"]
2308        )
2309    });
2310
2311    // Ensure buffer files are updated as well.
2312    buffer_a.read_with(cx_a, |buffer, _| {
2313        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2314        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2315    });
2316    buffer_b.read_with(cx_b, |buffer, _| {
2317        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2318        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2319    });
2320    buffer_c.read_with(cx_c, |buffer, _| {
2321        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2322        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2323    });
2324
2325    let new_buffer_a = project_a
2326        .update(cx_a, |p, cx| p.create_buffer("", None, cx))
2327        .unwrap();
2328    let new_buffer_id = new_buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
2329    let new_buffer_b = project_b
2330        .update(cx_b, |p, cx| p.open_buffer_by_id(new_buffer_id, cx))
2331        .await
2332        .unwrap();
2333    new_buffer_b.read_with(cx_b, |buffer, _| {
2334        assert!(buffer.file().is_none());
2335    });
2336
2337    new_buffer_a.update(cx_a, |buffer, cx| {
2338        buffer.edit([(0..0, "ok")], None, cx);
2339    });
2340    project_a
2341        .update(cx_a, |project, cx| {
2342            project.save_buffer_as(new_buffer_a.clone(), "/a/file3.rs".into(), cx)
2343        })
2344        .await
2345        .unwrap();
2346
2347    deterministic.run_until_parked();
2348    new_buffer_b.read_with(cx_b, |buffer_b, _| {
2349        assert_eq!(
2350            buffer_b.file().unwrap().path().as_ref(),
2351            Path::new("file3.rs")
2352        );
2353
2354        new_buffer_a.read_with(cx_a, |buffer_a, _| {
2355            assert_eq!(buffer_b.saved_mtime(), buffer_a.saved_mtime());
2356            assert_eq!(buffer_b.saved_version(), buffer_a.saved_version());
2357        });
2358    });
2359}
2360
2361#[gpui::test(iterations = 10)]
2362async fn test_git_diff_base_change(
2363    deterministic: Arc<Deterministic>,
2364    cx_a: &mut TestAppContext,
2365    cx_b: &mut TestAppContext,
2366) {
2367    deterministic.forbid_parking();
2368    let mut server = TestServer::start(&deterministic).await;
2369    let client_a = server.create_client(cx_a, "user_a").await;
2370    let client_b = server.create_client(cx_b, "user_b").await;
2371    server
2372        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2373        .await;
2374    let active_call_a = cx_a.read(ActiveCall::global);
2375
2376    client_a
2377        .fs
2378        .insert_tree(
2379            "/dir",
2380            json!({
2381            ".git": {},
2382            "sub": {
2383                ".git": {},
2384                "b.txt": "
2385                    one
2386                    two
2387                    three
2388                ".unindent(),
2389            },
2390            "a.txt": "
2391                    one
2392                    two
2393                    three
2394                ".unindent(),
2395            }),
2396        )
2397        .await;
2398
2399    let (project_local, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2400    let project_id = active_call_a
2401        .update(cx_a, |call, cx| {
2402            call.share_project(project_local.clone(), cx)
2403        })
2404        .await
2405        .unwrap();
2406
2407    let project_remote = client_b.build_remote_project(project_id, cx_b).await;
2408
2409    let diff_base = "
2410        one
2411        three
2412    "
2413    .unindent();
2414
2415    let new_diff_base = "
2416        one
2417        two
2418    "
2419    .unindent();
2420
2421    client_a
2422        .fs
2423        .as_fake()
2424        .set_index_for_repo(
2425            Path::new("/dir/.git"),
2426            &[(Path::new("a.txt"), diff_base.clone())],
2427        )
2428        .await;
2429
2430    // Create the buffer
2431    let buffer_local_a = project_local
2432        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2433        .await
2434        .unwrap();
2435
2436    // Wait for it to catch up to the new diff
2437    deterministic.run_until_parked();
2438
2439    // Smoke test diffing
2440    buffer_local_a.read_with(cx_a, |buffer, _| {
2441        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2442        git::diff::assert_hunks(
2443            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2444            &buffer,
2445            &diff_base,
2446            &[(1..2, "", "two\n")],
2447        );
2448    });
2449
2450    // Create remote buffer
2451    let buffer_remote_a = project_remote
2452        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2453        .await
2454        .unwrap();
2455
2456    // Wait remote buffer to catch up to the new diff
2457    deterministic.run_until_parked();
2458
2459    // Smoke test diffing
2460    buffer_remote_a.read_with(cx_b, |buffer, _| {
2461        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2462        git::diff::assert_hunks(
2463            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2464            &buffer,
2465            &diff_base,
2466            &[(1..2, "", "two\n")],
2467        );
2468    });
2469
2470    client_a
2471        .fs
2472        .as_fake()
2473        .set_index_for_repo(
2474            Path::new("/dir/.git"),
2475            &[(Path::new("a.txt"), new_diff_base.clone())],
2476        )
2477        .await;
2478
2479    // Wait for buffer_local_a to receive it
2480    deterministic.run_until_parked();
2481
2482    // Smoke test new diffing
2483    buffer_local_a.read_with(cx_a, |buffer, _| {
2484        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2485
2486        git::diff::assert_hunks(
2487            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2488            &buffer,
2489            &diff_base,
2490            &[(2..3, "", "three\n")],
2491        );
2492    });
2493
2494    // Smoke test B
2495    buffer_remote_a.read_with(cx_b, |buffer, _| {
2496        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2497        git::diff::assert_hunks(
2498            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2499            &buffer,
2500            &diff_base,
2501            &[(2..3, "", "three\n")],
2502        );
2503    });
2504
2505    //Nested git dir
2506
2507    let diff_base = "
2508        one
2509        three
2510    "
2511    .unindent();
2512
2513    let new_diff_base = "
2514        one
2515        two
2516    "
2517    .unindent();
2518
2519    client_a
2520        .fs
2521        .as_fake()
2522        .set_index_for_repo(
2523            Path::new("/dir/sub/.git"),
2524            &[(Path::new("b.txt"), diff_base.clone())],
2525        )
2526        .await;
2527
2528    // Create the buffer
2529    let buffer_local_b = project_local
2530        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
2531        .await
2532        .unwrap();
2533
2534    // Wait for it to catch up to the new diff
2535    deterministic.run_until_parked();
2536
2537    // Smoke test diffing
2538    buffer_local_b.read_with(cx_a, |buffer, _| {
2539        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2540        git::diff::assert_hunks(
2541            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2542            &buffer,
2543            &diff_base,
2544            &[(1..2, "", "two\n")],
2545        );
2546    });
2547
2548    // Create remote buffer
2549    let buffer_remote_b = project_remote
2550        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
2551        .await
2552        .unwrap();
2553
2554    // Wait remote buffer to catch up to the new diff
2555    deterministic.run_until_parked();
2556
2557    // Smoke test diffing
2558    buffer_remote_b.read_with(cx_b, |buffer, _| {
2559        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2560        git::diff::assert_hunks(
2561            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2562            &buffer,
2563            &diff_base,
2564            &[(1..2, "", "two\n")],
2565        );
2566    });
2567
2568    client_a
2569        .fs
2570        .as_fake()
2571        .set_index_for_repo(
2572            Path::new("/dir/sub/.git"),
2573            &[(Path::new("b.txt"), new_diff_base.clone())],
2574        )
2575        .await;
2576
2577    // Wait for buffer_local_b to receive it
2578    deterministic.run_until_parked();
2579
2580    // Smoke test new diffing
2581    buffer_local_b.read_with(cx_a, |buffer, _| {
2582        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2583        println!("{:?}", buffer.as_rope().to_string());
2584        println!("{:?}", buffer.diff_base());
2585        println!(
2586            "{:?}",
2587            buffer
2588                .snapshot()
2589                .git_diff_hunks_in_row_range(0..4, false)
2590                .collect::<Vec<_>>()
2591        );
2592
2593        git::diff::assert_hunks(
2594            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2595            &buffer,
2596            &diff_base,
2597            &[(2..3, "", "three\n")],
2598        );
2599    });
2600
2601    // Smoke test B
2602    buffer_remote_b.read_with(cx_b, |buffer, _| {
2603        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2604        git::diff::assert_hunks(
2605            buffer.snapshot().git_diff_hunks_in_row_range(0..4, false),
2606            &buffer,
2607            &diff_base,
2608            &[(2..3, "", "three\n")],
2609        );
2610    });
2611}
2612
2613#[gpui::test(iterations = 10)]
2614async fn test_fs_operations(
2615    deterministic: Arc<Deterministic>,
2616    cx_a: &mut TestAppContext,
2617    cx_b: &mut TestAppContext,
2618) {
2619    deterministic.forbid_parking();
2620    let mut server = TestServer::start(&deterministic).await;
2621    let client_a = server.create_client(cx_a, "user_a").await;
2622    let client_b = server.create_client(cx_b, "user_b").await;
2623    server
2624        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2625        .await;
2626    let active_call_a = cx_a.read(ActiveCall::global);
2627
2628    client_a
2629        .fs
2630        .insert_tree(
2631            "/dir",
2632            json!({
2633                "a.txt": "a-contents",
2634                "b.txt": "b-contents",
2635            }),
2636        )
2637        .await;
2638    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2639    let project_id = active_call_a
2640        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2641        .await
2642        .unwrap();
2643    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2644
2645    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
2646    let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
2647
2648    let entry = project_b
2649        .update(cx_b, |project, cx| {
2650            project
2651                .create_entry((worktree_id, "c.txt"), false, cx)
2652                .unwrap()
2653        })
2654        .await
2655        .unwrap();
2656    worktree_a.read_with(cx_a, |worktree, _| {
2657        assert_eq!(
2658            worktree
2659                .paths()
2660                .map(|p| p.to_string_lossy())
2661                .collect::<Vec<_>>(),
2662            ["a.txt", "b.txt", "c.txt"]
2663        );
2664    });
2665    worktree_b.read_with(cx_b, |worktree, _| {
2666        assert_eq!(
2667            worktree
2668                .paths()
2669                .map(|p| p.to_string_lossy())
2670                .collect::<Vec<_>>(),
2671            ["a.txt", "b.txt", "c.txt"]
2672        );
2673    });
2674
2675    project_b
2676        .update(cx_b, |project, cx| {
2677            project.rename_entry(entry.id, Path::new("d.txt"), cx)
2678        })
2679        .unwrap()
2680        .await
2681        .unwrap();
2682    worktree_a.read_with(cx_a, |worktree, _| {
2683        assert_eq!(
2684            worktree
2685                .paths()
2686                .map(|p| p.to_string_lossy())
2687                .collect::<Vec<_>>(),
2688            ["a.txt", "b.txt", "d.txt"]
2689        );
2690    });
2691    worktree_b.read_with(cx_b, |worktree, _| {
2692        assert_eq!(
2693            worktree
2694                .paths()
2695                .map(|p| p.to_string_lossy())
2696                .collect::<Vec<_>>(),
2697            ["a.txt", "b.txt", "d.txt"]
2698        );
2699    });
2700
2701    let dir_entry = project_b
2702        .update(cx_b, |project, cx| {
2703            project
2704                .create_entry((worktree_id, "DIR"), true, cx)
2705                .unwrap()
2706        })
2707        .await
2708        .unwrap();
2709    worktree_a.read_with(cx_a, |worktree, _| {
2710        assert_eq!(
2711            worktree
2712                .paths()
2713                .map(|p| p.to_string_lossy())
2714                .collect::<Vec<_>>(),
2715            ["DIR", "a.txt", "b.txt", "d.txt"]
2716        );
2717    });
2718    worktree_b.read_with(cx_b, |worktree, _| {
2719        assert_eq!(
2720            worktree
2721                .paths()
2722                .map(|p| p.to_string_lossy())
2723                .collect::<Vec<_>>(),
2724            ["DIR", "a.txt", "b.txt", "d.txt"]
2725        );
2726    });
2727
2728    project_b
2729        .update(cx_b, |project, cx| {
2730            project
2731                .create_entry((worktree_id, "DIR/e.txt"), false, cx)
2732                .unwrap()
2733        })
2734        .await
2735        .unwrap();
2736    project_b
2737        .update(cx_b, |project, cx| {
2738            project
2739                .create_entry((worktree_id, "DIR/SUBDIR"), true, cx)
2740                .unwrap()
2741        })
2742        .await
2743        .unwrap();
2744    project_b
2745        .update(cx_b, |project, cx| {
2746            project
2747                .create_entry((worktree_id, "DIR/SUBDIR/f.txt"), false, cx)
2748                .unwrap()
2749        })
2750        .await
2751        .unwrap();
2752    worktree_a.read_with(cx_a, |worktree, _| {
2753        assert_eq!(
2754            worktree
2755                .paths()
2756                .map(|p| p.to_string_lossy())
2757                .collect::<Vec<_>>(),
2758            [
2759                "DIR",
2760                "DIR/SUBDIR",
2761                "DIR/SUBDIR/f.txt",
2762                "DIR/e.txt",
2763                "a.txt",
2764                "b.txt",
2765                "d.txt"
2766            ]
2767        );
2768    });
2769    worktree_b.read_with(cx_b, |worktree, _| {
2770        assert_eq!(
2771            worktree
2772                .paths()
2773                .map(|p| p.to_string_lossy())
2774                .collect::<Vec<_>>(),
2775            [
2776                "DIR",
2777                "DIR/SUBDIR",
2778                "DIR/SUBDIR/f.txt",
2779                "DIR/e.txt",
2780                "a.txt",
2781                "b.txt",
2782                "d.txt"
2783            ]
2784        );
2785    });
2786
2787    project_b
2788        .update(cx_b, |project, cx| {
2789            project
2790                .copy_entry(entry.id, Path::new("f.txt"), cx)
2791                .unwrap()
2792        })
2793        .await
2794        .unwrap();
2795    worktree_a.read_with(cx_a, |worktree, _| {
2796        assert_eq!(
2797            worktree
2798                .paths()
2799                .map(|p| p.to_string_lossy())
2800                .collect::<Vec<_>>(),
2801            [
2802                "DIR",
2803                "DIR/SUBDIR",
2804                "DIR/SUBDIR/f.txt",
2805                "DIR/e.txt",
2806                "a.txt",
2807                "b.txt",
2808                "d.txt",
2809                "f.txt"
2810            ]
2811        );
2812    });
2813    worktree_b.read_with(cx_b, |worktree, _| {
2814        assert_eq!(
2815            worktree
2816                .paths()
2817                .map(|p| p.to_string_lossy())
2818                .collect::<Vec<_>>(),
2819            [
2820                "DIR",
2821                "DIR/SUBDIR",
2822                "DIR/SUBDIR/f.txt",
2823                "DIR/e.txt",
2824                "a.txt",
2825                "b.txt",
2826                "d.txt",
2827                "f.txt"
2828            ]
2829        );
2830    });
2831
2832    project_b
2833        .update(cx_b, |project, cx| {
2834            project.delete_entry(dir_entry.id, cx).unwrap()
2835        })
2836        .await
2837        .unwrap();
2838    deterministic.run_until_parked();
2839
2840    worktree_a.read_with(cx_a, |worktree, _| {
2841        assert_eq!(
2842            worktree
2843                .paths()
2844                .map(|p| p.to_string_lossy())
2845                .collect::<Vec<_>>(),
2846            ["a.txt", "b.txt", "d.txt", "f.txt"]
2847        );
2848    });
2849    worktree_b.read_with(cx_b, |worktree, _| {
2850        assert_eq!(
2851            worktree
2852                .paths()
2853                .map(|p| p.to_string_lossy())
2854                .collect::<Vec<_>>(),
2855            ["a.txt", "b.txt", "d.txt", "f.txt"]
2856        );
2857    });
2858
2859    project_b
2860        .update(cx_b, |project, cx| {
2861            project.delete_entry(entry.id, cx).unwrap()
2862        })
2863        .await
2864        .unwrap();
2865    worktree_a.read_with(cx_a, |worktree, _| {
2866        assert_eq!(
2867            worktree
2868                .paths()
2869                .map(|p| p.to_string_lossy())
2870                .collect::<Vec<_>>(),
2871            ["a.txt", "b.txt", "f.txt"]
2872        );
2873    });
2874    worktree_b.read_with(cx_b, |worktree, _| {
2875        assert_eq!(
2876            worktree
2877                .paths()
2878                .map(|p| p.to_string_lossy())
2879                .collect::<Vec<_>>(),
2880            ["a.txt", "b.txt", "f.txt"]
2881        );
2882    });
2883}
2884
2885#[gpui::test(iterations = 10)]
2886async fn test_buffer_conflict_after_save(
2887    deterministic: Arc<Deterministic>,
2888    cx_a: &mut TestAppContext,
2889    cx_b: &mut TestAppContext,
2890) {
2891    deterministic.forbid_parking();
2892    let mut server = TestServer::start(&deterministic).await;
2893    let client_a = server.create_client(cx_a, "user_a").await;
2894    let client_b = server.create_client(cx_b, "user_b").await;
2895    server
2896        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2897        .await;
2898    let active_call_a = cx_a.read(ActiveCall::global);
2899
2900    client_a
2901        .fs
2902        .insert_tree(
2903            "/dir",
2904            json!({
2905                "a.txt": "a-contents",
2906            }),
2907        )
2908        .await;
2909    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2910    let project_id = active_call_a
2911        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2912        .await
2913        .unwrap();
2914    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2915
2916    // Open a buffer as client B
2917    let buffer_b = project_b
2918        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2919        .await
2920        .unwrap();
2921
2922    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "world ")], None, cx));
2923    buffer_b.read_with(cx_b, |buf, _| {
2924        assert!(buf.is_dirty());
2925        assert!(!buf.has_conflict());
2926    });
2927
2928    project_b
2929        .update(cx_b, |project, cx| {
2930            project.save_buffer(buffer_b.clone(), cx)
2931        })
2932        .await
2933        .unwrap();
2934    cx_a.foreground().forbid_parking();
2935    buffer_b.read_with(cx_b, |buffer_b, _| assert!(!buffer_b.is_dirty()));
2936    buffer_b.read_with(cx_b, |buf, _| {
2937        assert!(!buf.has_conflict());
2938    });
2939
2940    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "hello ")], None, cx));
2941    buffer_b.read_with(cx_b, |buf, _| {
2942        assert!(buf.is_dirty());
2943        assert!(!buf.has_conflict());
2944    });
2945}
2946
2947#[gpui::test(iterations = 10)]
2948async fn test_buffer_reloading(
2949    deterministic: Arc<Deterministic>,
2950    cx_a: &mut TestAppContext,
2951    cx_b: &mut TestAppContext,
2952) {
2953    deterministic.forbid_parking();
2954    let mut server = TestServer::start(&deterministic).await;
2955    let client_a = server.create_client(cx_a, "user_a").await;
2956    let client_b = server.create_client(cx_b, "user_b").await;
2957    server
2958        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2959        .await;
2960    let active_call_a = cx_a.read(ActiveCall::global);
2961
2962    client_a
2963        .fs
2964        .insert_tree(
2965            "/dir",
2966            json!({
2967                "a.txt": "a\nb\nc",
2968            }),
2969        )
2970        .await;
2971    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2972    let project_id = active_call_a
2973        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2974        .await
2975        .unwrap();
2976    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2977
2978    // Open a buffer as client B
2979    let buffer_b = project_b
2980        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2981        .await
2982        .unwrap();
2983    buffer_b.read_with(cx_b, |buf, _| {
2984        assert!(!buf.is_dirty());
2985        assert!(!buf.has_conflict());
2986        assert_eq!(buf.line_ending(), LineEnding::Unix);
2987    });
2988
2989    let new_contents = Rope::from("d\ne\nf");
2990    client_a
2991        .fs
2992        .save("/dir/a.txt".as_ref(), &new_contents, LineEnding::Windows)
2993        .await
2994        .unwrap();
2995    cx_a.foreground().run_until_parked();
2996    buffer_b.read_with(cx_b, |buf, _| {
2997        assert_eq!(buf.text(), new_contents.to_string());
2998        assert!(!buf.is_dirty());
2999        assert!(!buf.has_conflict());
3000        assert_eq!(buf.line_ending(), LineEnding::Windows);
3001    });
3002}
3003
3004#[gpui::test(iterations = 10)]
3005async fn test_editing_while_guest_opens_buffer(
3006    deterministic: Arc<Deterministic>,
3007    cx_a: &mut TestAppContext,
3008    cx_b: &mut TestAppContext,
3009) {
3010    deterministic.forbid_parking();
3011    let mut server = TestServer::start(&deterministic).await;
3012    let client_a = server.create_client(cx_a, "user_a").await;
3013    let client_b = server.create_client(cx_b, "user_b").await;
3014    server
3015        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3016        .await;
3017    let active_call_a = cx_a.read(ActiveCall::global);
3018
3019    client_a
3020        .fs
3021        .insert_tree("/dir", json!({ "a.txt": "a-contents" }))
3022        .await;
3023    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3024    let project_id = active_call_a
3025        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3026        .await
3027        .unwrap();
3028    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3029
3030    // Open a buffer as client A
3031    let buffer_a = project_a
3032        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3033        .await
3034        .unwrap();
3035
3036    // Start opening the same buffer as client B
3037    let buffer_b = cx_b
3038        .background()
3039        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)));
3040
3041    // Edit the buffer as client A while client B is still opening it.
3042    cx_b.background().simulate_random_delay().await;
3043    buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "X")], None, cx));
3044    cx_b.background().simulate_random_delay().await;
3045    buffer_a.update(cx_a, |buf, cx| buf.edit([(1..1, "Y")], None, cx));
3046
3047    let text = buffer_a.read_with(cx_a, |buf, _| buf.text());
3048    let buffer_b = buffer_b.await.unwrap();
3049    cx_a.foreground().run_until_parked();
3050    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), text));
3051}
3052
3053#[gpui::test(iterations = 10)]
3054async fn test_leaving_worktree_while_opening_buffer(
3055    deterministic: Arc<Deterministic>,
3056    cx_a: &mut TestAppContext,
3057    cx_b: &mut TestAppContext,
3058) {
3059    deterministic.forbid_parking();
3060    let mut server = TestServer::start(&deterministic).await;
3061    let client_a = server.create_client(cx_a, "user_a").await;
3062    let client_b = server.create_client(cx_b, "user_b").await;
3063    server
3064        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3065        .await;
3066    let active_call_a = cx_a.read(ActiveCall::global);
3067
3068    client_a
3069        .fs
3070        .insert_tree("/dir", json!({ "a.txt": "a-contents" }))
3071        .await;
3072    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3073    let project_id = active_call_a
3074        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3075        .await
3076        .unwrap();
3077    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3078
3079    // See that a guest has joined as client A.
3080    cx_a.foreground().run_until_parked();
3081    project_a.read_with(cx_a, |p, _| assert_eq!(p.collaborators().len(), 1));
3082
3083    // Begin opening a buffer as client B, but leave the project before the open completes.
3084    let buffer_b = cx_b
3085        .background()
3086        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)));
3087    cx_b.update(|_| drop(project_b));
3088    drop(buffer_b);
3089
3090    // See that the guest has left.
3091    cx_a.foreground().run_until_parked();
3092    project_a.read_with(cx_a, |p, _| assert!(p.collaborators().is_empty()));
3093}
3094
3095#[gpui::test(iterations = 10)]
3096async fn test_canceling_buffer_opening(
3097    deterministic: Arc<Deterministic>,
3098    cx_a: &mut TestAppContext,
3099    cx_b: &mut TestAppContext,
3100) {
3101    deterministic.forbid_parking();
3102
3103    let mut server = TestServer::start(&deterministic).await;
3104    let client_a = server.create_client(cx_a, "user_a").await;
3105    let client_b = server.create_client(cx_b, "user_b").await;
3106    server
3107        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3108        .await;
3109    let active_call_a = cx_a.read(ActiveCall::global);
3110
3111    client_a
3112        .fs
3113        .insert_tree(
3114            "/dir",
3115            json!({
3116                "a.txt": "abc",
3117            }),
3118        )
3119        .await;
3120    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3121    let project_id = active_call_a
3122        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3123        .await
3124        .unwrap();
3125    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3126
3127    let buffer_a = project_a
3128        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3129        .await
3130        .unwrap();
3131
3132    // Open a buffer as client B but cancel after a random amount of time.
3133    let buffer_b = project_b.update(cx_b, |p, cx| p.open_buffer_by_id(buffer_a.id() as u64, cx));
3134    deterministic.simulate_random_delay().await;
3135    drop(buffer_b);
3136
3137    // Try opening the same buffer again as client B, and ensure we can
3138    // still do it despite the cancellation above.
3139    let buffer_b = project_b
3140        .update(cx_b, |p, cx| p.open_buffer_by_id(buffer_a.id() as u64, cx))
3141        .await
3142        .unwrap();
3143    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "abc"));
3144}
3145
3146#[gpui::test(iterations = 10)]
3147async fn test_leaving_project(
3148    deterministic: Arc<Deterministic>,
3149    cx_a: &mut TestAppContext,
3150    cx_b: &mut TestAppContext,
3151    cx_c: &mut TestAppContext,
3152) {
3153    deterministic.forbid_parking();
3154    let mut server = TestServer::start(&deterministic).await;
3155    let client_a = server.create_client(cx_a, "user_a").await;
3156    let client_b = server.create_client(cx_b, "user_b").await;
3157    let client_c = server.create_client(cx_c, "user_c").await;
3158    server
3159        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
3160        .await;
3161    let active_call_a = cx_a.read(ActiveCall::global);
3162
3163    client_a
3164        .fs
3165        .insert_tree(
3166            "/a",
3167            json!({
3168                "a.txt": "a-contents",
3169                "b.txt": "b-contents",
3170            }),
3171        )
3172        .await;
3173    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
3174    let project_id = active_call_a
3175        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3176        .await
3177        .unwrap();
3178    let project_b1 = client_b.build_remote_project(project_id, cx_b).await;
3179    let project_c = client_c.build_remote_project(project_id, cx_c).await;
3180
3181    // Client A sees that a guest has joined.
3182    deterministic.run_until_parked();
3183    project_a.read_with(cx_a, |project, _| {
3184        assert_eq!(project.collaborators().len(), 2);
3185    });
3186    project_b1.read_with(cx_b, |project, _| {
3187        assert_eq!(project.collaborators().len(), 2);
3188    });
3189    project_c.read_with(cx_c, |project, _| {
3190        assert_eq!(project.collaborators().len(), 2);
3191    });
3192
3193    // Client B opens a buffer.
3194    let buffer_b1 = project_b1
3195        .update(cx_b, |project, cx| {
3196            let worktree_id = project.worktrees(cx).next().unwrap().read(cx).id();
3197            project.open_buffer((worktree_id, "a.txt"), cx)
3198        })
3199        .await
3200        .unwrap();
3201    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "a-contents"));
3202
3203    // Drop client B's project and ensure client A and client C observe client B leaving.
3204    cx_b.update(|_| drop(project_b1));
3205    deterministic.run_until_parked();
3206    project_a.read_with(cx_a, |project, _| {
3207        assert_eq!(project.collaborators().len(), 1);
3208    });
3209    project_c.read_with(cx_c, |project, _| {
3210        assert_eq!(project.collaborators().len(), 1);
3211    });
3212
3213    // Client B re-joins the project and can open buffers as before.
3214    let project_b2 = client_b.build_remote_project(project_id, cx_b).await;
3215    deterministic.run_until_parked();
3216    project_a.read_with(cx_a, |project, _| {
3217        assert_eq!(project.collaborators().len(), 2);
3218    });
3219    project_b2.read_with(cx_b, |project, _| {
3220        assert_eq!(project.collaborators().len(), 2);
3221    });
3222    project_c.read_with(cx_c, |project, _| {
3223        assert_eq!(project.collaborators().len(), 2);
3224    });
3225
3226    let buffer_b2 = project_b2
3227        .update(cx_b, |project, cx| {
3228            let worktree_id = project.worktrees(cx).next().unwrap().read(cx).id();
3229            project.open_buffer((worktree_id, "a.txt"), cx)
3230        })
3231        .await
3232        .unwrap();
3233    buffer_b2.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "a-contents"));
3234
3235    // Drop client B's connection and ensure client A and client C observe client B leaving.
3236    client_b.disconnect(&cx_b.to_async());
3237    deterministic.advance_clock(RECONNECT_TIMEOUT);
3238    project_a.read_with(cx_a, |project, _| {
3239        assert_eq!(project.collaborators().len(), 1);
3240    });
3241    project_b2.read_with(cx_b, |project, _| {
3242        assert!(project.is_read_only());
3243    });
3244    project_c.read_with(cx_c, |project, _| {
3245        assert_eq!(project.collaborators().len(), 1);
3246    });
3247
3248    // Client B can't join the project, unless they re-join the room.
3249    cx_b.spawn(|cx| {
3250        Project::remote(
3251            project_id,
3252            client_b.client.clone(),
3253            client_b.user_store.clone(),
3254            client_b.language_registry.clone(),
3255            FakeFs::new(cx.background()),
3256            cx,
3257        )
3258    })
3259    .await
3260    .unwrap_err();
3261
3262    // Simulate connection loss for client C and ensure client A observes client C leaving the project.
3263    client_c.wait_for_current_user(cx_c).await;
3264    server.forbid_connections();
3265    server.disconnect_client(client_c.peer_id().unwrap());
3266    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
3267    deterministic.run_until_parked();
3268    project_a.read_with(cx_a, |project, _| {
3269        assert_eq!(project.collaborators().len(), 0);
3270    });
3271    project_b2.read_with(cx_b, |project, _| {
3272        assert!(project.is_read_only());
3273    });
3274    project_c.read_with(cx_c, |project, _| {
3275        assert!(project.is_read_only());
3276    });
3277}
3278
3279#[gpui::test(iterations = 10)]
3280async fn test_collaborating_with_diagnostics(
3281    deterministic: Arc<Deterministic>,
3282    cx_a: &mut TestAppContext,
3283    cx_b: &mut TestAppContext,
3284    cx_c: &mut TestAppContext,
3285) {
3286    deterministic.forbid_parking();
3287    let mut server = TestServer::start(&deterministic).await;
3288    let client_a = server.create_client(cx_a, "user_a").await;
3289    let client_b = server.create_client(cx_b, "user_b").await;
3290    let client_c = server.create_client(cx_c, "user_c").await;
3291    server
3292        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
3293        .await;
3294    let active_call_a = cx_a.read(ActiveCall::global);
3295
3296    // Set up a fake language server.
3297    let mut language = Language::new(
3298        LanguageConfig {
3299            name: "Rust".into(),
3300            path_suffixes: vec!["rs".to_string()],
3301            ..Default::default()
3302        },
3303        Some(tree_sitter_rust::language()),
3304    );
3305    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
3306    client_a.language_registry.add(Arc::new(language));
3307
3308    // Share a project as client A
3309    client_a
3310        .fs
3311        .insert_tree(
3312            "/a",
3313            json!({
3314                "a.rs": "let one = two",
3315                "other.rs": "",
3316            }),
3317        )
3318        .await;
3319    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
3320
3321    // Cause the language server to start.
3322    let _buffer = project_a
3323        .update(cx_a, |project, cx| {
3324            project.open_buffer(
3325                ProjectPath {
3326                    worktree_id,
3327                    path: Path::new("other.rs").into(),
3328                },
3329                cx,
3330            )
3331        })
3332        .await
3333        .unwrap();
3334
3335    // Simulate a language server reporting errors for a file.
3336    let mut fake_language_server = fake_language_servers.next().await.unwrap();
3337    fake_language_server
3338        .receive_notification::<lsp::notification::DidOpenTextDocument>()
3339        .await;
3340    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3341        lsp::PublishDiagnosticsParams {
3342            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3343            version: None,
3344            diagnostics: vec![lsp::Diagnostic {
3345                severity: Some(lsp::DiagnosticSeverity::WARNING),
3346                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3347                message: "message 0".to_string(),
3348                ..Default::default()
3349            }],
3350        },
3351    );
3352
3353    // Client A shares the project and, simultaneously, the language server
3354    // publishes a diagnostic. This is done to ensure that the server always
3355    // observes the latest diagnostics for a worktree.
3356    let project_id = active_call_a
3357        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3358        .await
3359        .unwrap();
3360    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3361        lsp::PublishDiagnosticsParams {
3362            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3363            version: None,
3364            diagnostics: vec![lsp::Diagnostic {
3365                severity: Some(lsp::DiagnosticSeverity::ERROR),
3366                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3367                message: "message 1".to_string(),
3368                ..Default::default()
3369            }],
3370        },
3371    );
3372
3373    // Join the worktree as client B.
3374    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3375
3376    // Wait for server to see the diagnostics update.
3377    deterministic.run_until_parked();
3378
3379    // Ensure client B observes the new diagnostics.
3380    project_b.read_with(cx_b, |project, cx| {
3381        assert_eq!(
3382            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3383            &[(
3384                ProjectPath {
3385                    worktree_id,
3386                    path: Arc::from(Path::new("a.rs")),
3387                },
3388                DiagnosticSummary {
3389                    error_count: 1,
3390                    warning_count: 0,
3391                    ..Default::default()
3392                },
3393            )]
3394        )
3395    });
3396
3397    // Join project as client C and observe the diagnostics.
3398    let project_c = client_c.build_remote_project(project_id, cx_c).await;
3399    let project_c_diagnostic_summaries =
3400        Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
3401            project.diagnostic_summaries(cx).collect::<Vec<_>>()
3402        })));
3403    project_c.update(cx_c, |_, cx| {
3404        let summaries = project_c_diagnostic_summaries.clone();
3405        cx.subscribe(&project_c, {
3406            move |p, _, event, cx| {
3407                if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
3408                    *summaries.borrow_mut() = p.diagnostic_summaries(cx).collect();
3409                }
3410            }
3411        })
3412        .detach();
3413    });
3414
3415    deterministic.run_until_parked();
3416    assert_eq!(
3417        project_c_diagnostic_summaries.borrow().as_slice(),
3418        &[(
3419            ProjectPath {
3420                worktree_id,
3421                path: Arc::from(Path::new("a.rs")),
3422            },
3423            DiagnosticSummary {
3424                error_count: 1,
3425                warning_count: 0,
3426                ..Default::default()
3427            },
3428        )]
3429    );
3430
3431    // Simulate a language server reporting more errors for a file.
3432    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3433        lsp::PublishDiagnosticsParams {
3434            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3435            version: None,
3436            diagnostics: vec![
3437                lsp::Diagnostic {
3438                    severity: Some(lsp::DiagnosticSeverity::ERROR),
3439                    range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3440                    message: "message 1".to_string(),
3441                    ..Default::default()
3442                },
3443                lsp::Diagnostic {
3444                    severity: Some(lsp::DiagnosticSeverity::WARNING),
3445                    range: lsp::Range::new(lsp::Position::new(0, 10), lsp::Position::new(0, 13)),
3446                    message: "message 2".to_string(),
3447                    ..Default::default()
3448                },
3449            ],
3450        },
3451    );
3452
3453    // Clients B and C get the updated summaries
3454    deterministic.run_until_parked();
3455    project_b.read_with(cx_b, |project, cx| {
3456        assert_eq!(
3457            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3458            [(
3459                ProjectPath {
3460                    worktree_id,
3461                    path: Arc::from(Path::new("a.rs")),
3462                },
3463                DiagnosticSummary {
3464                    error_count: 1,
3465                    warning_count: 1,
3466                    ..Default::default()
3467                },
3468            )]
3469        );
3470    });
3471    project_c.read_with(cx_c, |project, cx| {
3472        assert_eq!(
3473            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3474            [(
3475                ProjectPath {
3476                    worktree_id,
3477                    path: Arc::from(Path::new("a.rs")),
3478                },
3479                DiagnosticSummary {
3480                    error_count: 1,
3481                    warning_count: 1,
3482                    ..Default::default()
3483                },
3484            )]
3485        );
3486    });
3487
3488    // Open the file with the errors on client B. They should be present.
3489    let buffer_b = cx_b
3490        .background()
3491        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
3492        .await
3493        .unwrap();
3494
3495    buffer_b.read_with(cx_b, |buffer, _| {
3496        assert_eq!(
3497            buffer
3498                .snapshot()
3499                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
3500                .collect::<Vec<_>>(),
3501            &[
3502                DiagnosticEntry {
3503                    range: Point::new(0, 4)..Point::new(0, 7),
3504                    diagnostic: Diagnostic {
3505                        group_id: 2,
3506                        message: "message 1".to_string(),
3507                        severity: lsp::DiagnosticSeverity::ERROR,
3508                        is_primary: true,
3509                        ..Default::default()
3510                    }
3511                },
3512                DiagnosticEntry {
3513                    range: Point::new(0, 10)..Point::new(0, 13),
3514                    diagnostic: Diagnostic {
3515                        group_id: 3,
3516                        severity: lsp::DiagnosticSeverity::WARNING,
3517                        message: "message 2".to_string(),
3518                        is_primary: true,
3519                        ..Default::default()
3520                    }
3521                }
3522            ]
3523        );
3524    });
3525
3526    // Simulate a language server reporting no errors for a file.
3527    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3528        lsp::PublishDiagnosticsParams {
3529            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3530            version: None,
3531            diagnostics: vec![],
3532        },
3533    );
3534    deterministic.run_until_parked();
3535    project_a.read_with(cx_a, |project, cx| {
3536        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3537    });
3538    project_b.read_with(cx_b, |project, cx| {
3539        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3540    });
3541    project_c.read_with(cx_c, |project, cx| {
3542        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3543    });
3544}
3545
3546#[gpui::test(iterations = 10)]
3547async fn test_collaborating_with_completion(
3548    deterministic: Arc<Deterministic>,
3549    cx_a: &mut TestAppContext,
3550    cx_b: &mut TestAppContext,
3551) {
3552    deterministic.forbid_parking();
3553    let mut server = TestServer::start(&deterministic).await;
3554    let client_a = server.create_client(cx_a, "user_a").await;
3555    let client_b = server.create_client(cx_b, "user_b").await;
3556    server
3557        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3558        .await;
3559    let active_call_a = cx_a.read(ActiveCall::global);
3560
3561    // Set up a fake language server.
3562    let mut language = Language::new(
3563        LanguageConfig {
3564            name: "Rust".into(),
3565            path_suffixes: vec!["rs".to_string()],
3566            ..Default::default()
3567        },
3568        Some(tree_sitter_rust::language()),
3569    );
3570    let mut fake_language_servers = language
3571        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
3572            capabilities: lsp::ServerCapabilities {
3573                completion_provider: Some(lsp::CompletionOptions {
3574                    trigger_characters: Some(vec![".".to_string()]),
3575                    ..Default::default()
3576                }),
3577                ..Default::default()
3578            },
3579            ..Default::default()
3580        }))
3581        .await;
3582    client_a.language_registry.add(Arc::new(language));
3583
3584    client_a
3585        .fs
3586        .insert_tree(
3587            "/a",
3588            json!({
3589                "main.rs": "fn main() { a }",
3590                "other.rs": "",
3591            }),
3592        )
3593        .await;
3594    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
3595    let project_id = active_call_a
3596        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3597        .await
3598        .unwrap();
3599    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3600
3601    // Open a file in an editor as the guest.
3602    let buffer_b = project_b
3603        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
3604        .await
3605        .unwrap();
3606    let (_, window_b) = cx_b.add_window(|_| EmptyView);
3607    let editor_b = cx_b.add_view(&window_b, |cx| {
3608        Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
3609    });
3610
3611    let fake_language_server = fake_language_servers.next().await.unwrap();
3612    cx_a.foreground().run_until_parked();
3613    buffer_b.read_with(cx_b, |buffer, _| {
3614        assert!(!buffer.completion_triggers().is_empty())
3615    });
3616
3617    // Type a completion trigger character as the guest.
3618    editor_b.update(cx_b, |editor, cx| {
3619        editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
3620        editor.handle_input(".", cx);
3621        cx.focus(&editor_b);
3622    });
3623
3624    // Receive a completion request as the host's language server.
3625    // Return some completions from the host's language server.
3626    cx_a.foreground().start_waiting();
3627    fake_language_server
3628        .handle_request::<lsp::request::Completion, _, _>(|params, _| async move {
3629            assert_eq!(
3630                params.text_document_position.text_document.uri,
3631                lsp::Url::from_file_path("/a/main.rs").unwrap(),
3632            );
3633            assert_eq!(
3634                params.text_document_position.position,
3635                lsp::Position::new(0, 14),
3636            );
3637
3638            Ok(Some(lsp::CompletionResponse::Array(vec![
3639                lsp::CompletionItem {
3640                    label: "first_method(…)".into(),
3641                    detail: Some("fn(&mut self, B) -> C".into()),
3642                    text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
3643                        new_text: "first_method($1)".to_string(),
3644                        range: lsp::Range::new(
3645                            lsp::Position::new(0, 14),
3646                            lsp::Position::new(0, 14),
3647                        ),
3648                    })),
3649                    insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
3650                    ..Default::default()
3651                },
3652                lsp::CompletionItem {
3653                    label: "second_method(…)".into(),
3654                    detail: Some("fn(&mut self, C) -> D<E>".into()),
3655                    text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
3656                        new_text: "second_method()".to_string(),
3657                        range: lsp::Range::new(
3658                            lsp::Position::new(0, 14),
3659                            lsp::Position::new(0, 14),
3660                        ),
3661                    })),
3662                    insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
3663                    ..Default::default()
3664                },
3665            ])))
3666        })
3667        .next()
3668        .await
3669        .unwrap();
3670    cx_a.foreground().finish_waiting();
3671
3672    // Open the buffer on the host.
3673    let buffer_a = project_a
3674        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
3675        .await
3676        .unwrap();
3677    cx_a.foreground().run_until_parked();
3678    buffer_a.read_with(cx_a, |buffer, _| {
3679        assert_eq!(buffer.text(), "fn main() { a. }")
3680    });
3681
3682    // Confirm a completion on the guest.
3683    editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
3684    editor_b.update(cx_b, |editor, cx| {
3685        editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
3686        assert_eq!(editor.text(cx), "fn main() { a.first_method() }");
3687    });
3688
3689    // Return a resolved completion from the host's language server.
3690    // The resolved completion has an additional text edit.
3691    fake_language_server.handle_request::<lsp::request::ResolveCompletionItem, _, _>(
3692        |params, _| async move {
3693            assert_eq!(params.label, "first_method(…)");
3694            Ok(lsp::CompletionItem {
3695                label: "first_method(…)".into(),
3696                detail: Some("fn(&mut self, B) -> C".into()),
3697                text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
3698                    new_text: "first_method($1)".to_string(),
3699                    range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
3700                })),
3701                additional_text_edits: Some(vec![lsp::TextEdit {
3702                    new_text: "use d::SomeTrait;\n".to_string(),
3703                    range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
3704                }]),
3705                insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
3706                ..Default::default()
3707            })
3708        },
3709    );
3710
3711    // The additional edit is applied.
3712    cx_a.foreground().run_until_parked();
3713    buffer_a.read_with(cx_a, |buffer, _| {
3714        assert_eq!(
3715            buffer.text(),
3716            "use d::SomeTrait;\nfn main() { a.first_method() }"
3717        );
3718    });
3719    buffer_b.read_with(cx_b, |buffer, _| {
3720        assert_eq!(
3721            buffer.text(),
3722            "use d::SomeTrait;\nfn main() { a.first_method() }"
3723        );
3724    });
3725}
3726
3727#[gpui::test(iterations = 10)]
3728async fn test_reloading_buffer_manually(
3729    deterministic: Arc<Deterministic>,
3730    cx_a: &mut TestAppContext,
3731    cx_b: &mut TestAppContext,
3732) {
3733    deterministic.forbid_parking();
3734    let mut server = TestServer::start(&deterministic).await;
3735    let client_a = server.create_client(cx_a, "user_a").await;
3736    let client_b = server.create_client(cx_b, "user_b").await;
3737    server
3738        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3739        .await;
3740    let active_call_a = cx_a.read(ActiveCall::global);
3741
3742    client_a
3743        .fs
3744        .insert_tree("/a", json!({ "a.rs": "let one = 1;" }))
3745        .await;
3746    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
3747    let buffer_a = project_a
3748        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
3749        .await
3750        .unwrap();
3751    let project_id = active_call_a
3752        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3753        .await
3754        .unwrap();
3755
3756    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3757
3758    let buffer_b = cx_b
3759        .background()
3760        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
3761        .await
3762        .unwrap();
3763    buffer_b.update(cx_b, |buffer, cx| {
3764        buffer.edit([(4..7, "six")], None, cx);
3765        buffer.edit([(10..11, "6")], None, cx);
3766        assert_eq!(buffer.text(), "let six = 6;");
3767        assert!(buffer.is_dirty());
3768        assert!(!buffer.has_conflict());
3769    });
3770    cx_a.foreground().run_until_parked();
3771    buffer_a.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "let six = 6;"));
3772
3773    client_a
3774        .fs
3775        .save(
3776            "/a/a.rs".as_ref(),
3777            &Rope::from("let seven = 7;"),
3778            LineEnding::Unix,
3779        )
3780        .await
3781        .unwrap();
3782    cx_a.foreground().run_until_parked();
3783    buffer_a.read_with(cx_a, |buffer, _| assert!(buffer.has_conflict()));
3784    buffer_b.read_with(cx_b, |buffer, _| assert!(buffer.has_conflict()));
3785
3786    project_b
3787        .update(cx_b, |project, cx| {
3788            project.reload_buffers(HashSet::from_iter([buffer_b.clone()]), true, cx)
3789        })
3790        .await
3791        .unwrap();
3792    buffer_a.read_with(cx_a, |buffer, _| {
3793        assert_eq!(buffer.text(), "let seven = 7;");
3794        assert!(!buffer.is_dirty());
3795        assert!(!buffer.has_conflict());
3796    });
3797    buffer_b.read_with(cx_b, |buffer, _| {
3798        assert_eq!(buffer.text(), "let seven = 7;");
3799        assert!(!buffer.is_dirty());
3800        assert!(!buffer.has_conflict());
3801    });
3802
3803    buffer_a.update(cx_a, |buffer, cx| {
3804        // Undoing on the host is a no-op when the reload was initiated by the guest.
3805        buffer.undo(cx);
3806        assert_eq!(buffer.text(), "let seven = 7;");
3807        assert!(!buffer.is_dirty());
3808        assert!(!buffer.has_conflict());
3809    });
3810    buffer_b.update(cx_b, |buffer, cx| {
3811        // Undoing on the guest rolls back the buffer to before it was reloaded but the conflict gets cleared.
3812        buffer.undo(cx);
3813        assert_eq!(buffer.text(), "let six = 6;");
3814        assert!(buffer.is_dirty());
3815        assert!(!buffer.has_conflict());
3816    });
3817}
3818
3819#[gpui::test(iterations = 10)]
3820async fn test_formatting_buffer(
3821    deterministic: Arc<Deterministic>,
3822    cx_a: &mut TestAppContext,
3823    cx_b: &mut TestAppContext,
3824) {
3825    use project::FormatTrigger;
3826
3827    let mut server = TestServer::start(&deterministic).await;
3828    let client_a = server.create_client(cx_a, "user_a").await;
3829    let client_b = server.create_client(cx_b, "user_b").await;
3830    server
3831        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3832        .await;
3833    let active_call_a = cx_a.read(ActiveCall::global);
3834
3835    // Set up a fake language server.
3836    let mut language = Language::new(
3837        LanguageConfig {
3838            name: "Rust".into(),
3839            path_suffixes: vec!["rs".to_string()],
3840            ..Default::default()
3841        },
3842        Some(tree_sitter_rust::language()),
3843    );
3844    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
3845    client_a.language_registry.add(Arc::new(language));
3846
3847    // Here we insert a fake tree with a directory that exists on disk. This is needed
3848    // because later we'll invoke a command, which requires passing a working directory
3849    // that points to a valid location on disk.
3850    let directory = env::current_dir().unwrap();
3851    client_a
3852        .fs
3853        .insert_tree(&directory, json!({ "a.rs": "let one = \"two\"" }))
3854        .await;
3855    let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await;
3856    let project_id = active_call_a
3857        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3858        .await
3859        .unwrap();
3860    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3861
3862    let buffer_b = cx_b
3863        .background()
3864        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
3865        .await
3866        .unwrap();
3867
3868    let fake_language_server = fake_language_servers.next().await.unwrap();
3869    fake_language_server.handle_request::<lsp::request::Formatting, _, _>(|_, _| async move {
3870        Ok(Some(vec![
3871            lsp::TextEdit {
3872                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 4)),
3873                new_text: "h".to_string(),
3874            },
3875            lsp::TextEdit {
3876                range: lsp::Range::new(lsp::Position::new(0, 7), lsp::Position::new(0, 7)),
3877                new_text: "y".to_string(),
3878            },
3879        ]))
3880    });
3881
3882    project_b
3883        .update(cx_b, |project, cx| {
3884            project.format(
3885                HashSet::from_iter([buffer_b.clone()]),
3886                true,
3887                FormatTrigger::Save,
3888                cx,
3889            )
3890        })
3891        .await
3892        .unwrap();
3893
3894    // The edits from the LSP are applied, and a final newline is added.
3895    assert_eq!(
3896        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
3897        "let honey = \"two\"\n"
3898    );
3899
3900    // Ensure buffer can be formatted using an external command. Notice how the
3901    // host's configuration is honored as opposed to using the guest's settings.
3902    cx_a.update(|cx| {
3903        cx.update_global(|settings: &mut Settings, _| {
3904            settings.editor_defaults.formatter = Some(Formatter::External {
3905                command: "awk".to_string(),
3906                arguments: vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()],
3907            });
3908        });
3909    });
3910    project_b
3911        .update(cx_b, |project, cx| {
3912            project.format(
3913                HashSet::from_iter([buffer_b.clone()]),
3914                true,
3915                FormatTrigger::Save,
3916                cx,
3917            )
3918        })
3919        .await
3920        .unwrap();
3921    assert_eq!(
3922        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
3923        format!("let honey = \"{}/a.rs\"\n", directory.to_str().unwrap())
3924    );
3925}
3926
3927#[gpui::test(iterations = 10)]
3928async fn test_definition(
3929    deterministic: Arc<Deterministic>,
3930    cx_a: &mut TestAppContext,
3931    cx_b: &mut TestAppContext,
3932) {
3933    deterministic.forbid_parking();
3934    let mut server = TestServer::start(&deterministic).await;
3935    let client_a = server.create_client(cx_a, "user_a").await;
3936    let client_b = server.create_client(cx_b, "user_b").await;
3937    server
3938        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3939        .await;
3940    let active_call_a = cx_a.read(ActiveCall::global);
3941
3942    // Set up a fake language server.
3943    let mut language = Language::new(
3944        LanguageConfig {
3945            name: "Rust".into(),
3946            path_suffixes: vec!["rs".to_string()],
3947            ..Default::default()
3948        },
3949        Some(tree_sitter_rust::language()),
3950    );
3951    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
3952    client_a.language_registry.add(Arc::new(language));
3953
3954    client_a
3955        .fs
3956        .insert_tree(
3957            "/root",
3958            json!({
3959                "dir-1": {
3960                    "a.rs": "const ONE: usize = b::TWO + b::THREE;",
3961                },
3962                "dir-2": {
3963                    "b.rs": "const TWO: c::T2 = 2;\nconst THREE: usize = 3;",
3964                    "c.rs": "type T2 = usize;",
3965                }
3966            }),
3967        )
3968        .await;
3969    let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await;
3970    let project_id = active_call_a
3971        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3972        .await
3973        .unwrap();
3974    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3975
3976    // Open the file on client B.
3977    let buffer_b = cx_b
3978        .background()
3979        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
3980        .await
3981        .unwrap();
3982
3983    // Request the definition of a symbol as the guest.
3984    let fake_language_server = fake_language_servers.next().await.unwrap();
3985    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
3986        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
3987            lsp::Location::new(
3988                lsp::Url::from_file_path("/root/dir-2/b.rs").unwrap(),
3989                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
3990            ),
3991        )))
3992    });
3993
3994    let definitions_1 = project_b
3995        .update(cx_b, |p, cx| p.definition(&buffer_b, 23, cx))
3996        .await
3997        .unwrap();
3998    cx_b.read(|cx| {
3999        assert_eq!(definitions_1.len(), 1);
4000        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4001        let target_buffer = definitions_1[0].target.buffer.read(cx);
4002        assert_eq!(
4003            target_buffer.text(),
4004            "const TWO: c::T2 = 2;\nconst THREE: usize = 3;"
4005        );
4006        assert_eq!(
4007            definitions_1[0].target.range.to_point(target_buffer),
4008            Point::new(0, 6)..Point::new(0, 9)
4009        );
4010    });
4011
4012    // Try getting more definitions for the same buffer, ensuring the buffer gets reused from
4013    // the previous call to `definition`.
4014    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
4015        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4016            lsp::Location::new(
4017                lsp::Url::from_file_path("/root/dir-2/b.rs").unwrap(),
4018                lsp::Range::new(lsp::Position::new(1, 6), lsp::Position::new(1, 11)),
4019            ),
4020        )))
4021    });
4022
4023    let definitions_2 = project_b
4024        .update(cx_b, |p, cx| p.definition(&buffer_b, 33, cx))
4025        .await
4026        .unwrap();
4027    cx_b.read(|cx| {
4028        assert_eq!(definitions_2.len(), 1);
4029        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4030        let target_buffer = definitions_2[0].target.buffer.read(cx);
4031        assert_eq!(
4032            target_buffer.text(),
4033            "const TWO: c::T2 = 2;\nconst THREE: usize = 3;"
4034        );
4035        assert_eq!(
4036            definitions_2[0].target.range.to_point(target_buffer),
4037            Point::new(1, 6)..Point::new(1, 11)
4038        );
4039    });
4040    assert_eq!(
4041        definitions_1[0].target.buffer,
4042        definitions_2[0].target.buffer
4043    );
4044
4045    fake_language_server.handle_request::<lsp::request::GotoTypeDefinition, _, _>(
4046        |req, _| async move {
4047            assert_eq!(
4048                req.text_document_position_params.position,
4049                lsp::Position::new(0, 7)
4050            );
4051            Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4052                lsp::Location::new(
4053                    lsp::Url::from_file_path("/root/dir-2/c.rs").unwrap(),
4054                    lsp::Range::new(lsp::Position::new(0, 5), lsp::Position::new(0, 7)),
4055                ),
4056            )))
4057        },
4058    );
4059
4060    let type_definitions = project_b
4061        .update(cx_b, |p, cx| p.type_definition(&buffer_b, 7, cx))
4062        .await
4063        .unwrap();
4064    cx_b.read(|cx| {
4065        assert_eq!(type_definitions.len(), 1);
4066        let target_buffer = type_definitions[0].target.buffer.read(cx);
4067        assert_eq!(target_buffer.text(), "type T2 = usize;");
4068        assert_eq!(
4069            type_definitions[0].target.range.to_point(target_buffer),
4070            Point::new(0, 5)..Point::new(0, 7)
4071        );
4072    });
4073}
4074
4075#[gpui::test(iterations = 10)]
4076async fn test_references(
4077    deterministic: Arc<Deterministic>,
4078    cx_a: &mut TestAppContext,
4079    cx_b: &mut TestAppContext,
4080) {
4081    deterministic.forbid_parking();
4082    let mut server = TestServer::start(&deterministic).await;
4083    let client_a = server.create_client(cx_a, "user_a").await;
4084    let client_b = server.create_client(cx_b, "user_b").await;
4085    server
4086        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4087        .await;
4088    let active_call_a = cx_a.read(ActiveCall::global);
4089
4090    // Set up a fake language server.
4091    let mut language = Language::new(
4092        LanguageConfig {
4093            name: "Rust".into(),
4094            path_suffixes: vec!["rs".to_string()],
4095            ..Default::default()
4096        },
4097        Some(tree_sitter_rust::language()),
4098    );
4099    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4100    client_a.language_registry.add(Arc::new(language));
4101
4102    client_a
4103        .fs
4104        .insert_tree(
4105            "/root",
4106            json!({
4107                "dir-1": {
4108                    "one.rs": "const ONE: usize = 1;",
4109                    "two.rs": "const TWO: usize = one::ONE + one::ONE;",
4110                },
4111                "dir-2": {
4112                    "three.rs": "const THREE: usize = two::TWO + one::ONE;",
4113                }
4114            }),
4115        )
4116        .await;
4117    let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await;
4118    let project_id = active_call_a
4119        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4120        .await
4121        .unwrap();
4122    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4123
4124    // Open the file on client B.
4125    let buffer_b = cx_b
4126        .background()
4127        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx)))
4128        .await
4129        .unwrap();
4130
4131    // Request references to a symbol as the guest.
4132    let fake_language_server = fake_language_servers.next().await.unwrap();
4133    fake_language_server.handle_request::<lsp::request::References, _, _>(|params, _| async move {
4134        assert_eq!(
4135            params.text_document_position.text_document.uri.as_str(),
4136            "file:///root/dir-1/one.rs"
4137        );
4138        Ok(Some(vec![
4139            lsp::Location {
4140                uri: lsp::Url::from_file_path("/root/dir-1/two.rs").unwrap(),
4141                range: lsp::Range::new(lsp::Position::new(0, 24), lsp::Position::new(0, 27)),
4142            },
4143            lsp::Location {
4144                uri: lsp::Url::from_file_path("/root/dir-1/two.rs").unwrap(),
4145                range: lsp::Range::new(lsp::Position::new(0, 35), lsp::Position::new(0, 38)),
4146            },
4147            lsp::Location {
4148                uri: lsp::Url::from_file_path("/root/dir-2/three.rs").unwrap(),
4149                range: lsp::Range::new(lsp::Position::new(0, 37), lsp::Position::new(0, 40)),
4150            },
4151        ]))
4152    });
4153
4154    let references = project_b
4155        .update(cx_b, |p, cx| p.references(&buffer_b, 7, cx))
4156        .await
4157        .unwrap();
4158    cx_b.read(|cx| {
4159        assert_eq!(references.len(), 3);
4160        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4161
4162        let two_buffer = references[0].buffer.read(cx);
4163        let three_buffer = references[2].buffer.read(cx);
4164        assert_eq!(
4165            two_buffer.file().unwrap().path().as_ref(),
4166            Path::new("two.rs")
4167        );
4168        assert_eq!(references[1].buffer, references[0].buffer);
4169        assert_eq!(
4170            three_buffer.file().unwrap().full_path(cx),
4171            Path::new("/root/dir-2/three.rs")
4172        );
4173
4174        assert_eq!(references[0].range.to_offset(two_buffer), 24..27);
4175        assert_eq!(references[1].range.to_offset(two_buffer), 35..38);
4176        assert_eq!(references[2].range.to_offset(three_buffer), 37..40);
4177    });
4178}
4179
4180#[gpui::test(iterations = 10)]
4181async fn test_project_search(
4182    deterministic: Arc<Deterministic>,
4183    cx_a: &mut TestAppContext,
4184    cx_b: &mut TestAppContext,
4185) {
4186    deterministic.forbid_parking();
4187    let mut server = TestServer::start(&deterministic).await;
4188    let client_a = server.create_client(cx_a, "user_a").await;
4189    let client_b = server.create_client(cx_b, "user_b").await;
4190    server
4191        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4192        .await;
4193    let active_call_a = cx_a.read(ActiveCall::global);
4194
4195    client_a
4196        .fs
4197        .insert_tree(
4198            "/root",
4199            json!({
4200                "dir-1": {
4201                    "a": "hello world",
4202                    "b": "goodnight moon",
4203                    "c": "a world of goo",
4204                    "d": "world champion of clown world",
4205                },
4206                "dir-2": {
4207                    "e": "disney world is fun",
4208                }
4209            }),
4210        )
4211        .await;
4212    let (project_a, _) = client_a.build_local_project("/root/dir-1", cx_a).await;
4213    let (worktree_2, _) = project_a
4214        .update(cx_a, |p, cx| {
4215            p.find_or_create_local_worktree("/root/dir-2", true, cx)
4216        })
4217        .await
4218        .unwrap();
4219    worktree_2
4220        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
4221        .await;
4222    let project_id = active_call_a
4223        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4224        .await
4225        .unwrap();
4226
4227    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4228
4229    // Perform a search as the guest.
4230    let results = project_b
4231        .update(cx_b, |project, cx| {
4232            project.search(SearchQuery::text("world", false, false), cx)
4233        })
4234        .await
4235        .unwrap();
4236
4237    let mut ranges_by_path = results
4238        .into_iter()
4239        .map(|(buffer, ranges)| {
4240            buffer.read_with(cx_b, |buffer, cx| {
4241                let path = buffer.file().unwrap().full_path(cx);
4242                let offset_ranges = ranges
4243                    .into_iter()
4244                    .map(|range| range.to_offset(buffer))
4245                    .collect::<Vec<_>>();
4246                (path, offset_ranges)
4247            })
4248        })
4249        .collect::<Vec<_>>();
4250    ranges_by_path.sort_by_key(|(path, _)| path.clone());
4251
4252    assert_eq!(
4253        ranges_by_path,
4254        &[
4255            (PathBuf::from("dir-1/a"), vec![6..11]),
4256            (PathBuf::from("dir-1/c"), vec![2..7]),
4257            (PathBuf::from("dir-1/d"), vec![0..5, 24..29]),
4258            (PathBuf::from("dir-2/e"), vec![7..12]),
4259        ]
4260    );
4261}
4262
4263#[gpui::test(iterations = 10)]
4264async fn test_document_highlights(
4265    deterministic: Arc<Deterministic>,
4266    cx_a: &mut TestAppContext,
4267    cx_b: &mut TestAppContext,
4268) {
4269    deterministic.forbid_parking();
4270    let mut server = TestServer::start(&deterministic).await;
4271    let client_a = server.create_client(cx_a, "user_a").await;
4272    let client_b = server.create_client(cx_b, "user_b").await;
4273    server
4274        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4275        .await;
4276    let active_call_a = cx_a.read(ActiveCall::global);
4277
4278    client_a
4279        .fs
4280        .insert_tree(
4281            "/root-1",
4282            json!({
4283                "main.rs": "fn double(number: i32) -> i32 { number + number }",
4284            }),
4285        )
4286        .await;
4287
4288    // Set up a fake language server.
4289    let mut language = Language::new(
4290        LanguageConfig {
4291            name: "Rust".into(),
4292            path_suffixes: vec!["rs".to_string()],
4293            ..Default::default()
4294        },
4295        Some(tree_sitter_rust::language()),
4296    );
4297    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4298    client_a.language_registry.add(Arc::new(language));
4299
4300    let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
4301    let project_id = active_call_a
4302        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4303        .await
4304        .unwrap();
4305    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4306
4307    // Open the file on client B.
4308    let buffer_b = cx_b
4309        .background()
4310        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)))
4311        .await
4312        .unwrap();
4313
4314    // Request document highlights as the guest.
4315    let fake_language_server = fake_language_servers.next().await.unwrap();
4316    fake_language_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>(
4317        |params, _| async move {
4318            assert_eq!(
4319                params
4320                    .text_document_position_params
4321                    .text_document
4322                    .uri
4323                    .as_str(),
4324                "file:///root-1/main.rs"
4325            );
4326            assert_eq!(
4327                params.text_document_position_params.position,
4328                lsp::Position::new(0, 34)
4329            );
4330            Ok(Some(vec![
4331                lsp::DocumentHighlight {
4332                    kind: Some(lsp::DocumentHighlightKind::WRITE),
4333                    range: lsp::Range::new(lsp::Position::new(0, 10), lsp::Position::new(0, 16)),
4334                },
4335                lsp::DocumentHighlight {
4336                    kind: Some(lsp::DocumentHighlightKind::READ),
4337                    range: lsp::Range::new(lsp::Position::new(0, 32), lsp::Position::new(0, 38)),
4338                },
4339                lsp::DocumentHighlight {
4340                    kind: Some(lsp::DocumentHighlightKind::READ),
4341                    range: lsp::Range::new(lsp::Position::new(0, 41), lsp::Position::new(0, 47)),
4342                },
4343            ]))
4344        },
4345    );
4346
4347    let highlights = project_b
4348        .update(cx_b, |p, cx| p.document_highlights(&buffer_b, 34, cx))
4349        .await
4350        .unwrap();
4351    buffer_b.read_with(cx_b, |buffer, _| {
4352        let snapshot = buffer.snapshot();
4353
4354        let highlights = highlights
4355            .into_iter()
4356            .map(|highlight| (highlight.kind, highlight.range.to_offset(&snapshot)))
4357            .collect::<Vec<_>>();
4358        assert_eq!(
4359            highlights,
4360            &[
4361                (lsp::DocumentHighlightKind::WRITE, 10..16),
4362                (lsp::DocumentHighlightKind::READ, 32..38),
4363                (lsp::DocumentHighlightKind::READ, 41..47)
4364            ]
4365        )
4366    });
4367}
4368
4369#[gpui::test(iterations = 10)]
4370async fn test_lsp_hover(
4371    deterministic: Arc<Deterministic>,
4372    cx_a: &mut TestAppContext,
4373    cx_b: &mut TestAppContext,
4374) {
4375    deterministic.forbid_parking();
4376    let mut server = TestServer::start(&deterministic).await;
4377    let client_a = server.create_client(cx_a, "user_a").await;
4378    let client_b = server.create_client(cx_b, "user_b").await;
4379    server
4380        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4381        .await;
4382    let active_call_a = cx_a.read(ActiveCall::global);
4383
4384    client_a
4385        .fs
4386        .insert_tree(
4387            "/root-1",
4388            json!({
4389                "main.rs": "use std::collections::HashMap;",
4390            }),
4391        )
4392        .await;
4393
4394    // Set up a fake language server.
4395    let mut language = Language::new(
4396        LanguageConfig {
4397            name: "Rust".into(),
4398            path_suffixes: vec!["rs".to_string()],
4399            ..Default::default()
4400        },
4401        Some(tree_sitter_rust::language()),
4402    );
4403    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4404    client_a.language_registry.add(Arc::new(language));
4405
4406    let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
4407    let project_id = active_call_a
4408        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4409        .await
4410        .unwrap();
4411    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4412
4413    // Open the file as the guest
4414    let buffer_b = cx_b
4415        .background()
4416        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)))
4417        .await
4418        .unwrap();
4419
4420    // Request hover information as the guest.
4421    let fake_language_server = fake_language_servers.next().await.unwrap();
4422    fake_language_server.handle_request::<lsp::request::HoverRequest, _, _>(
4423        |params, _| async move {
4424            assert_eq!(
4425                params
4426                    .text_document_position_params
4427                    .text_document
4428                    .uri
4429                    .as_str(),
4430                "file:///root-1/main.rs"
4431            );
4432            assert_eq!(
4433                params.text_document_position_params.position,
4434                lsp::Position::new(0, 22)
4435            );
4436            Ok(Some(lsp::Hover {
4437                contents: lsp::HoverContents::Array(vec![
4438                    lsp::MarkedString::String("Test hover content.".to_string()),
4439                    lsp::MarkedString::LanguageString(lsp::LanguageString {
4440                        language: "Rust".to_string(),
4441                        value: "let foo = 42;".to_string(),
4442                    }),
4443                ]),
4444                range: Some(lsp::Range::new(
4445                    lsp::Position::new(0, 22),
4446                    lsp::Position::new(0, 29),
4447                )),
4448            }))
4449        },
4450    );
4451
4452    let hover_info = project_b
4453        .update(cx_b, |p, cx| p.hover(&buffer_b, 22, cx))
4454        .await
4455        .unwrap()
4456        .unwrap();
4457    buffer_b.read_with(cx_b, |buffer, _| {
4458        let snapshot = buffer.snapshot();
4459        assert_eq!(hover_info.range.unwrap().to_offset(&snapshot), 22..29);
4460        assert_eq!(
4461            hover_info.contents,
4462            vec![
4463                project::HoverBlock {
4464                    text: "Test hover content.".to_string(),
4465                    language: None,
4466                },
4467                project::HoverBlock {
4468                    text: "let foo = 42;".to_string(),
4469                    language: Some("Rust".to_string()),
4470                }
4471            ]
4472        );
4473    });
4474}
4475
4476#[gpui::test(iterations = 10)]
4477async fn test_project_symbols(
4478    deterministic: Arc<Deterministic>,
4479    cx_a: &mut TestAppContext,
4480    cx_b: &mut TestAppContext,
4481) {
4482    deterministic.forbid_parking();
4483    let mut server = TestServer::start(&deterministic).await;
4484    let client_a = server.create_client(cx_a, "user_a").await;
4485    let client_b = server.create_client(cx_b, "user_b").await;
4486    server
4487        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4488        .await;
4489    let active_call_a = cx_a.read(ActiveCall::global);
4490
4491    // Set up a fake language server.
4492    let mut language = Language::new(
4493        LanguageConfig {
4494            name: "Rust".into(),
4495            path_suffixes: vec!["rs".to_string()],
4496            ..Default::default()
4497        },
4498        Some(tree_sitter_rust::language()),
4499    );
4500    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4501    client_a.language_registry.add(Arc::new(language));
4502
4503    client_a
4504        .fs
4505        .insert_tree(
4506            "/code",
4507            json!({
4508                "crate-1": {
4509                    "one.rs": "const ONE: usize = 1;",
4510                },
4511                "crate-2": {
4512                    "two.rs": "const TWO: usize = 2; const THREE: usize = 3;",
4513                },
4514                "private": {
4515                    "passwords.txt": "the-password",
4516                }
4517            }),
4518        )
4519        .await;
4520    let (project_a, worktree_id) = client_a.build_local_project("/code/crate-1", cx_a).await;
4521    let project_id = active_call_a
4522        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4523        .await
4524        .unwrap();
4525    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4526
4527    // Cause the language server to start.
4528    let _buffer = cx_b
4529        .background()
4530        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx)))
4531        .await
4532        .unwrap();
4533
4534    let fake_language_server = fake_language_servers.next().await.unwrap();
4535    fake_language_server.handle_request::<lsp::request::WorkspaceSymbol, _, _>(|_, _| async move {
4536        #[allow(deprecated)]
4537        Ok(Some(vec![lsp::SymbolInformation {
4538            name: "TWO".into(),
4539            location: lsp::Location {
4540                uri: lsp::Url::from_file_path("/code/crate-2/two.rs").unwrap(),
4541                range: lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
4542            },
4543            kind: lsp::SymbolKind::CONSTANT,
4544            tags: None,
4545            container_name: None,
4546            deprecated: None,
4547        }]))
4548    });
4549
4550    // Request the definition of a symbol as the guest.
4551    let symbols = project_b
4552        .update(cx_b, |p, cx| p.symbols("two", cx))
4553        .await
4554        .unwrap();
4555    assert_eq!(symbols.len(), 1);
4556    assert_eq!(symbols[0].name, "TWO");
4557
4558    // Open one of the returned symbols.
4559    let buffer_b_2 = project_b
4560        .update(cx_b, |project, cx| {
4561            project.open_buffer_for_symbol(&symbols[0], cx)
4562        })
4563        .await
4564        .unwrap();
4565    buffer_b_2.read_with(cx_b, |buffer, _| {
4566        assert_eq!(
4567            buffer.file().unwrap().path().as_ref(),
4568            Path::new("../crate-2/two.rs")
4569        );
4570    });
4571
4572    // Attempt to craft a symbol and violate host's privacy by opening an arbitrary file.
4573    let mut fake_symbol = symbols[0].clone();
4574    fake_symbol.path.path = Path::new("/code/secrets").into();
4575    let error = project_b
4576        .update(cx_b, |project, cx| {
4577            project.open_buffer_for_symbol(&fake_symbol, cx)
4578        })
4579        .await
4580        .unwrap_err();
4581    assert!(error.to_string().contains("invalid symbol signature"));
4582}
4583
4584#[gpui::test(iterations = 10)]
4585async fn test_open_buffer_while_getting_definition_pointing_to_it(
4586    deterministic: Arc<Deterministic>,
4587    cx_a: &mut TestAppContext,
4588    cx_b: &mut TestAppContext,
4589    mut rng: StdRng,
4590) {
4591    deterministic.forbid_parking();
4592    let mut server = TestServer::start(&deterministic).await;
4593    let client_a = server.create_client(cx_a, "user_a").await;
4594    let client_b = server.create_client(cx_b, "user_b").await;
4595    server
4596        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4597        .await;
4598    let active_call_a = cx_a.read(ActiveCall::global);
4599
4600    // Set up a fake language server.
4601    let mut language = Language::new(
4602        LanguageConfig {
4603            name: "Rust".into(),
4604            path_suffixes: vec!["rs".to_string()],
4605            ..Default::default()
4606        },
4607        Some(tree_sitter_rust::language()),
4608    );
4609    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4610    client_a.language_registry.add(Arc::new(language));
4611
4612    client_a
4613        .fs
4614        .insert_tree(
4615            "/root",
4616            json!({
4617                "a.rs": "const ONE: usize = b::TWO;",
4618                "b.rs": "const TWO: usize = 2",
4619            }),
4620        )
4621        .await;
4622    let (project_a, worktree_id) = client_a.build_local_project("/root", cx_a).await;
4623    let project_id = active_call_a
4624        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4625        .await
4626        .unwrap();
4627    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4628
4629    let buffer_b1 = cx_b
4630        .background()
4631        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
4632        .await
4633        .unwrap();
4634
4635    let fake_language_server = fake_language_servers.next().await.unwrap();
4636    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
4637        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4638            lsp::Location::new(
4639                lsp::Url::from_file_path("/root/b.rs").unwrap(),
4640                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
4641            ),
4642        )))
4643    });
4644
4645    let definitions;
4646    let buffer_b2;
4647    if rng.gen() {
4648        definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
4649        buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
4650    } else {
4651        buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
4652        definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
4653    }
4654
4655    let buffer_b2 = buffer_b2.await.unwrap();
4656    let definitions = definitions.await.unwrap();
4657    assert_eq!(definitions.len(), 1);
4658    assert_eq!(definitions[0].target.buffer, buffer_b2);
4659}
4660
4661#[gpui::test(iterations = 10)]
4662async fn test_collaborating_with_code_actions(
4663    deterministic: Arc<Deterministic>,
4664    cx_a: &mut TestAppContext,
4665    cx_b: &mut TestAppContext,
4666) {
4667    deterministic.forbid_parking();
4668    cx_b.update(editor::init);
4669    let mut server = TestServer::start(&deterministic).await;
4670    let client_a = server.create_client(cx_a, "user_a").await;
4671    let client_b = server.create_client(cx_b, "user_b").await;
4672    server
4673        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4674        .await;
4675    let active_call_a = cx_a.read(ActiveCall::global);
4676
4677    // Set up a fake language server.
4678    let mut language = Language::new(
4679        LanguageConfig {
4680            name: "Rust".into(),
4681            path_suffixes: vec!["rs".to_string()],
4682            ..Default::default()
4683        },
4684        Some(tree_sitter_rust::language()),
4685    );
4686    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4687    client_a.language_registry.add(Arc::new(language));
4688
4689    client_a
4690        .fs
4691        .insert_tree(
4692            "/a",
4693            json!({
4694                "main.rs": "mod other;\nfn main() { let foo = other::foo(); }",
4695                "other.rs": "pub fn foo() -> usize { 4 }",
4696            }),
4697        )
4698        .await;
4699    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
4700    let project_id = active_call_a
4701        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4702        .await
4703        .unwrap();
4704
4705    // Join the project as client B.
4706    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4707    let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
4708    let editor_b = workspace_b
4709        .update(cx_b, |workspace, cx| {
4710            workspace.open_path((worktree_id, "main.rs"), None, true, cx)
4711        })
4712        .await
4713        .unwrap()
4714        .downcast::<Editor>()
4715        .unwrap();
4716
4717    let mut fake_language_server = fake_language_servers.next().await.unwrap();
4718    fake_language_server
4719        .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
4720            assert_eq!(
4721                params.text_document.uri,
4722                lsp::Url::from_file_path("/a/main.rs").unwrap(),
4723            );
4724            assert_eq!(params.range.start, lsp::Position::new(0, 0));
4725            assert_eq!(params.range.end, lsp::Position::new(0, 0));
4726            Ok(None)
4727        })
4728        .next()
4729        .await;
4730
4731    // Move cursor to a location that contains code actions.
4732    editor_b.update(cx_b, |editor, cx| {
4733        editor.change_selections(None, cx, |s| {
4734            s.select_ranges([Point::new(1, 31)..Point::new(1, 31)])
4735        });
4736        cx.focus(&editor_b);
4737    });
4738
4739    fake_language_server
4740        .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
4741            assert_eq!(
4742                params.text_document.uri,
4743                lsp::Url::from_file_path("/a/main.rs").unwrap(),
4744            );
4745            assert_eq!(params.range.start, lsp::Position::new(1, 31));
4746            assert_eq!(params.range.end, lsp::Position::new(1, 31));
4747
4748            Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
4749                lsp::CodeAction {
4750                    title: "Inline into all callers".to_string(),
4751                    edit: Some(lsp::WorkspaceEdit {
4752                        changes: Some(
4753                            [
4754                                (
4755                                    lsp::Url::from_file_path("/a/main.rs").unwrap(),
4756                                    vec![lsp::TextEdit::new(
4757                                        lsp::Range::new(
4758                                            lsp::Position::new(1, 22),
4759                                            lsp::Position::new(1, 34),
4760                                        ),
4761                                        "4".to_string(),
4762                                    )],
4763                                ),
4764                                (
4765                                    lsp::Url::from_file_path("/a/other.rs").unwrap(),
4766                                    vec![lsp::TextEdit::new(
4767                                        lsp::Range::new(
4768                                            lsp::Position::new(0, 0),
4769                                            lsp::Position::new(0, 27),
4770                                        ),
4771                                        "".to_string(),
4772                                    )],
4773                                ),
4774                            ]
4775                            .into_iter()
4776                            .collect(),
4777                        ),
4778                        ..Default::default()
4779                    }),
4780                    data: Some(json!({
4781                        "codeActionParams": {
4782                            "range": {
4783                                "start": {"line": 1, "column": 31},
4784                                "end": {"line": 1, "column": 31},
4785                            }
4786                        }
4787                    })),
4788                    ..Default::default()
4789                },
4790            )]))
4791        })
4792        .next()
4793        .await;
4794
4795    // Toggle code actions and wait for them to display.
4796    editor_b.update(cx_b, |editor, cx| {
4797        editor.toggle_code_actions(
4798            &ToggleCodeActions {
4799                deployed_from_indicator: false,
4800            },
4801            cx,
4802        );
4803    });
4804    cx_a.foreground().run_until_parked();
4805    editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
4806
4807    fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>();
4808
4809    // Confirming the code action will trigger a resolve request.
4810    let confirm_action = workspace_b
4811        .update(cx_b, |workspace, cx| {
4812            Editor::confirm_code_action(workspace, &ConfirmCodeAction { item_ix: Some(0) }, cx)
4813        })
4814        .unwrap();
4815    fake_language_server.handle_request::<lsp::request::CodeActionResolveRequest, _, _>(
4816        |_, _| async move {
4817            Ok(lsp::CodeAction {
4818                title: "Inline into all callers".to_string(),
4819                edit: Some(lsp::WorkspaceEdit {
4820                    changes: Some(
4821                        [
4822                            (
4823                                lsp::Url::from_file_path("/a/main.rs").unwrap(),
4824                                vec![lsp::TextEdit::new(
4825                                    lsp::Range::new(
4826                                        lsp::Position::new(1, 22),
4827                                        lsp::Position::new(1, 34),
4828                                    ),
4829                                    "4".to_string(),
4830                                )],
4831                            ),
4832                            (
4833                                lsp::Url::from_file_path("/a/other.rs").unwrap(),
4834                                vec![lsp::TextEdit::new(
4835                                    lsp::Range::new(
4836                                        lsp::Position::new(0, 0),
4837                                        lsp::Position::new(0, 27),
4838                                    ),
4839                                    "".to_string(),
4840                                )],
4841                            ),
4842                        ]
4843                        .into_iter()
4844                        .collect(),
4845                    ),
4846                    ..Default::default()
4847                }),
4848                ..Default::default()
4849            })
4850        },
4851    );
4852
4853    // After the action is confirmed, an editor containing both modified files is opened.
4854    confirm_action.await.unwrap();
4855    let code_action_editor = workspace_b.read_with(cx_b, |workspace, cx| {
4856        workspace
4857            .active_item(cx)
4858            .unwrap()
4859            .downcast::<Editor>()
4860            .unwrap()
4861    });
4862    code_action_editor.update(cx_b, |editor, cx| {
4863        assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
4864        editor.undo(&Undo, cx);
4865        assert_eq!(
4866            editor.text(cx),
4867            "mod other;\nfn main() { let foo = other::foo(); }\npub fn foo() -> usize { 4 }"
4868        );
4869        editor.redo(&Redo, cx);
4870        assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
4871    });
4872}
4873
4874#[gpui::test(iterations = 10)]
4875async fn test_collaborating_with_renames(
4876    deterministic: Arc<Deterministic>,
4877    cx_a: &mut TestAppContext,
4878    cx_b: &mut TestAppContext,
4879) {
4880    deterministic.forbid_parking();
4881    cx_b.update(editor::init);
4882    let mut server = TestServer::start(&deterministic).await;
4883    let client_a = server.create_client(cx_a, "user_a").await;
4884    let client_b = server.create_client(cx_b, "user_b").await;
4885    server
4886        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4887        .await;
4888    let active_call_a = cx_a.read(ActiveCall::global);
4889
4890    // Set up a fake language server.
4891    let mut language = Language::new(
4892        LanguageConfig {
4893            name: "Rust".into(),
4894            path_suffixes: vec!["rs".to_string()],
4895            ..Default::default()
4896        },
4897        Some(tree_sitter_rust::language()),
4898    );
4899    let mut fake_language_servers = language
4900        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
4901            capabilities: lsp::ServerCapabilities {
4902                rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
4903                    prepare_provider: Some(true),
4904                    work_done_progress_options: Default::default(),
4905                })),
4906                ..Default::default()
4907            },
4908            ..Default::default()
4909        }))
4910        .await;
4911    client_a.language_registry.add(Arc::new(language));
4912
4913    client_a
4914        .fs
4915        .insert_tree(
4916            "/dir",
4917            json!({
4918                "one.rs": "const ONE: usize = 1;",
4919                "two.rs": "const TWO: usize = one::ONE + one::ONE;"
4920            }),
4921        )
4922        .await;
4923    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
4924    let project_id = active_call_a
4925        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4926        .await
4927        .unwrap();
4928    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4929
4930    let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
4931    let editor_b = workspace_b
4932        .update(cx_b, |workspace, cx| {
4933            workspace.open_path((worktree_id, "one.rs"), None, true, cx)
4934        })
4935        .await
4936        .unwrap()
4937        .downcast::<Editor>()
4938        .unwrap();
4939    let fake_language_server = fake_language_servers.next().await.unwrap();
4940
4941    // Move cursor to a location that can be renamed.
4942    let prepare_rename = editor_b.update(cx_b, |editor, cx| {
4943        editor.change_selections(None, cx, |s| s.select_ranges([7..7]));
4944        editor.rename(&Rename, cx).unwrap()
4945    });
4946
4947    fake_language_server
4948        .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
4949            assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
4950            assert_eq!(params.position, lsp::Position::new(0, 7));
4951            Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
4952                lsp::Position::new(0, 6),
4953                lsp::Position::new(0, 9),
4954            ))))
4955        })
4956        .next()
4957        .await
4958        .unwrap();
4959    prepare_rename.await.unwrap();
4960    editor_b.update(cx_b, |editor, cx| {
4961        let rename = editor.pending_rename().unwrap();
4962        let buffer = editor.buffer().read(cx).snapshot(cx);
4963        assert_eq!(
4964            rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
4965            6..9
4966        );
4967        rename.editor.update(cx, |rename_editor, cx| {
4968            rename_editor.buffer().update(cx, |rename_buffer, cx| {
4969                rename_buffer.edit([(0..3, "THREE")], None, cx);
4970            });
4971        });
4972    });
4973
4974    let confirm_rename = workspace_b.update(cx_b, |workspace, cx| {
4975        Editor::confirm_rename(workspace, &ConfirmRename, cx).unwrap()
4976    });
4977    fake_language_server
4978        .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
4979            assert_eq!(
4980                params.text_document_position.text_document.uri.as_str(),
4981                "file:///dir/one.rs"
4982            );
4983            assert_eq!(
4984                params.text_document_position.position,
4985                lsp::Position::new(0, 6)
4986            );
4987            assert_eq!(params.new_name, "THREE");
4988            Ok(Some(lsp::WorkspaceEdit {
4989                changes: Some(
4990                    [
4991                        (
4992                            lsp::Url::from_file_path("/dir/one.rs").unwrap(),
4993                            vec![lsp::TextEdit::new(
4994                                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
4995                                "THREE".to_string(),
4996                            )],
4997                        ),
4998                        (
4999                            lsp::Url::from_file_path("/dir/two.rs").unwrap(),
5000                            vec![
5001                                lsp::TextEdit::new(
5002                                    lsp::Range::new(
5003                                        lsp::Position::new(0, 24),
5004                                        lsp::Position::new(0, 27),
5005                                    ),
5006                                    "THREE".to_string(),
5007                                ),
5008                                lsp::TextEdit::new(
5009                                    lsp::Range::new(
5010                                        lsp::Position::new(0, 35),
5011                                        lsp::Position::new(0, 38),
5012                                    ),
5013                                    "THREE".to_string(),
5014                                ),
5015                            ],
5016                        ),
5017                    ]
5018                    .into_iter()
5019                    .collect(),
5020                ),
5021                ..Default::default()
5022            }))
5023        })
5024        .next()
5025        .await
5026        .unwrap();
5027    confirm_rename.await.unwrap();
5028
5029    let rename_editor = workspace_b.read_with(cx_b, |workspace, cx| {
5030        workspace
5031            .active_item(cx)
5032            .unwrap()
5033            .downcast::<Editor>()
5034            .unwrap()
5035    });
5036    rename_editor.update(cx_b, |editor, cx| {
5037        assert_eq!(
5038            editor.text(cx),
5039            "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
5040        );
5041        editor.undo(&Undo, cx);
5042        assert_eq!(
5043            editor.text(cx),
5044            "const ONE: usize = 1;\nconst TWO: usize = one::ONE + one::ONE;"
5045        );
5046        editor.redo(&Redo, cx);
5047        assert_eq!(
5048            editor.text(cx),
5049            "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
5050        );
5051    });
5052
5053    // Ensure temporary rename edits cannot be undone/redone.
5054    editor_b.update(cx_b, |editor, cx| {
5055        editor.undo(&Undo, cx);
5056        assert_eq!(editor.text(cx), "const ONE: usize = 1;");
5057        editor.undo(&Undo, cx);
5058        assert_eq!(editor.text(cx), "const ONE: usize = 1;");
5059        editor.redo(&Redo, cx);
5060        assert_eq!(editor.text(cx), "const THREE: usize = 1;");
5061    })
5062}
5063
5064#[gpui::test(iterations = 10)]
5065async fn test_language_server_statuses(
5066    deterministic: Arc<Deterministic>,
5067    cx_a: &mut TestAppContext,
5068    cx_b: &mut TestAppContext,
5069) {
5070    deterministic.forbid_parking();
5071
5072    cx_b.update(editor::init);
5073    let mut server = TestServer::start(&deterministic).await;
5074    let client_a = server.create_client(cx_a, "user_a").await;
5075    let client_b = server.create_client(cx_b, "user_b").await;
5076    server
5077        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
5078        .await;
5079    let active_call_a = cx_a.read(ActiveCall::global);
5080
5081    // Set up a fake language server.
5082    let mut language = Language::new(
5083        LanguageConfig {
5084            name: "Rust".into(),
5085            path_suffixes: vec!["rs".to_string()],
5086            ..Default::default()
5087        },
5088        Some(tree_sitter_rust::language()),
5089    );
5090    let mut fake_language_servers = language
5091        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
5092            name: "the-language-server",
5093            ..Default::default()
5094        }))
5095        .await;
5096    client_a.language_registry.add(Arc::new(language));
5097
5098    client_a
5099        .fs
5100        .insert_tree(
5101            "/dir",
5102            json!({
5103                "main.rs": "const ONE: usize = 1;",
5104            }),
5105        )
5106        .await;
5107    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
5108
5109    let _buffer_a = project_a
5110        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
5111        .await
5112        .unwrap();
5113
5114    let fake_language_server = fake_language_servers.next().await.unwrap();
5115    fake_language_server.start_progress("the-token").await;
5116    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
5117        token: lsp::NumberOrString::String("the-token".to_string()),
5118        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
5119            lsp::WorkDoneProgressReport {
5120                message: Some("the-message".to_string()),
5121                ..Default::default()
5122            },
5123        )),
5124    });
5125    deterministic.run_until_parked();
5126    project_a.read_with(cx_a, |project, _| {
5127        let status = project.language_server_statuses().next().unwrap();
5128        assert_eq!(status.name, "the-language-server");
5129        assert_eq!(status.pending_work.len(), 1);
5130        assert_eq!(
5131            status.pending_work["the-token"].message.as_ref().unwrap(),
5132            "the-message"
5133        );
5134    });
5135
5136    let project_id = active_call_a
5137        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5138        .await
5139        .unwrap();
5140    deterministic.run_until_parked();
5141    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5142    project_b.read_with(cx_b, |project, _| {
5143        let status = project.language_server_statuses().next().unwrap();
5144        assert_eq!(status.name, "the-language-server");
5145    });
5146
5147    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
5148        token: lsp::NumberOrString::String("the-token".to_string()),
5149        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
5150            lsp::WorkDoneProgressReport {
5151                message: Some("the-message-2".to_string()),
5152                ..Default::default()
5153            },
5154        )),
5155    });
5156    deterministic.run_until_parked();
5157    project_a.read_with(cx_a, |project, _| {
5158        let status = project.language_server_statuses().next().unwrap();
5159        assert_eq!(status.name, "the-language-server");
5160        assert_eq!(status.pending_work.len(), 1);
5161        assert_eq!(
5162            status.pending_work["the-token"].message.as_ref().unwrap(),
5163            "the-message-2"
5164        );
5165    });
5166    project_b.read_with(cx_b, |project, _| {
5167        let status = project.language_server_statuses().next().unwrap();
5168        assert_eq!(status.name, "the-language-server");
5169        assert_eq!(status.pending_work.len(), 1);
5170        assert_eq!(
5171            status.pending_work["the-token"].message.as_ref().unwrap(),
5172            "the-message-2"
5173        );
5174    });
5175}
5176
5177#[gpui::test(iterations = 10)]
5178async fn test_contacts(
5179    deterministic: Arc<Deterministic>,
5180    cx_a: &mut TestAppContext,
5181    cx_b: &mut TestAppContext,
5182    cx_c: &mut TestAppContext,
5183    cx_d: &mut TestAppContext,
5184) {
5185    deterministic.forbid_parking();
5186    let mut server = TestServer::start(&deterministic).await;
5187    let client_a = server.create_client(cx_a, "user_a").await;
5188    let client_b = server.create_client(cx_b, "user_b").await;
5189    let client_c = server.create_client(cx_c, "user_c").await;
5190    let client_d = server.create_client(cx_d, "user_d").await;
5191    server
5192        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
5193        .await;
5194    let active_call_a = cx_a.read(ActiveCall::global);
5195    let active_call_b = cx_b.read(ActiveCall::global);
5196    let active_call_c = cx_c.read(ActiveCall::global);
5197    let _active_call_d = cx_d.read(ActiveCall::global);
5198
5199    deterministic.run_until_parked();
5200    assert_eq!(
5201        contacts(&client_a, cx_a),
5202        [
5203            ("user_b".to_string(), "online", "free"),
5204            ("user_c".to_string(), "online", "free")
5205        ]
5206    );
5207    assert_eq!(
5208        contacts(&client_b, cx_b),
5209        [
5210            ("user_a".to_string(), "online", "free"),
5211            ("user_c".to_string(), "online", "free")
5212        ]
5213    );
5214    assert_eq!(
5215        contacts(&client_c, cx_c),
5216        [
5217            ("user_a".to_string(), "online", "free"),
5218            ("user_b".to_string(), "online", "free")
5219        ]
5220    );
5221    assert_eq!(contacts(&client_d, cx_d), []);
5222
5223    server.disconnect_client(client_c.peer_id().unwrap());
5224    server.forbid_connections();
5225    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
5226    assert_eq!(
5227        contacts(&client_a, cx_a),
5228        [
5229            ("user_b".to_string(), "online", "free"),
5230            ("user_c".to_string(), "offline", "free")
5231        ]
5232    );
5233    assert_eq!(
5234        contacts(&client_b, cx_b),
5235        [
5236            ("user_a".to_string(), "online", "free"),
5237            ("user_c".to_string(), "offline", "free")
5238        ]
5239    );
5240    assert_eq!(contacts(&client_c, cx_c), []);
5241    assert_eq!(contacts(&client_d, cx_d), []);
5242
5243    server.allow_connections();
5244    client_c
5245        .authenticate_and_connect(false, &cx_c.to_async())
5246        .await
5247        .unwrap();
5248
5249    deterministic.run_until_parked();
5250    assert_eq!(
5251        contacts(&client_a, cx_a),
5252        [
5253            ("user_b".to_string(), "online", "free"),
5254            ("user_c".to_string(), "online", "free")
5255        ]
5256    );
5257    assert_eq!(
5258        contacts(&client_b, cx_b),
5259        [
5260            ("user_a".to_string(), "online", "free"),
5261            ("user_c".to_string(), "online", "free")
5262        ]
5263    );
5264    assert_eq!(
5265        contacts(&client_c, cx_c),
5266        [
5267            ("user_a".to_string(), "online", "free"),
5268            ("user_b".to_string(), "online", "free")
5269        ]
5270    );
5271    assert_eq!(contacts(&client_d, cx_d), []);
5272
5273    active_call_a
5274        .update(cx_a, |call, cx| {
5275            call.invite(client_b.user_id().unwrap(), None, cx)
5276        })
5277        .await
5278        .unwrap();
5279    deterministic.run_until_parked();
5280    assert_eq!(
5281        contacts(&client_a, cx_a),
5282        [
5283            ("user_b".to_string(), "online", "busy"),
5284            ("user_c".to_string(), "online", "free")
5285        ]
5286    );
5287    assert_eq!(
5288        contacts(&client_b, cx_b),
5289        [
5290            ("user_a".to_string(), "online", "busy"),
5291            ("user_c".to_string(), "online", "free")
5292        ]
5293    );
5294    assert_eq!(
5295        contacts(&client_c, cx_c),
5296        [
5297            ("user_a".to_string(), "online", "busy"),
5298            ("user_b".to_string(), "online", "busy")
5299        ]
5300    );
5301    assert_eq!(contacts(&client_d, cx_d), []);
5302
5303    // Client B and client D become contacts while client B is being called.
5304    server
5305        .make_contacts(&mut [(&client_b, cx_b), (&client_d, cx_d)])
5306        .await;
5307    deterministic.run_until_parked();
5308    assert_eq!(
5309        contacts(&client_a, cx_a),
5310        [
5311            ("user_b".to_string(), "online", "busy"),
5312            ("user_c".to_string(), "online", "free")
5313        ]
5314    );
5315    assert_eq!(
5316        contacts(&client_b, cx_b),
5317        [
5318            ("user_a".to_string(), "online", "busy"),
5319            ("user_c".to_string(), "online", "free"),
5320            ("user_d".to_string(), "online", "free"),
5321        ]
5322    );
5323    assert_eq!(
5324        contacts(&client_c, cx_c),
5325        [
5326            ("user_a".to_string(), "online", "busy"),
5327            ("user_b".to_string(), "online", "busy")
5328        ]
5329    );
5330    assert_eq!(
5331        contacts(&client_d, cx_d),
5332        [("user_b".to_string(), "online", "busy")]
5333    );
5334
5335    active_call_b.update(cx_b, |call, _| call.decline_incoming().unwrap());
5336    deterministic.run_until_parked();
5337    assert_eq!(
5338        contacts(&client_a, cx_a),
5339        [
5340            ("user_b".to_string(), "online", "free"),
5341            ("user_c".to_string(), "online", "free")
5342        ]
5343    );
5344    assert_eq!(
5345        contacts(&client_b, cx_b),
5346        [
5347            ("user_a".to_string(), "online", "free"),
5348            ("user_c".to_string(), "online", "free"),
5349            ("user_d".to_string(), "online", "free")
5350        ]
5351    );
5352    assert_eq!(
5353        contacts(&client_c, cx_c),
5354        [
5355            ("user_a".to_string(), "online", "free"),
5356            ("user_b".to_string(), "online", "free")
5357        ]
5358    );
5359    assert_eq!(
5360        contacts(&client_d, cx_d),
5361        [("user_b".to_string(), "online", "free")]
5362    );
5363
5364    active_call_c
5365        .update(cx_c, |call, cx| {
5366            call.invite(client_a.user_id().unwrap(), None, cx)
5367        })
5368        .await
5369        .unwrap();
5370    deterministic.run_until_parked();
5371    assert_eq!(
5372        contacts(&client_a, cx_a),
5373        [
5374            ("user_b".to_string(), "online", "free"),
5375            ("user_c".to_string(), "online", "busy")
5376        ]
5377    );
5378    assert_eq!(
5379        contacts(&client_b, cx_b),
5380        [
5381            ("user_a".to_string(), "online", "busy"),
5382            ("user_c".to_string(), "online", "busy"),
5383            ("user_d".to_string(), "online", "free")
5384        ]
5385    );
5386    assert_eq!(
5387        contacts(&client_c, cx_c),
5388        [
5389            ("user_a".to_string(), "online", "busy"),
5390            ("user_b".to_string(), "online", "free")
5391        ]
5392    );
5393    assert_eq!(
5394        contacts(&client_d, cx_d),
5395        [("user_b".to_string(), "online", "free")]
5396    );
5397
5398    active_call_a
5399        .update(cx_a, |call, cx| call.accept_incoming(cx))
5400        .await
5401        .unwrap();
5402    deterministic.run_until_parked();
5403    assert_eq!(
5404        contacts(&client_a, cx_a),
5405        [
5406            ("user_b".to_string(), "online", "free"),
5407            ("user_c".to_string(), "online", "busy")
5408        ]
5409    );
5410    assert_eq!(
5411        contacts(&client_b, cx_b),
5412        [
5413            ("user_a".to_string(), "online", "busy"),
5414            ("user_c".to_string(), "online", "busy"),
5415            ("user_d".to_string(), "online", "free")
5416        ]
5417    );
5418    assert_eq!(
5419        contacts(&client_c, cx_c),
5420        [
5421            ("user_a".to_string(), "online", "busy"),
5422            ("user_b".to_string(), "online", "free")
5423        ]
5424    );
5425    assert_eq!(
5426        contacts(&client_d, cx_d),
5427        [("user_b".to_string(), "online", "free")]
5428    );
5429
5430    active_call_a
5431        .update(cx_a, |call, cx| {
5432            call.invite(client_b.user_id().unwrap(), None, cx)
5433        })
5434        .await
5435        .unwrap();
5436    deterministic.run_until_parked();
5437    assert_eq!(
5438        contacts(&client_a, cx_a),
5439        [
5440            ("user_b".to_string(), "online", "busy"),
5441            ("user_c".to_string(), "online", "busy")
5442        ]
5443    );
5444    assert_eq!(
5445        contacts(&client_b, cx_b),
5446        [
5447            ("user_a".to_string(), "online", "busy"),
5448            ("user_c".to_string(), "online", "busy"),
5449            ("user_d".to_string(), "online", "free")
5450        ]
5451    );
5452    assert_eq!(
5453        contacts(&client_c, cx_c),
5454        [
5455            ("user_a".to_string(), "online", "busy"),
5456            ("user_b".to_string(), "online", "busy")
5457        ]
5458    );
5459    assert_eq!(
5460        contacts(&client_d, cx_d),
5461        [("user_b".to_string(), "online", "busy")]
5462    );
5463
5464    active_call_a
5465        .update(cx_a, |call, cx| call.hang_up(cx))
5466        .await
5467        .unwrap();
5468    deterministic.run_until_parked();
5469    assert_eq!(
5470        contacts(&client_a, cx_a),
5471        [
5472            ("user_b".to_string(), "online", "free"),
5473            ("user_c".to_string(), "online", "free")
5474        ]
5475    );
5476    assert_eq!(
5477        contacts(&client_b, cx_b),
5478        [
5479            ("user_a".to_string(), "online", "free"),
5480            ("user_c".to_string(), "online", "free"),
5481            ("user_d".to_string(), "online", "free")
5482        ]
5483    );
5484    assert_eq!(
5485        contacts(&client_c, cx_c),
5486        [
5487            ("user_a".to_string(), "online", "free"),
5488            ("user_b".to_string(), "online", "free")
5489        ]
5490    );
5491    assert_eq!(
5492        contacts(&client_d, cx_d),
5493        [("user_b".to_string(), "online", "free")]
5494    );
5495
5496    active_call_a
5497        .update(cx_a, |call, cx| {
5498            call.invite(client_b.user_id().unwrap(), None, cx)
5499        })
5500        .await
5501        .unwrap();
5502    deterministic.run_until_parked();
5503    assert_eq!(
5504        contacts(&client_a, cx_a),
5505        [
5506            ("user_b".to_string(), "online", "busy"),
5507            ("user_c".to_string(), "online", "free")
5508        ]
5509    );
5510    assert_eq!(
5511        contacts(&client_b, cx_b),
5512        [
5513            ("user_a".to_string(), "online", "busy"),
5514            ("user_c".to_string(), "online", "free"),
5515            ("user_d".to_string(), "online", "free")
5516        ]
5517    );
5518    assert_eq!(
5519        contacts(&client_c, cx_c),
5520        [
5521            ("user_a".to_string(), "online", "busy"),
5522            ("user_b".to_string(), "online", "busy")
5523        ]
5524    );
5525    assert_eq!(
5526        contacts(&client_d, cx_d),
5527        [("user_b".to_string(), "online", "busy")]
5528    );
5529
5530    server.forbid_connections();
5531    server.disconnect_client(client_a.peer_id().unwrap());
5532    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
5533    assert_eq!(contacts(&client_a, cx_a), []);
5534    assert_eq!(
5535        contacts(&client_b, cx_b),
5536        [
5537            ("user_a".to_string(), "offline", "free"),
5538            ("user_c".to_string(), "online", "free"),
5539            ("user_d".to_string(), "online", "free")
5540        ]
5541    );
5542    assert_eq!(
5543        contacts(&client_c, cx_c),
5544        [
5545            ("user_a".to_string(), "offline", "free"),
5546            ("user_b".to_string(), "online", "free")
5547        ]
5548    );
5549    assert_eq!(
5550        contacts(&client_d, cx_d),
5551        [("user_b".to_string(), "online", "free")]
5552    );
5553
5554    // Test removing a contact
5555    client_b
5556        .user_store
5557        .update(cx_b, |store, cx| {
5558            store.remove_contact(client_c.user_id().unwrap(), cx)
5559        })
5560        .await
5561        .unwrap();
5562    deterministic.run_until_parked();
5563    assert_eq!(
5564        contacts(&client_b, cx_b),
5565        [
5566            ("user_a".to_string(), "offline", "free"),
5567            ("user_d".to_string(), "online", "free")
5568        ]
5569    );
5570    assert_eq!(
5571        contacts(&client_c, cx_c),
5572        [("user_a".to_string(), "offline", "free"),]
5573    );
5574
5575    fn contacts(
5576        client: &TestClient,
5577        cx: &TestAppContext,
5578    ) -> Vec<(String, &'static str, &'static str)> {
5579        client.user_store.read_with(cx, |store, _| {
5580            store
5581                .contacts()
5582                .iter()
5583                .map(|contact| {
5584                    (
5585                        contact.user.github_login.clone(),
5586                        if contact.online { "online" } else { "offline" },
5587                        if contact.busy { "busy" } else { "free" },
5588                    )
5589                })
5590                .collect()
5591        })
5592    }
5593}
5594
5595#[gpui::test(iterations = 10)]
5596async fn test_contact_requests(
5597    deterministic: Arc<Deterministic>,
5598    cx_a: &mut TestAppContext,
5599    cx_a2: &mut TestAppContext,
5600    cx_b: &mut TestAppContext,
5601    cx_b2: &mut TestAppContext,
5602    cx_c: &mut TestAppContext,
5603    cx_c2: &mut TestAppContext,
5604) {
5605    deterministic.forbid_parking();
5606
5607    // Connect to a server as 3 clients.
5608    let mut server = TestServer::start(&deterministic).await;
5609    let client_a = server.create_client(cx_a, "user_a").await;
5610    let client_a2 = server.create_client(cx_a2, "user_a").await;
5611    let client_b = server.create_client(cx_b, "user_b").await;
5612    let client_b2 = server.create_client(cx_b2, "user_b").await;
5613    let client_c = server.create_client(cx_c, "user_c").await;
5614    let client_c2 = server.create_client(cx_c2, "user_c").await;
5615
5616    assert_eq!(client_a.user_id().unwrap(), client_a2.user_id().unwrap());
5617    assert_eq!(client_b.user_id().unwrap(), client_b2.user_id().unwrap());
5618    assert_eq!(client_c.user_id().unwrap(), client_c2.user_id().unwrap());
5619
5620    // User A and User C request that user B become their contact.
5621    client_a
5622        .user_store
5623        .update(cx_a, |store, cx| {
5624            store.request_contact(client_b.user_id().unwrap(), cx)
5625        })
5626        .await
5627        .unwrap();
5628    client_c
5629        .user_store
5630        .update(cx_c, |store, cx| {
5631            store.request_contact(client_b.user_id().unwrap(), cx)
5632        })
5633        .await
5634        .unwrap();
5635    deterministic.run_until_parked();
5636
5637    // All users see the pending request appear in all their clients.
5638    assert_eq!(
5639        client_a.summarize_contacts(cx_a).outgoing_requests,
5640        &["user_b"]
5641    );
5642    assert_eq!(
5643        client_a2.summarize_contacts(cx_a2).outgoing_requests,
5644        &["user_b"]
5645    );
5646    assert_eq!(
5647        client_b.summarize_contacts(cx_b).incoming_requests,
5648        &["user_a", "user_c"]
5649    );
5650    assert_eq!(
5651        client_b2.summarize_contacts(cx_b2).incoming_requests,
5652        &["user_a", "user_c"]
5653    );
5654    assert_eq!(
5655        client_c.summarize_contacts(cx_c).outgoing_requests,
5656        &["user_b"]
5657    );
5658    assert_eq!(
5659        client_c2.summarize_contacts(cx_c2).outgoing_requests,
5660        &["user_b"]
5661    );
5662
5663    // Contact requests are present upon connecting (tested here via disconnect/reconnect)
5664    disconnect_and_reconnect(&client_a, cx_a).await;
5665    disconnect_and_reconnect(&client_b, cx_b).await;
5666    disconnect_and_reconnect(&client_c, cx_c).await;
5667    deterministic.run_until_parked();
5668    assert_eq!(
5669        client_a.summarize_contacts(cx_a).outgoing_requests,
5670        &["user_b"]
5671    );
5672    assert_eq!(
5673        client_b.summarize_contacts(cx_b).incoming_requests,
5674        &["user_a", "user_c"]
5675    );
5676    assert_eq!(
5677        client_c.summarize_contacts(cx_c).outgoing_requests,
5678        &["user_b"]
5679    );
5680
5681    // User B accepts the request from user A.
5682    client_b
5683        .user_store
5684        .update(cx_b, |store, cx| {
5685            store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
5686        })
5687        .await
5688        .unwrap();
5689
5690    deterministic.run_until_parked();
5691
5692    // User B sees user A as their contact now in all client, and the incoming request from them is removed.
5693    let contacts_b = client_b.summarize_contacts(cx_b);
5694    assert_eq!(contacts_b.current, &["user_a"]);
5695    assert_eq!(contacts_b.incoming_requests, &["user_c"]);
5696    let contacts_b2 = client_b2.summarize_contacts(cx_b2);
5697    assert_eq!(contacts_b2.current, &["user_a"]);
5698    assert_eq!(contacts_b2.incoming_requests, &["user_c"]);
5699
5700    // User A sees user B as their contact now in all clients, and the outgoing request to them is removed.
5701    let contacts_a = client_a.summarize_contacts(cx_a);
5702    assert_eq!(contacts_a.current, &["user_b"]);
5703    assert!(contacts_a.outgoing_requests.is_empty());
5704    let contacts_a2 = client_a2.summarize_contacts(cx_a2);
5705    assert_eq!(contacts_a2.current, &["user_b"]);
5706    assert!(contacts_a2.outgoing_requests.is_empty());
5707
5708    // Contacts are present upon connecting (tested here via disconnect/reconnect)
5709    disconnect_and_reconnect(&client_a, cx_a).await;
5710    disconnect_and_reconnect(&client_b, cx_b).await;
5711    disconnect_and_reconnect(&client_c, cx_c).await;
5712    deterministic.run_until_parked();
5713    assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
5714    assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
5715    assert_eq!(
5716        client_b.summarize_contacts(cx_b).incoming_requests,
5717        &["user_c"]
5718    );
5719    assert!(client_c.summarize_contacts(cx_c).current.is_empty());
5720    assert_eq!(
5721        client_c.summarize_contacts(cx_c).outgoing_requests,
5722        &["user_b"]
5723    );
5724
5725    // User B rejects the request from user C.
5726    client_b
5727        .user_store
5728        .update(cx_b, |store, cx| {
5729            store.respond_to_contact_request(client_c.user_id().unwrap(), false, cx)
5730        })
5731        .await
5732        .unwrap();
5733
5734    deterministic.run_until_parked();
5735
5736    // User B doesn't see user C as their contact, and the incoming request from them is removed.
5737    let contacts_b = client_b.summarize_contacts(cx_b);
5738    assert_eq!(contacts_b.current, &["user_a"]);
5739    assert!(contacts_b.incoming_requests.is_empty());
5740    let contacts_b2 = client_b2.summarize_contacts(cx_b2);
5741    assert_eq!(contacts_b2.current, &["user_a"]);
5742    assert!(contacts_b2.incoming_requests.is_empty());
5743
5744    // User C doesn't see user B as their contact, and the outgoing request to them is removed.
5745    let contacts_c = client_c.summarize_contacts(cx_c);
5746    assert!(contacts_c.current.is_empty());
5747    assert!(contacts_c.outgoing_requests.is_empty());
5748    let contacts_c2 = client_c2.summarize_contacts(cx_c2);
5749    assert!(contacts_c2.current.is_empty());
5750    assert!(contacts_c2.outgoing_requests.is_empty());
5751
5752    // Incoming/outgoing requests are not present upon connecting (tested here via disconnect/reconnect)
5753    disconnect_and_reconnect(&client_a, cx_a).await;
5754    disconnect_and_reconnect(&client_b, cx_b).await;
5755    disconnect_and_reconnect(&client_c, cx_c).await;
5756    deterministic.run_until_parked();
5757    assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
5758    assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
5759    assert!(client_b
5760        .summarize_contacts(cx_b)
5761        .incoming_requests
5762        .is_empty());
5763    assert!(client_c.summarize_contacts(cx_c).current.is_empty());
5764    assert!(client_c
5765        .summarize_contacts(cx_c)
5766        .outgoing_requests
5767        .is_empty());
5768
5769    async fn disconnect_and_reconnect(client: &TestClient, cx: &mut TestAppContext) {
5770        client.disconnect(&cx.to_async());
5771        client.clear_contacts(cx).await;
5772        client
5773            .authenticate_and_connect(false, &cx.to_async())
5774            .await
5775            .unwrap();
5776    }
5777}
5778
5779#[gpui::test(iterations = 10)]
5780async fn test_basic_following(
5781    deterministic: Arc<Deterministic>,
5782    cx_a: &mut TestAppContext,
5783    cx_b: &mut TestAppContext,
5784    cx_c: &mut TestAppContext,
5785    cx_d: &mut TestAppContext,
5786) {
5787    deterministic.forbid_parking();
5788    cx_a.update(editor::init);
5789    cx_b.update(editor::init);
5790
5791    let mut server = TestServer::start(&deterministic).await;
5792    let client_a = server.create_client(cx_a, "user_a").await;
5793    let client_b = server.create_client(cx_b, "user_b").await;
5794    let client_c = server.create_client(cx_c, "user_c").await;
5795    let client_d = server.create_client(cx_d, "user_d").await;
5796    server
5797        .create_room(&mut [
5798            (&client_a, cx_a),
5799            (&client_b, cx_b),
5800            (&client_c, cx_c),
5801            (&client_d, cx_d),
5802        ])
5803        .await;
5804    let active_call_a = cx_a.read(ActiveCall::global);
5805    let active_call_b = cx_b.read(ActiveCall::global);
5806
5807    client_a
5808        .fs
5809        .insert_tree(
5810            "/a",
5811            json!({
5812                "1.txt": "one\none\none",
5813                "2.txt": "two\ntwo\ntwo",
5814                "3.txt": "three\nthree\nthree",
5815            }),
5816        )
5817        .await;
5818    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
5819    active_call_a
5820        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
5821        .await
5822        .unwrap();
5823
5824    let project_id = active_call_a
5825        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5826        .await
5827        .unwrap();
5828    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5829    active_call_b
5830        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
5831        .await
5832        .unwrap();
5833
5834    let workspace_a = client_a.build_workspace(&project_a, cx_a);
5835    let workspace_b = client_b.build_workspace(&project_b, cx_b);
5836
5837    // Client A opens some editors.
5838    let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
5839    let editor_a1 = workspace_a
5840        .update(cx_a, |workspace, cx| {
5841            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
5842        })
5843        .await
5844        .unwrap()
5845        .downcast::<Editor>()
5846        .unwrap();
5847    let editor_a2 = workspace_a
5848        .update(cx_a, |workspace, cx| {
5849            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
5850        })
5851        .await
5852        .unwrap()
5853        .downcast::<Editor>()
5854        .unwrap();
5855
5856    // Client B opens an editor.
5857    let editor_b1 = workspace_b
5858        .update(cx_b, |workspace, cx| {
5859            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
5860        })
5861        .await
5862        .unwrap()
5863        .downcast::<Editor>()
5864        .unwrap();
5865
5866    let peer_id_a = client_a.peer_id().unwrap();
5867    let peer_id_b = client_b.peer_id().unwrap();
5868    let peer_id_c = client_c.peer_id().unwrap();
5869    let peer_id_d = client_d.peer_id().unwrap();
5870
5871    // Client A updates their selections in those editors
5872    editor_a1.update(cx_a, |editor, cx| {
5873        editor.change_selections(None, cx, |s| s.select_ranges([0..1]))
5874    });
5875    editor_a2.update(cx_a, |editor, cx| {
5876        editor.change_selections(None, cx, |s| s.select_ranges([2..3]))
5877    });
5878
5879    // When client B starts following client A, all visible view states are replicated to client B.
5880    workspace_b
5881        .update(cx_b, |workspace, cx| {
5882            workspace
5883                .toggle_follow(&ToggleFollow(peer_id_a), cx)
5884                .unwrap()
5885        })
5886        .await
5887        .unwrap();
5888
5889    cx_c.foreground().run_until_parked();
5890    let active_call_c = cx_c.read(ActiveCall::global);
5891    let project_c = client_c.build_remote_project(project_id, cx_c).await;
5892    let workspace_c = client_c.build_workspace(&project_c, cx_c);
5893    active_call_c
5894        .update(cx_c, |call, cx| call.set_location(Some(&project_c), cx))
5895        .await
5896        .unwrap();
5897    drop(project_c);
5898
5899    // Client C also follows client A.
5900    workspace_c
5901        .update(cx_c, |workspace, cx| {
5902            workspace
5903                .toggle_follow(&ToggleFollow(peer_id_a), cx)
5904                .unwrap()
5905        })
5906        .await
5907        .unwrap();
5908
5909    cx_d.foreground().run_until_parked();
5910    let active_call_d = cx_d.read(ActiveCall::global);
5911    let project_d = client_d.build_remote_project(project_id, cx_d).await;
5912    let workspace_d = client_d.build_workspace(&project_d, cx_d);
5913    active_call_d
5914        .update(cx_d, |call, cx| call.set_location(Some(&project_d), cx))
5915        .await
5916        .unwrap();
5917    drop(project_d);
5918
5919    // All clients see that clients B and C are following client A.
5920    cx_c.foreground().run_until_parked();
5921    for (name, active_call, cx) in [
5922        ("A", &active_call_a, &cx_a),
5923        ("B", &active_call_b, &cx_b),
5924        ("C", &active_call_c, &cx_c),
5925        ("D", &active_call_d, &cx_d),
5926    ] {
5927        active_call.read_with(*cx, |call, cx| {
5928            let room = call.room().unwrap().read(cx);
5929            assert_eq!(
5930                room.followers_for(peer_id_a, project_id),
5931                &[peer_id_b, peer_id_c],
5932                "checking followers for A as {name}"
5933            );
5934        });
5935    }
5936
5937    // Client C unfollows client A.
5938    workspace_c.update(cx_c, |workspace, cx| {
5939        workspace.toggle_follow(&ToggleFollow(peer_id_a), cx);
5940    });
5941
5942    // All clients see that clients B is following client A.
5943    cx_c.foreground().run_until_parked();
5944    for (name, active_call, cx) in [
5945        ("A", &active_call_a, &cx_a),
5946        ("B", &active_call_b, &cx_b),
5947        ("C", &active_call_c, &cx_c),
5948        ("D", &active_call_d, &cx_d),
5949    ] {
5950        active_call.read_with(*cx, |call, cx| {
5951            let room = call.room().unwrap().read(cx);
5952            assert_eq!(
5953                room.followers_for(peer_id_a, project_id),
5954                &[peer_id_b],
5955                "checking followers for A as {name}"
5956            );
5957        });
5958    }
5959
5960    // Client C re-follows client A.
5961    workspace_c.update(cx_c, |workspace, cx| {
5962        workspace.toggle_follow(&ToggleFollow(peer_id_a), cx);
5963    });
5964
5965    // All clients see that clients B and C are following client A.
5966    cx_c.foreground().run_until_parked();
5967    for (name, active_call, cx) in [
5968        ("A", &active_call_a, &cx_a),
5969        ("B", &active_call_b, &cx_b),
5970        ("C", &active_call_c, &cx_c),
5971        ("D", &active_call_d, &cx_d),
5972    ] {
5973        active_call.read_with(*cx, |call, cx| {
5974            let room = call.room().unwrap().read(cx);
5975            assert_eq!(
5976                room.followers_for(peer_id_a, project_id),
5977                &[peer_id_b, peer_id_c],
5978                "checking followers for A as {name}"
5979            );
5980        });
5981    }
5982
5983    // Client D follows client C.
5984    workspace_d
5985        .update(cx_d, |workspace, cx| {
5986            workspace
5987                .toggle_follow(&ToggleFollow(peer_id_c), cx)
5988                .unwrap()
5989        })
5990        .await
5991        .unwrap();
5992
5993    // All clients see that D is following C
5994    cx_d.foreground().run_until_parked();
5995    for (name, active_call, cx) in [
5996        ("A", &active_call_a, &cx_a),
5997        ("B", &active_call_b, &cx_b),
5998        ("C", &active_call_c, &cx_c),
5999        ("D", &active_call_d, &cx_d),
6000    ] {
6001        active_call.read_with(*cx, |call, cx| {
6002            let room = call.room().unwrap().read(cx);
6003            assert_eq!(
6004                room.followers_for(peer_id_c, project_id),
6005                &[peer_id_d],
6006                "checking followers for C as {name}"
6007            );
6008        });
6009    }
6010
6011    // Client C closes the project.
6012    cx_c.drop_last(workspace_c);
6013
6014    // Clients A and B see that client B is following A, and client C is not present in the followers.
6015    cx_c.foreground().run_until_parked();
6016    for (name, active_call, cx) in [("A", &active_call_a, &cx_a), ("B", &active_call_b, &cx_b)] {
6017        active_call.read_with(*cx, |call, cx| {
6018            let room = call.room().unwrap().read(cx);
6019            assert_eq!(
6020                room.followers_for(peer_id_a, project_id),
6021                &[peer_id_b],
6022                "checking followers for A as {name}"
6023            );
6024        });
6025    }
6026
6027    // All clients see that no-one is following C
6028    for (name, active_call, cx) in [
6029        ("A", &active_call_a, &cx_a),
6030        ("B", &active_call_b, &cx_b),
6031        ("C", &active_call_c, &cx_c),
6032        ("D", &active_call_d, &cx_d),
6033    ] {
6034        active_call.read_with(*cx, |call, cx| {
6035            let room = call.room().unwrap().read(cx);
6036            assert_eq!(
6037                room.followers_for(peer_id_c, project_id),
6038                &[],
6039                "checking followers for C as {name}"
6040            );
6041        });
6042    }
6043
6044    let editor_b2 = workspace_b.read_with(cx_b, |workspace, cx| {
6045        workspace
6046            .active_item(cx)
6047            .unwrap()
6048            .downcast::<Editor>()
6049            .unwrap()
6050    });
6051    assert_eq!(
6052        cx_b.read(|cx| editor_b2.project_path(cx)),
6053        Some((worktree_id, "2.txt").into())
6054    );
6055    assert_eq!(
6056        editor_b2.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
6057        vec![2..3]
6058    );
6059    assert_eq!(
6060        editor_b1.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
6061        vec![0..1]
6062    );
6063
6064    // When client A activates a different editor, client B does so as well.
6065    workspace_a.update(cx_a, |workspace, cx| {
6066        workspace.activate_item(&editor_a1, cx)
6067    });
6068    deterministic.run_until_parked();
6069    workspace_b.read_with(cx_b, |workspace, cx| {
6070        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6071    });
6072
6073    // When client A opens a multibuffer, client B does so as well.
6074    let multibuffer_a = cx_a.add_model(|cx| {
6075        let buffer_a1 = project_a.update(cx, |project, cx| {
6076            project
6077                .get_open_buffer(&(worktree_id, "1.txt").into(), cx)
6078                .unwrap()
6079        });
6080        let buffer_a2 = project_a.update(cx, |project, cx| {
6081            project
6082                .get_open_buffer(&(worktree_id, "2.txt").into(), cx)
6083                .unwrap()
6084        });
6085        let mut result = MultiBuffer::new(0);
6086        result.push_excerpts(
6087            buffer_a1,
6088            [ExcerptRange {
6089                context: 0..3,
6090                primary: None,
6091            }],
6092            cx,
6093        );
6094        result.push_excerpts(
6095            buffer_a2,
6096            [ExcerptRange {
6097                context: 4..7,
6098                primary: None,
6099            }],
6100            cx,
6101        );
6102        result
6103    });
6104    let multibuffer_editor_a = workspace_a.update(cx_a, |workspace, cx| {
6105        let editor =
6106            cx.add_view(|cx| Editor::for_multibuffer(multibuffer_a, Some(project_a.clone()), cx));
6107        workspace.add_item(Box::new(editor.clone()), cx);
6108        editor
6109    });
6110    deterministic.run_until_parked();
6111    let multibuffer_editor_b = workspace_b.read_with(cx_b, |workspace, cx| {
6112        workspace
6113            .active_item(cx)
6114            .unwrap()
6115            .downcast::<Editor>()
6116            .unwrap()
6117    });
6118    assert_eq!(
6119        multibuffer_editor_a.read_with(cx_a, |editor, cx| editor.text(cx)),
6120        multibuffer_editor_b.read_with(cx_b, |editor, cx| editor.text(cx)),
6121    );
6122
6123    // When client A navigates back and forth, client B does so as well.
6124    workspace_a
6125        .update(cx_a, |workspace, cx| {
6126            workspace::Pane::go_back(workspace, None, cx)
6127        })
6128        .await;
6129    deterministic.run_until_parked();
6130    workspace_b.read_with(cx_b, |workspace, cx| {
6131        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6132    });
6133
6134    workspace_a
6135        .update(cx_a, |workspace, cx| {
6136            workspace::Pane::go_back(workspace, None, cx)
6137        })
6138        .await;
6139    deterministic.run_until_parked();
6140    workspace_b.read_with(cx_b, |workspace, cx| {
6141        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b2.id());
6142    });
6143
6144    workspace_a
6145        .update(cx_a, |workspace, cx| {
6146            workspace::Pane::go_forward(workspace, None, cx)
6147        })
6148        .await;
6149    deterministic.run_until_parked();
6150    workspace_b.read_with(cx_b, |workspace, cx| {
6151        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6152    });
6153
6154    // Changes to client A's editor are reflected on client B.
6155    editor_a1.update(cx_a, |editor, cx| {
6156        editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2]));
6157    });
6158    deterministic.run_until_parked();
6159    editor_b1.read_with(cx_b, |editor, cx| {
6160        assert_eq!(editor.selections.ranges(cx), &[1..1, 2..2]);
6161    });
6162
6163    editor_a1.update(cx_a, |editor, cx| editor.set_text("TWO", cx));
6164    deterministic.run_until_parked();
6165    editor_b1.read_with(cx_b, |editor, cx| assert_eq!(editor.text(cx), "TWO"));
6166
6167    editor_a1.update(cx_a, |editor, cx| {
6168        editor.change_selections(None, cx, |s| s.select_ranges([3..3]));
6169        editor.set_scroll_position(vec2f(0., 100.), cx);
6170    });
6171    deterministic.run_until_parked();
6172    editor_b1.read_with(cx_b, |editor, cx| {
6173        assert_eq!(editor.selections.ranges(cx), &[3..3]);
6174    });
6175
6176    // After unfollowing, client B stops receiving updates from client A.
6177    workspace_b.update(cx_b, |workspace, cx| {
6178        workspace.unfollow(&workspace.active_pane().clone(), cx)
6179    });
6180    workspace_a.update(cx_a, |workspace, cx| {
6181        workspace.activate_item(&editor_a2, cx)
6182    });
6183    deterministic.run_until_parked();
6184    assert_eq!(
6185        workspace_b.read_with(cx_b, |workspace, cx| workspace
6186            .active_item(cx)
6187            .unwrap()
6188            .id()),
6189        editor_b1.id()
6190    );
6191
6192    // Client A starts following client B.
6193    workspace_a
6194        .update(cx_a, |workspace, cx| {
6195            workspace
6196                .toggle_follow(&ToggleFollow(peer_id_b), cx)
6197                .unwrap()
6198        })
6199        .await
6200        .unwrap();
6201    assert_eq!(
6202        workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)),
6203        Some(peer_id_b)
6204    );
6205    assert_eq!(
6206        workspace_a.read_with(cx_a, |workspace, cx| workspace
6207            .active_item(cx)
6208            .unwrap()
6209            .id()),
6210        editor_a1.id()
6211    );
6212
6213    // Client B activates an external window, which causes a new screen-sharing item to be added to the pane.
6214    let display = MacOSDisplay::new();
6215    active_call_b
6216        .update(cx_b, |call, cx| call.set_location(None, cx))
6217        .await
6218        .unwrap();
6219    active_call_b
6220        .update(cx_b, |call, cx| {
6221            call.room().unwrap().update(cx, |room, cx| {
6222                room.set_display_sources(vec![display.clone()]);
6223                room.share_screen(cx)
6224            })
6225        })
6226        .await
6227        .unwrap();
6228    deterministic.run_until_parked();
6229    let shared_screen = workspace_a.read_with(cx_a, |workspace, cx| {
6230        workspace
6231            .active_item(cx)
6232            .unwrap()
6233            .downcast::<SharedScreen>()
6234            .unwrap()
6235    });
6236
6237    // Client B activates Zed again, which causes the previous editor to become focused again.
6238    active_call_b
6239        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6240        .await
6241        .unwrap();
6242    deterministic.run_until_parked();
6243    workspace_a.read_with(cx_a, |workspace, cx| {
6244        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_a1.id())
6245    });
6246
6247    // Client B activates a multibuffer that was created by following client A. Client A returns to that multibuffer.
6248    workspace_b.update(cx_b, |workspace, cx| {
6249        workspace.activate_item(&multibuffer_editor_b, cx)
6250    });
6251    deterministic.run_until_parked();
6252    workspace_a.read_with(cx_a, |workspace, cx| {
6253        assert_eq!(
6254            workspace.active_item(cx).unwrap().id(),
6255            multibuffer_editor_a.id()
6256        )
6257    });
6258
6259    // Client B activates an external window again, and the previously-opened screen-sharing item
6260    // gets activated.
6261    active_call_b
6262        .update(cx_b, |call, cx| call.set_location(None, cx))
6263        .await
6264        .unwrap();
6265    deterministic.run_until_parked();
6266    assert_eq!(
6267        workspace_a.read_with(cx_a, |workspace, cx| workspace
6268            .active_item(cx)
6269            .unwrap()
6270            .id()),
6271        shared_screen.id()
6272    );
6273
6274    // Following interrupts when client B disconnects.
6275    client_b.disconnect(&cx_b.to_async());
6276    deterministic.advance_clock(RECONNECT_TIMEOUT);
6277    assert_eq!(
6278        workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)),
6279        None
6280    );
6281}
6282
6283#[gpui::test(iterations = 10)]
6284async fn test_join_call_after_screen_was_shared(
6285    deterministic: Arc<Deterministic>,
6286    cx_a: &mut TestAppContext,
6287    cx_b: &mut TestAppContext,
6288) {
6289    deterministic.forbid_parking();
6290    let mut server = TestServer::start(&deterministic).await;
6291
6292    let client_a = server.create_client(cx_a, "user_a").await;
6293    let client_b = server.create_client(cx_b, "user_b").await;
6294    server
6295        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6296        .await;
6297
6298    let active_call_a = cx_a.read(ActiveCall::global);
6299    let active_call_b = cx_b.read(ActiveCall::global);
6300
6301    // Call users B and C from client A.
6302    active_call_a
6303        .update(cx_a, |call, cx| {
6304            call.invite(client_b.user_id().unwrap(), None, cx)
6305        })
6306        .await
6307        .unwrap();
6308    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
6309    deterministic.run_until_parked();
6310    assert_eq!(
6311        room_participants(&room_a, cx_a),
6312        RoomParticipants {
6313            remote: Default::default(),
6314            pending: vec!["user_b".to_string()]
6315        }
6316    );
6317
6318    // User B receives the call.
6319    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
6320    let call_b = incoming_call_b.next().await.unwrap().unwrap();
6321    assert_eq!(call_b.calling_user.github_login, "user_a");
6322
6323    // User A shares their screen
6324    let display = MacOSDisplay::new();
6325    active_call_a
6326        .update(cx_a, |call, cx| {
6327            call.room().unwrap().update(cx, |room, cx| {
6328                room.set_display_sources(vec![display.clone()]);
6329                room.share_screen(cx)
6330            })
6331        })
6332        .await
6333        .unwrap();
6334
6335    client_b.user_store.update(cx_b, |user_store, _| {
6336        user_store.clear_cache();
6337    });
6338
6339    // User B joins the room
6340    active_call_b
6341        .update(cx_b, |call, cx| call.accept_incoming(cx))
6342        .await
6343        .unwrap();
6344    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
6345    assert!(incoming_call_b.next().await.unwrap().is_none());
6346
6347    deterministic.run_until_parked();
6348    assert_eq!(
6349        room_participants(&room_a, cx_a),
6350        RoomParticipants {
6351            remote: vec!["user_b".to_string()],
6352            pending: vec![],
6353        }
6354    );
6355    assert_eq!(
6356        room_participants(&room_b, cx_b),
6357        RoomParticipants {
6358            remote: vec!["user_a".to_string()],
6359            pending: vec![],
6360        }
6361    );
6362
6363    // Ensure User B sees User A's screenshare.
6364    room_b.read_with(cx_b, |room, _| {
6365        assert_eq!(
6366            room.remote_participants()
6367                .get(&client_a.user_id().unwrap())
6368                .unwrap()
6369                .tracks
6370                .len(),
6371            1
6372        );
6373    });
6374}
6375
6376#[gpui::test]
6377async fn test_following_tab_order(
6378    deterministic: Arc<Deterministic>,
6379    cx_a: &mut TestAppContext,
6380    cx_b: &mut TestAppContext,
6381) {
6382    cx_a.update(editor::init);
6383    cx_b.update(editor::init);
6384
6385    let mut server = TestServer::start(&deterministic).await;
6386    let client_a = server.create_client(cx_a, "user_a").await;
6387    let client_b = server.create_client(cx_b, "user_b").await;
6388    server
6389        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6390        .await;
6391    let active_call_a = cx_a.read(ActiveCall::global);
6392    let active_call_b = cx_b.read(ActiveCall::global);
6393
6394    client_a
6395        .fs
6396        .insert_tree(
6397            "/a",
6398            json!({
6399                "1.txt": "one",
6400                "2.txt": "two",
6401                "3.txt": "three",
6402            }),
6403        )
6404        .await;
6405    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6406    active_call_a
6407        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6408        .await
6409        .unwrap();
6410
6411    let project_id = active_call_a
6412        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6413        .await
6414        .unwrap();
6415    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6416    active_call_b
6417        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6418        .await
6419        .unwrap();
6420
6421    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6422    let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
6423
6424    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6425    let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
6426
6427    let client_b_id = project_a.read_with(cx_a, |project, _| {
6428        project.collaborators().values().next().unwrap().peer_id
6429    });
6430
6431    //Open 1, 3 in that order on client A
6432    workspace_a
6433        .update(cx_a, |workspace, cx| {
6434            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6435        })
6436        .await
6437        .unwrap();
6438    workspace_a
6439        .update(cx_a, |workspace, cx| {
6440            workspace.open_path((worktree_id, "3.txt"), None, true, cx)
6441        })
6442        .await
6443        .unwrap();
6444
6445    let pane_paths = |pane: &ViewHandle<workspace::Pane>, cx: &mut TestAppContext| {
6446        pane.update(cx, |pane, cx| {
6447            pane.items()
6448                .map(|item| {
6449                    item.project_path(cx)
6450                        .unwrap()
6451                        .path
6452                        .to_str()
6453                        .unwrap()
6454                        .to_owned()
6455                })
6456                .collect::<Vec<_>>()
6457        })
6458    };
6459
6460    //Verify that the tabs opened in the order we expect
6461    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt"]);
6462
6463    //Follow client B as client A
6464    workspace_a
6465        .update(cx_a, |workspace, cx| {
6466            workspace
6467                .toggle_follow(&ToggleFollow(client_b_id), cx)
6468                .unwrap()
6469        })
6470        .await
6471        .unwrap();
6472
6473    //Open just 2 on client B
6474    workspace_b
6475        .update(cx_b, |workspace, cx| {
6476            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
6477        })
6478        .await
6479        .unwrap();
6480    deterministic.run_until_parked();
6481
6482    // Verify that newly opened followed file is at the end
6483    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]);
6484
6485    //Open just 1 on client B
6486    workspace_b
6487        .update(cx_b, |workspace, cx| {
6488            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6489        })
6490        .await
6491        .unwrap();
6492    assert_eq!(&pane_paths(&pane_b, cx_b), &["2.txt", "1.txt"]);
6493    deterministic.run_until_parked();
6494
6495    // Verify that following into 1 did not reorder
6496    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]);
6497}
6498
6499#[gpui::test(iterations = 10)]
6500async fn test_peers_following_each_other(
6501    deterministic: Arc<Deterministic>,
6502    cx_a: &mut TestAppContext,
6503    cx_b: &mut TestAppContext,
6504) {
6505    deterministic.forbid_parking();
6506    cx_a.update(editor::init);
6507    cx_b.update(editor::init);
6508
6509    let mut server = TestServer::start(&deterministic).await;
6510    let client_a = server.create_client(cx_a, "user_a").await;
6511    let client_b = server.create_client(cx_b, "user_b").await;
6512    server
6513        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6514        .await;
6515    let active_call_a = cx_a.read(ActiveCall::global);
6516    let active_call_b = cx_b.read(ActiveCall::global);
6517
6518    // Client A shares a project.
6519    client_a
6520        .fs
6521        .insert_tree(
6522            "/a",
6523            json!({
6524                "1.txt": "one",
6525                "2.txt": "two",
6526                "3.txt": "three",
6527                "4.txt": "four",
6528            }),
6529        )
6530        .await;
6531    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6532    active_call_a
6533        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6534        .await
6535        .unwrap();
6536    let project_id = active_call_a
6537        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6538        .await
6539        .unwrap();
6540
6541    // Client B joins the project.
6542    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6543    active_call_b
6544        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6545        .await
6546        .unwrap();
6547
6548    // Client A opens some editors.
6549    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6550    let pane_a1 = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
6551    let _editor_a1 = workspace_a
6552        .update(cx_a, |workspace, cx| {
6553            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6554        })
6555        .await
6556        .unwrap()
6557        .downcast::<Editor>()
6558        .unwrap();
6559
6560    // Client B opens an editor.
6561    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6562    let pane_b1 = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
6563    let _editor_b1 = workspace_b
6564        .update(cx_b, |workspace, cx| {
6565            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
6566        })
6567        .await
6568        .unwrap()
6569        .downcast::<Editor>()
6570        .unwrap();
6571
6572    // Clients A and B follow each other in split panes
6573    workspace_a.update(cx_a, |workspace, cx| {
6574        workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
6575        let pane_a1 = pane_a1.clone();
6576        cx.defer(move |workspace, _| {
6577            assert_ne!(*workspace.active_pane(), pane_a1);
6578        });
6579    });
6580    workspace_a
6581        .update(cx_a, |workspace, cx| {
6582            let leader_id = *project_a.read(cx).collaborators().keys().next().unwrap();
6583            workspace
6584                .toggle_follow(&workspace::ToggleFollow(leader_id), cx)
6585                .unwrap()
6586        })
6587        .await
6588        .unwrap();
6589    workspace_b.update(cx_b, |workspace, cx| {
6590        workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
6591        let pane_b1 = pane_b1.clone();
6592        cx.defer(move |workspace, _| {
6593            assert_ne!(*workspace.active_pane(), pane_b1);
6594        });
6595    });
6596    workspace_b
6597        .update(cx_b, |workspace, cx| {
6598            let leader_id = *project_b.read(cx).collaborators().keys().next().unwrap();
6599            workspace
6600                .toggle_follow(&workspace::ToggleFollow(leader_id), cx)
6601                .unwrap()
6602        })
6603        .await
6604        .unwrap();
6605
6606    workspace_a.update(cx_a, |workspace, cx| {
6607        workspace.activate_next_pane(cx);
6608    });
6609    // Wait for focus effects to be fully flushed
6610    workspace_a.update(cx_a, |workspace, _| {
6611        assert_eq!(*workspace.active_pane(), pane_a1);
6612    });
6613
6614    workspace_a
6615        .update(cx_a, |workspace, cx| {
6616            workspace.open_path((worktree_id, "3.txt"), None, true, cx)
6617        })
6618        .await
6619        .unwrap();
6620    workspace_b.update(cx_b, |workspace, cx| {
6621        workspace.activate_next_pane(cx);
6622    });
6623
6624    workspace_b
6625        .update(cx_b, |workspace, cx| {
6626            assert_eq!(*workspace.active_pane(), pane_b1);
6627            workspace.open_path((worktree_id, "4.txt"), None, true, cx)
6628        })
6629        .await
6630        .unwrap();
6631    cx_a.foreground().run_until_parked();
6632
6633    // Ensure leader updates don't change the active pane of followers
6634    workspace_a.read_with(cx_a, |workspace, _| {
6635        assert_eq!(*workspace.active_pane(), pane_a1);
6636    });
6637    workspace_b.read_with(cx_b, |workspace, _| {
6638        assert_eq!(*workspace.active_pane(), pane_b1);
6639    });
6640
6641    // Ensure peers following each other doesn't cause an infinite loop.
6642    assert_eq!(
6643        workspace_a.read_with(cx_a, |workspace, cx| workspace
6644            .active_item(cx)
6645            .unwrap()
6646            .project_path(cx)),
6647        Some((worktree_id, "3.txt").into())
6648    );
6649    workspace_a.update(cx_a, |workspace, cx| {
6650        assert_eq!(
6651            workspace.active_item(cx).unwrap().project_path(cx),
6652            Some((worktree_id, "3.txt").into())
6653        );
6654        workspace.activate_next_pane(cx);
6655    });
6656
6657    workspace_a.update(cx_a, |workspace, cx| {
6658        assert_eq!(
6659            workspace.active_item(cx).unwrap().project_path(cx),
6660            Some((worktree_id, "4.txt").into())
6661        );
6662    });
6663
6664    workspace_b.update(cx_b, |workspace, cx| {
6665        assert_eq!(
6666            workspace.active_item(cx).unwrap().project_path(cx),
6667            Some((worktree_id, "4.txt").into())
6668        );
6669        workspace.activate_next_pane(cx);
6670    });
6671
6672    workspace_b.update(cx_b, |workspace, cx| {
6673        assert_eq!(
6674            workspace.active_item(cx).unwrap().project_path(cx),
6675            Some((worktree_id, "3.txt").into())
6676        );
6677    });
6678}
6679
6680#[gpui::test(iterations = 10)]
6681async fn test_auto_unfollowing(
6682    deterministic: Arc<Deterministic>,
6683    cx_a: &mut TestAppContext,
6684    cx_b: &mut TestAppContext,
6685) {
6686    deterministic.forbid_parking();
6687    cx_a.update(editor::init);
6688    cx_b.update(editor::init);
6689
6690    // 2 clients connect to a server.
6691    let mut server = TestServer::start(&deterministic).await;
6692    let client_a = server.create_client(cx_a, "user_a").await;
6693    let client_b = server.create_client(cx_b, "user_b").await;
6694    server
6695        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6696        .await;
6697    let active_call_a = cx_a.read(ActiveCall::global);
6698    let active_call_b = cx_b.read(ActiveCall::global);
6699
6700    // Client A shares a project.
6701    client_a
6702        .fs
6703        .insert_tree(
6704            "/a",
6705            json!({
6706                "1.txt": "one",
6707                "2.txt": "two",
6708                "3.txt": "three",
6709            }),
6710        )
6711        .await;
6712    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6713    active_call_a
6714        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6715        .await
6716        .unwrap();
6717
6718    let project_id = active_call_a
6719        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6720        .await
6721        .unwrap();
6722    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6723    active_call_b
6724        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6725        .await
6726        .unwrap();
6727
6728    // Client A opens some editors.
6729    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6730    let _editor_a1 = workspace_a
6731        .update(cx_a, |workspace, cx| {
6732            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6733        })
6734        .await
6735        .unwrap()
6736        .downcast::<Editor>()
6737        .unwrap();
6738
6739    // Client B starts following client A.
6740    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6741    let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
6742    let leader_id = project_b.read_with(cx_b, |project, _| {
6743        project.collaborators().values().next().unwrap().peer_id
6744    });
6745    workspace_b
6746        .update(cx_b, |workspace, cx| {
6747            workspace
6748                .toggle_follow(&ToggleFollow(leader_id), cx)
6749                .unwrap()
6750        })
6751        .await
6752        .unwrap();
6753    assert_eq!(
6754        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6755        Some(leader_id)
6756    );
6757    let editor_b2 = workspace_b.read_with(cx_b, |workspace, cx| {
6758        workspace
6759            .active_item(cx)
6760            .unwrap()
6761            .downcast::<Editor>()
6762            .unwrap()
6763    });
6764
6765    // When client B moves, it automatically stops following client A.
6766    editor_b2.update(cx_b, |editor, cx| editor.move_right(&editor::MoveRight, cx));
6767    assert_eq!(
6768        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6769        None
6770    );
6771
6772    workspace_b
6773        .update(cx_b, |workspace, cx| {
6774            workspace
6775                .toggle_follow(&ToggleFollow(leader_id), cx)
6776                .unwrap()
6777        })
6778        .await
6779        .unwrap();
6780    assert_eq!(
6781        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6782        Some(leader_id)
6783    );
6784
6785    // When client B edits, it automatically stops following client A.
6786    editor_b2.update(cx_b, |editor, cx| editor.insert("X", cx));
6787    assert_eq!(
6788        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6789        None
6790    );
6791
6792    workspace_b
6793        .update(cx_b, |workspace, cx| {
6794            workspace
6795                .toggle_follow(&ToggleFollow(leader_id), cx)
6796                .unwrap()
6797        })
6798        .await
6799        .unwrap();
6800    assert_eq!(
6801        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6802        Some(leader_id)
6803    );
6804
6805    // When client B scrolls, it automatically stops following client A.
6806    editor_b2.update(cx_b, |editor, cx| {
6807        editor.set_scroll_position(vec2f(0., 3.), cx)
6808    });
6809    assert_eq!(
6810        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6811        None
6812    );
6813
6814    workspace_b
6815        .update(cx_b, |workspace, cx| {
6816            workspace
6817                .toggle_follow(&ToggleFollow(leader_id), cx)
6818                .unwrap()
6819        })
6820        .await
6821        .unwrap();
6822    assert_eq!(
6823        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6824        Some(leader_id)
6825    );
6826
6827    // When client B activates a different pane, it continues following client A in the original pane.
6828    workspace_b.update(cx_b, |workspace, cx| {
6829        workspace.split_pane(pane_b.clone(), SplitDirection::Right, cx)
6830    });
6831    assert_eq!(
6832        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6833        Some(leader_id)
6834    );
6835
6836    workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx));
6837    assert_eq!(
6838        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6839        Some(leader_id)
6840    );
6841
6842    // When client B activates a different item in the original pane, it automatically stops following client A.
6843    workspace_b
6844        .update(cx_b, |workspace, cx| {
6845            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
6846        })
6847        .await
6848        .unwrap();
6849    assert_eq!(
6850        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
6851        None
6852    );
6853}
6854
6855#[gpui::test(iterations = 10)]
6856async fn test_peers_simultaneously_following_each_other(
6857    deterministic: Arc<Deterministic>,
6858    cx_a: &mut TestAppContext,
6859    cx_b: &mut TestAppContext,
6860) {
6861    deterministic.forbid_parking();
6862    cx_a.update(editor::init);
6863    cx_b.update(editor::init);
6864
6865    let mut server = TestServer::start(&deterministic).await;
6866    let client_a = server.create_client(cx_a, "user_a").await;
6867    let client_b = server.create_client(cx_b, "user_b").await;
6868    server
6869        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6870        .await;
6871    let active_call_a = cx_a.read(ActiveCall::global);
6872
6873    client_a.fs.insert_tree("/a", json!({})).await;
6874    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
6875    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6876    let project_id = active_call_a
6877        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6878        .await
6879        .unwrap();
6880
6881    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6882    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6883
6884    deterministic.run_until_parked();
6885    let client_a_id = project_b.read_with(cx_b, |project, _| {
6886        project.collaborators().values().next().unwrap().peer_id
6887    });
6888    let client_b_id = project_a.read_with(cx_a, |project, _| {
6889        project.collaborators().values().next().unwrap().peer_id
6890    });
6891
6892    let a_follow_b = workspace_a.update(cx_a, |workspace, cx| {
6893        workspace
6894            .toggle_follow(&ToggleFollow(client_b_id), cx)
6895            .unwrap()
6896    });
6897    let b_follow_a = workspace_b.update(cx_b, |workspace, cx| {
6898        workspace
6899            .toggle_follow(&ToggleFollow(client_a_id), cx)
6900            .unwrap()
6901    });
6902
6903    futures::try_join!(a_follow_b, b_follow_a).unwrap();
6904    workspace_a.read_with(cx_a, |workspace, _| {
6905        assert_eq!(
6906            workspace.leader_for_pane(workspace.active_pane()),
6907            Some(client_b_id)
6908        );
6909    });
6910    workspace_b.read_with(cx_b, |workspace, _| {
6911        assert_eq!(
6912            workspace.leader_for_pane(workspace.active_pane()),
6913            Some(client_a_id)
6914        );
6915    });
6916}
6917
6918#[derive(Debug, Eq, PartialEq)]
6919struct RoomParticipants {
6920    remote: Vec<String>,
6921    pending: Vec<String>,
6922}
6923
6924fn room_participants(room: &ModelHandle<Room>, cx: &mut TestAppContext) -> RoomParticipants {
6925    room.read_with(cx, |room, _| {
6926        let mut remote = room
6927            .remote_participants()
6928            .iter()
6929            .map(|(_, participant)| participant.user.github_login.clone())
6930            .collect::<Vec<_>>();
6931        let mut pending = room
6932            .pending_participants()
6933            .iter()
6934            .map(|user| user.github_login.clone())
6935            .collect::<Vec<_>>();
6936        remote.sort();
6937        pending.sort();
6938        RoomParticipants { remote, pending }
6939    })
6940}