In random collaboration test, add failing assertion for worktree convergence

This commit is contained in:
Max Brunsfeld 2022-02-15 14:55:38 -08:00
parent a11495af19
commit 34bba303dc
5 changed files with 88 additions and 15 deletions

View File

@ -1,6 +1,6 @@
use std::iter::FromIterator;
#[derive(Copy, Clone, Debug, Default)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct CharBag(u64);
impl CharBag {

View File

@ -370,6 +370,13 @@ impl Foreground {
*any_value.downcast().unwrap()
}
pub fn run_until_parked(&self) {
match self {
Self::Deterministic { executor, .. } => executor.run_until_parked(),
_ => panic!("this method can only be called on a deterministic executor"),
}
}
pub fn parking_forbidden(&self) -> bool {
match self {
Self::Deterministic { executor, .. } => executor.state.lock().forbid_parking,

View File

@ -87,7 +87,7 @@ pub struct RemoteWorktree {
pending_updates: VecDeque<proto::UpdateWorktree>,
}
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
pub struct Snapshot {
id: WorktreeId,
root_name: String,
@ -1315,13 +1315,29 @@ impl fmt::Debug for LocalWorktree {
impl fmt::Debug for Snapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for entry in self.entries_by_path.cursor::<()>() {
for _ in entry.path.ancestors().skip(1) {
write!(f, " ")?;
struct EntriesById<'a>(&'a SumTree<PathEntry>);
struct EntriesByPath<'a>(&'a SumTree<Entry>);
impl<'a> fmt::Debug for EntriesByPath<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.0.iter().map(|entry| (&entry.path, entry.id)))
.finish()
}
writeln!(f, "{:?} (inode: {})", entry.path, entry.inode)?;
}
Ok(())
impl<'a> fmt::Debug for EntriesById<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter()).finish()
}
}
f.debug_struct("Snapshot")
.field("id", &self.id)
.field("root_name", &self.root_name)
.field("entries_by_path", &EntriesByPath(&self.entries_by_path))
.field("entries_by_id", &EntriesById(&self.entries_by_id))
.finish()
}
}
@ -1528,7 +1544,7 @@ impl File {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Entry {
pub id: usize,
pub kind: EntryKind,
@ -1539,7 +1555,7 @@ pub struct Entry {
pub is_ignored: bool,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EntryKind {
PendingDir,
Dir,
@ -1642,7 +1658,7 @@ impl sum_tree::Summary for EntrySummary {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
struct PathEntry {
id: usize,
path: Arc<Path>,

View File

@ -1085,6 +1085,7 @@ mod tests {
github, AppState, Config,
};
use ::rpc::Peer;
use collections::BTreeMap;
use gpui::{executor, ModelHandle, TestAppContext};
use parking_lot::Mutex;
use postage::{mpsc, watch};
@ -3597,11 +3598,11 @@ mod tests {
.unwrap();
clients.push(cx.foreground().spawn(host.simulate_host(
host_project,
host_project.clone(),
operations.clone(),
max_operations,
rng.clone(),
host_cx,
host_cx.clone(),
)));
while operations.get() < max_operations {
@ -3647,10 +3648,51 @@ mod tests {
}
let clients = futures::future::join_all(clients).await;
cx.foreground().run_until_parked();
let host_worktree_snapshots = host_project.read_with(&host_cx, |project, cx| {
project
.worktrees(cx)
.map(|worktree| {
let snapshot = worktree.read(cx).snapshot();
(snapshot.id(), snapshot)
})
.collect::<BTreeMap<_, _>>()
});
for (ix, (client_a, cx_a)) in clients.iter().enumerate() {
for buffer_a in &client_a.buffers {
let buffer_id = buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
for (client_b, cx_b) in &clients[ix + 1..] {
let worktree_snapshots =
client_a
.project
.as_ref()
.unwrap()
.read_with(cx_a, |project, cx| {
project
.worktrees(cx)
.map(|worktree| {
let snapshot = worktree.read(cx).snapshot();
(snapshot.id(), snapshot)
})
.collect::<BTreeMap<_, _>>()
});
assert_eq!(
worktree_snapshots.keys().collect::<Vec<_>>(),
host_worktree_snapshots.keys().collect::<Vec<_>>(),
"guest {} has different worktrees than the host",
ix
);
for (id, snapshot) in &host_worktree_snapshots {
assert_eq!(
worktree_snapshots[id], *snapshot,
"guest {} has different snapshot than the host for worktree {}",
ix, id
);
}
for (client_b, cx_b) in &clients[ix + 1..] {
for buffer_a in &client_a.buffers {
let buffer_id = buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
if let Some(buffer_b) = client_b.buffers.iter().find(|buffer| {
buffer.read_with(cx_b, |buffer, _| buffer.remote_id() == buffer_id)
}) {

View File

@ -478,6 +478,14 @@ impl<T: Item> SumTree<T> {
}
}
impl<T: Item + PartialEq> PartialEq for SumTree<T> {
fn eq(&self, other: &Self) -> bool {
self.iter().eq(other.iter())
}
}
impl<T: Item + Eq> Eq for SumTree<T> {}
impl<T: KeyedItem> SumTree<T> {
pub fn insert_or_replace(&mut self, item: T, cx: &<T::Summary as Summary>::Context) -> bool {
let mut replaced = false;