integration_tests.rs

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