Introduce randomized test for collaboration on buffers

This test will exercise serialization of operations as well as peers
replicating from an existing buffer.
This commit is contained in:
Antonio Scandurra 2022-01-05 11:51:41 +01:00
parent 7bc8eb4f3d
commit d383ff30ce
8 changed files with 264 additions and 85 deletions

View file

@ -24,6 +24,7 @@ smallvec = { version = "1.6", features = ["union"] }
[dev-dependencies]
collections = { path = "../collections", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.8"
rand = "0.8.3"

View file

@ -7,6 +7,7 @@ use std::{
iter::Iterator,
time::{Duration, Instant},
};
use util::test::Network;
#[cfg(test)]
#[ctor::ctor]
@ -602,18 +603,6 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
}
}
#[derive(Clone)]
struct Envelope<T: Clone> {
message: T,
sender: ReplicaId,
}
struct Network<T: Clone, R: rand::Rng> {
inboxes: std::collections::BTreeMap<ReplicaId, Vec<Envelope<T>>>,
all_messages: Vec<T>,
rng: R,
}
impl Buffer {
fn check_invariants(&self) {
// Ensure every fragment is ordered by locator in the fragment tree and corresponds
@ -646,69 +635,3 @@ impl Buffer {
}
}
}
impl<T: Clone, R: rand::Rng> Network<T, R> {
fn new(rng: R) -> Self {
Network {
inboxes: Default::default(),
all_messages: Vec::new(),
rng,
}
}
fn add_peer(&mut self, id: ReplicaId) {
self.inboxes.insert(id, Vec::new());
}
fn is_idle(&self) -> bool {
self.inboxes.values().all(|i| i.is_empty())
}
fn broadcast(&mut self, sender: ReplicaId, messages: Vec<T>) {
for (replica, inbox) in self.inboxes.iter_mut() {
if *replica != sender {
for message in &messages {
let min_index = inbox
.iter()
.enumerate()
.rev()
.find_map(|(index, envelope)| {
if sender == envelope.sender {
Some(index + 1)
} else {
None
}
})
.unwrap_or(0);
// Insert one or more duplicates of this message *after* the previous
// message delivered by this replica.
for _ in 0..self.rng.gen_range(1..4) {
let insertion_index = self.rng.gen_range(min_index..inbox.len() + 1);
inbox.insert(
insertion_index,
Envelope {
message: message.clone(),
sender,
},
);
}
}
}
}
self.all_messages.extend(messages);
}
fn has_unreceived(&self, receiver: ReplicaId) -> bool {
!self.inboxes[&receiver].is_empty()
}
fn receive(&mut self, receiver: ReplicaId) -> Vec<T> {
let inbox = self.inboxes.get_mut(&receiver).unwrap();
let count = self.rng.gen_range(0..inbox.len() + 1);
inbox
.drain(0..count)
.map(|envelope| envelope.message)
.collect()
}
}

View file

@ -1105,7 +1105,6 @@ impl Buffer {
self.deferred_replicas.clear();
let mut deferred_ops = Vec::new();
for op in self.deferred_ops.drain().iter().cloned() {
dbg!(&self.version, &op, self.can_apply_op(&op));
if self.can_apply_op(&op) {
self.apply_op(op)?;
} else {
@ -1241,7 +1240,15 @@ impl Buffer {
#[cfg(any(test, feature = "test-support"))]
impl Buffer {
fn random_byte_range(&mut self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
pub fn set_group_interval(&mut self, group_interval: Duration) {
self.history.group_interval = group_interval;
}
pub fn random_byte_range(
&mut self,
start_offset: usize,
rng: &mut impl rand::Rng,
) -> Range<usize> {
let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
start..end