add proptest for action sequences

This commit is contained in:
Dustin J. Mitchell 2020-01-01 17:45:43 -05:00
parent 04f6b1d421
commit f6ffcc7039
2 changed files with 70 additions and 2 deletions

View file

@ -5,11 +5,10 @@
- annotations: `annotation.<epoch time> = "annotation"`
- tags: `tags.<tag> = ""`
* add HTTP API
* abstract server, storage, etc. into traits
* implement snapshot requests
* implement backups
* implement client-side encryption
* design expiration
- need to be sure that create / delete operations don't get reversed
* cli tools
* prop testing for DB modifications
- generate a non-failing sequence of operations with syncs interspersed

View file

@ -0,0 +1,69 @@
use chrono::Utc;
use ot::{Operation, Server, DB};
use proptest::prelude::*;
use uuid::Uuid;
#[derive(Debug)]
enum Action {
Op(Operation),
Sync,
}
fn action_sequence_strategy() -> impl Strategy<Value = Vec<(Action, u8)>> {
// Create, Update, Delete, or Sync on client 1, 2, .., followed by a round of syncs
"([CUDS][123])*S1S2S3S1S2".prop_map(|seq| {
let uuid = Uuid::parse_str("83a2f9ef-f455-4195-b92e-a54c161eebfc").unwrap();
seq.as_bytes()
.chunks(2)
.map(|action_on| {
let action = match action_on[0] {
b'C' => Action::Op(Operation::Create { uuid }),
b'U' => Action::Op(Operation::Update {
uuid,
property: "title".into(),
value: Some("foo".into()),
timestamp: Utc::now(),
}),
b'D' => Action::Op(Operation::Delete { uuid }),
b'S' => Action::Sync,
_ => unreachable!(),
};
let acton = action_on[1] - b'1';
(action, acton)
})
.collect::<Vec<(Action, u8)>>()
})
}
proptest! {
#[test]
// check that various sequences of operations on mulitple db's do not get the db's into an
// incompatible state. The main concern here is that there might be a sequence of create
// and delete operations that results in a task existing in one DB but not existing in
// another. So, the generated sequences focus on a single task UUID.
fn transform_sequences_of_operations(action_sequence in action_sequence_strategy()) {
let mut server = Server::new();
let mut dbs = [DB::new(), DB::new(), DB::new()];
for (action, db) in action_sequence {
println!("{:?} on db {}", action, db);
let db = &mut dbs[db as usize];
match action {
Action::Op(op) => {
if let Err(e) = db.apply(op) {
println!(" {:?} (ignored)", e);
}
},
Action::Sync => db.sync("me", &mut server),
}
}
println!("{:?}", dbs[0].tasks());
println!("{:?}", dbs[1].tasks());
println!("{:?}", dbs[2].tasks());
assert_eq!(dbs[0].tasks(), dbs[1].tasks());
assert_eq!(dbs[1].tasks(), dbs[2].tasks());
}
}