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