//! Integration tests that replay the Kleppmann editing trace to validate list-CRDT correctness and performance. use bft_json_crdt::keypair::make_author; use bft_json_crdt::list_crdt::ListCrdt; use bft_json_crdt::op::{OpId, ROOT_ID}; use std::{fs::File, io::Read, time::Instant}; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] #[serde(rename_all = "camelCase")] struct Edit { pos: usize, delete: bool, #[serde(default)] content: Option, } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct Trace { final_text: String, edits: Vec, } fn get_trace() -> Trace { let fp = "./tests/edits.json"; match File::open(fp) { Err(e) => panic!("Open edits.json failed: {:?}", e.kind()), Ok(mut file) => { let mut content: String = String::new(); file.read_to_string(&mut content) .expect("Problem reading file"); serde_json::from_str(&content).expect("JSON was not well-formatted") } } } /// Really large test to run Martin Kleppmann's /// editing trace over his paper /// Data source: https://github.com/automerge/automerge-perf // Commented out: takes 10+ minutes and 12GB+ RAM. Run manually with: // cargo test --package bft-json-crdt --test kleppmann_trace -- --ignored #[test] #[ignore] fn test_editing_trace() { let t = get_trace(); let mut list = ListCrdt::::new(make_author(1), vec![]); let mut ops: Vec = Vec::new(); ops.push(ROOT_ID); let start = Instant::now(); let edits = t.edits; for (i, op) in edits.into_iter().enumerate() { let origin = ops[op.pos]; if op.delete { let delete_op = list.delete(origin); ops.push(delete_op.id); } else { let new_op = list.insert(origin, op.content.unwrap()); ops.push(new_op.id); } match i { 10_000 | 100_000 => { println!("took {:?} to run {i} ops", start.elapsed()); } _ => {} }; } println!("took {:?} to finish", start.elapsed()); let result = list.iter().collect::(); let expected = t.final_text; assert_eq!(result.len(), expected.len()); assert_eq!(result, expected); }