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