integration_tests.rs

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