integration_tests.rs

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