Fix notes unread status (#7643)

1. The client-side comparison was wrong
2. The server never told the client about the version it remembered
3. The server generated broken timestamps in some cases

Release Notes:

- Fixed the notes/chat appearing as unread too often

**or**

- N/A
This commit is contained in:
Conrad Irwin 2024-02-09 23:12:26 -07:00 committed by GitHub
parent e2a3e89318
commit 68893c2ae6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 157 additions and 120 deletions

View file

@ -1,6 +1,6 @@
use crate::{
rpc::{CLEANUP_TIMEOUT, RECONNECT_TIMEOUT},
tests::TestServer,
tests::{test_server::open_channel_notes, TestServer},
};
use call::ActiveCall;
use channel::ACKNOWLEDGE_DEBOUNCE_INTERVAL;
@ -605,113 +605,75 @@ async fn test_channel_buffer_changes(
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
) {
let mut server = TestServer::start(deterministic.clone()).await;
let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await;
let (server, client_a, client_b, channel_id) = TestServer::start2(cx_a, cx_b).await;
let (_, cx_a) = client_a.build_test_workspace(cx_a).await;
let (workspace_b, cx_b) = client_b.build_test_workspace(cx_b).await;
let channel_store_b = client_b.channel_store().clone();
let channel_id = server
.make_channel(
"the-channel",
None,
(&client_a, cx_a),
&mut [(&client_b, cx_b)],
)
.await;
let channel_buffer_a = client_a
.channel_store()
.update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
.await
.unwrap();
// Client A makes an edit, and client B should see that the note has changed.
channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "1")], None, cx);
})
// Editing the channel notes should set them to dirty
open_channel_notes(channel_id, cx_a).await.unwrap();
cx_a.simulate_keystrokes("1");
channel_store_b.read_with(cx_b, |channel_store, _| {
assert!(channel_store.has_channel_buffer_changed(channel_id))
});
deterministic.run_until_parked();
let has_buffer_changed = cx_b.update(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
});
assert!(has_buffer_changed);
// Opening the buffer should clear the changed flag.
let project_b = client_b.build_empty_local_project(cx_b);
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
let channel_view_b = cx_b
.update(|cx| ChannelView::open(channel_id, None, workspace_b.clone(), cx))
.await
.unwrap();
deterministic.run_until_parked();
let has_buffer_changed = cx_b.update(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
open_channel_notes(channel_id, cx_b).await.unwrap();
channel_store_b.read_with(cx_b, |channel_store, _| {
assert!(!channel_store.has_channel_buffer_changed(channel_id))
});
assert!(!has_buffer_changed);
// Editing the channel while the buffer is open should not show that the buffer has changed.
channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "2")], None, cx);
})
cx_a.simulate_keystrokes("2");
channel_store_b.read_with(cx_b, |channel_store, _| {
assert!(!channel_store.has_channel_buffer_changed(channel_id))
});
deterministic.run_until_parked();
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
});
assert!(!has_buffer_changed);
deterministic.advance_clock(ACKNOWLEDGE_DEBOUNCE_INTERVAL);
// Test that the server is tracking things correctly, and we retain our 'not changed'
// state across a disconnect
deterministic.advance_clock(ACKNOWLEDGE_DEBOUNCE_INTERVAL);
server
.simulate_long_connection_interruption(client_b.peer_id().unwrap(), deterministic.clone());
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
channel_store_b.read_with(cx_b, |channel_store, _| {
assert!(!channel_store.has_channel_buffer_changed(channel_id))
});
assert!(!has_buffer_changed);
// Closing the buffer should re-enable change tracking
cx_b.update(|cx| {
workspace_b.update(cx, |workspace, cx| {
workspace.close_all_items_and_panes(&Default::default(), cx)
});
drop(channel_view_b)
});
deterministic.run_until_parked();
channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "3")], None, cx);
})
});
deterministic.run_until_parked();
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
cx_a.simulate_keystrokes("3");
channel_store_b.read_with(cx_b, |channel_store, _| {
assert!(channel_store.has_channel_buffer_changed(channel_id))
});
}
#[gpui::test]
async fn test_channel_buffer_changes_persist(
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
cx_b2: &mut TestAppContext,
) {
let (mut server, client_a, client_b, channel_id) = TestServer::start2(cx_a, cx_b).await;
let (_, cx_a) = client_a.build_test_workspace(cx_a).await;
let (_, cx_b) = client_b.build_test_workspace(cx_b).await;
// a) edits the notes
open_channel_notes(channel_id, cx_a).await.unwrap();
cx_a.simulate_keystrokes("1");
// b) opens them to observe the current version
open_channel_notes(channel_id, cx_b).await.unwrap();
// On boot the client should get the correct state.
let client_b2 = server.create_client(cx_b2, "user_b").await;
let channel_store_b2 = client_b2.channel_store().clone();
channel_store_b2.read_with(cx_b2, |channel_store, _| {
assert!(!channel_store.has_channel_buffer_changed(channel_id))
});
assert!(has_buffer_changed);
}
#[track_caller]

View file

@ -10,6 +10,7 @@ use channel::{ChannelBuffer, ChannelStore};
use client::{
self, proto::PeerId, Client, Connection, Credentials, EstablishConnectionError, UserStore,
};
use collab_ui::channel_view::ChannelView;
use collections::{HashMap, HashSet};
use fs::FakeFs;
use futures::{channel::oneshot, StreamExt as _};
@ -766,6 +767,16 @@ pub fn join_channel_call(cx: &mut TestAppContext) -> Task<anyhow::Result<()>> {
room.unwrap().update(cx, |room, cx| room.join_call(cx))
}
pub fn open_channel_notes(
channel_id: u64,
cx: &mut VisualTestContext,
) -> Task<anyhow::Result<View<ChannelView>>> {
let window = cx.update(|cx| cx.active_window().unwrap().downcast::<Workspace>().unwrap());
let view = window.root_view(cx).unwrap();
cx.update(|cx| ChannelView::open(channel_id, None, view.clone(), cx))
}
impl Drop for TestClient {
fn drop(&mut self) {
self.app_state.client.teardown();