channel_buffer_tests.rs

  1use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
  2
  3use client::UserId;
  4use gpui::{executor::Deterministic, ModelHandle, TestAppContext};
  5use rpc::{proto, RECEIVE_TIMEOUT};
  6use std::sync::Arc;
  7
  8#[gpui::test]
  9async fn test_core_channel_buffers(
 10    deterministic: Arc<Deterministic>,
 11    cx_a: &mut TestAppContext,
 12    cx_b: &mut TestAppContext,
 13) {
 14    deterministic.forbid_parking();
 15    let mut server = TestServer::start(&deterministic).await;
 16    let client_a = server.create_client(cx_a, "user_a").await;
 17    let client_b = server.create_client(cx_b, "user_b").await;
 18
 19    let zed_id = server
 20        .make_channel("zed", (&client_a, cx_a), &mut [(&client_b, cx_b)])
 21        .await;
 22
 23    // Client A joins the channel buffer
 24    let channel_buffer_a = client_a
 25        .channel_store()
 26        .update(cx_a, |channel, cx| channel.open_channel_buffer(zed_id, cx))
 27        .await
 28        .unwrap();
 29
 30    // Client A edits the buffer
 31    let buffer_a = channel_buffer_a.read_with(cx_a, |buffer, _| buffer.buffer());
 32
 33    buffer_a.update(cx_a, |buffer, cx| {
 34        buffer.edit([(0..0, "hello world")], None, cx)
 35    });
 36    buffer_a.update(cx_a, |buffer, cx| {
 37        buffer.edit([(5..5, ", cruel")], None, cx)
 38    });
 39    buffer_a.update(cx_a, |buffer, cx| {
 40        buffer.edit([(0..5, "goodbye")], None, cx)
 41    });
 42    buffer_a.update(cx_a, |buffer, cx| buffer.undo(cx));
 43    deterministic.run_until_parked();
 44
 45    assert_eq!(buffer_text(&buffer_a, cx_a), "hello, cruel world");
 46
 47    // Client B joins the channel buffer
 48    let channel_buffer_b = client_b
 49        .channel_store()
 50        .update(cx_b, |channel, cx| channel.open_channel_buffer(zed_id, cx))
 51        .await
 52        .unwrap();
 53
 54    channel_buffer_b.read_with(cx_b, |buffer, _| {
 55        assert_collaborators(
 56            buffer.collaborators(),
 57            &[client_a.user_id(), client_b.user_id()],
 58        );
 59    });
 60
 61    // Client B sees the correct text, and then edits it
 62    let buffer_b = channel_buffer_b.read_with(cx_b, |buffer, _| buffer.buffer());
 63    assert_eq!(buffer_text(&buffer_b, cx_b), "hello, cruel world");
 64    buffer_b.update(cx_b, |buffer, cx| {
 65        buffer.edit([(7..12, "beautiful")], None, cx)
 66    });
 67
 68    // Both A and B see the new edit
 69    deterministic.run_until_parked();
 70    assert_eq!(buffer_text(&buffer_a, cx_a), "hello, beautiful world");
 71    assert_eq!(buffer_text(&buffer_b, cx_b), "hello, beautiful world");
 72
 73    // Client A closes the channel buffer.
 74    cx_a.update(|_| drop(channel_buffer_a));
 75    deterministic.run_until_parked();
 76
 77    // Client B sees that client A is gone from the channel buffer.
 78    channel_buffer_b.read_with(cx_b, |buffer, _| {
 79        assert_collaborators(&buffer.collaborators(), &[client_b.user_id()]);
 80    });
 81
 82    // Client A rejoins the channel buffer
 83    let _channel_buffer_a = client_a
 84        .channel_store()
 85        .update(cx_a, |channels, cx| channels.open_channel_buffer(zed_id, cx))
 86        .await
 87        .unwrap();
 88    deterministic.run_until_parked();
 89
 90    // Sanity test, make sure we saw A rejoining
 91    channel_buffer_b.read_with(cx_b, |buffer, _| {
 92        assert_collaborators(
 93            &buffer.collaborators(),
 94            &[client_b.user_id(), client_a.user_id()],
 95        );
 96    });
 97
 98    // Client A loses connection.
 99    server.forbid_connections();
100    server.disconnect_client(client_a.peer_id().unwrap());
101    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
102
103    // Client B observes A disconnect
104    channel_buffer_b.read_with(cx_b, |buffer, _| {
105        assert_collaborators(&buffer.collaborators(), &[client_b.user_id()]);
106    });
107
108    // TODO:
109    // - Test synchronizing offline updates, what happens to A's channel buffer when A disconnects
110    // - Test interaction with channel deletion while buffer is open
111}
112
113#[track_caller]
114fn assert_collaborators(collaborators: &[proto::Collaborator], ids: &[Option<UserId>]) {
115    assert_eq!(
116        collaborators
117            .into_iter()
118            .map(|collaborator| collaborator.user_id)
119            .collect::<Vec<_>>(),
120        ids.into_iter().map(|id| id.unwrap()).collect::<Vec<_>>()
121    );
122}
123
124fn buffer_text(channel_buffer: &ModelHandle<language::Buffer>, cx: &mut TestAppContext) -> String {
125    channel_buffer.read_with(cx, |buffer, _| buffer.text())
126}