use std::time::Duration;
use reconcile::{reconcile_store::Config, ReconcileMirror, ReconcileStore};
async fn wait_until<F: FnMut() -> bool>(mut f: F) -> bool {
for _ in 0..200 {
tokio::time::sleep(Duration::from_millis(10)).await;
if f() {
return true;
}
}
false
}
macro_rules! assert_until {
( $x:expr ) => {
assert!(wait_until(|| $x).await, stringify!($x))
};
}
#[tokio::test(flavor = "multi_thread")]
async fn mirror_converges_with_dated_store() {
let port = 8086;
let net = "127.0.0.1/8".parse().unwrap();
let dated_addr = "127.0.0.90".parse().unwrap();
let mirror_addr = "127.0.0.91".parse().unwrap();
let dated = ReconcileStore::<String, String>::new(
Config::default()
.with_port(port)
.with_listen_addr(dated_addr)
.with_net(net),
)
.await;
let mirror = ReconcileMirror::<String, String>::new(
Config::default()
.with_port(port)
.with_listen_addr(mirror_addr)
.with_net(net),
)
.await
.with_seed(dated_addr);
for i in 0..50 {
dated.insert(format!("k{i:02}"), format!("v{i:02}"));
}
dated.insert("doomed".to_string(), "to be deleted".to_string());
let dated_task = tokio::spawn(dated.clone().run());
let mirror_task = tokio::spawn(mirror.clone().run());
assert_until!(mirror.get(&"k00".to_string()).as_deref() == Some(&"v00".to_string()));
assert_until!(mirror.get(&"k49".to_string()).as_deref() == Some(&"v49".to_string()));
assert_until!(
mirror.get(&"doomed".to_string()).as_deref() == Some(&"to be deleted".to_string())
);
assert_until!(mirror.fingerprint(..) == dated.value_fingerprint(..));
assert_eq!(mirror.len(), 51);
dated.insert("late".to_string(), "arrival".to_string());
assert_until!(mirror.get(&"late".to_string()).as_deref() == Some(&"arrival".to_string()));
dated.remove(&"doomed".to_string());
assert_until!(mirror.get(&"doomed".to_string()).is_none());
assert_until!(mirror.fingerprint(..) == dated.value_fingerprint(..));
dated_task.abort();
mirror_task.abort();
}
#[tokio::test(flavor = "multi_thread")]
async fn mirror_does_not_block_tombstone_gc() {
let port = 8087;
let net = "127.0.0.1/8".parse().unwrap();
let dated_addr = "127.0.0.92".parse().unwrap();
let mirror_addr = "127.0.0.93".parse().unwrap();
let dated = ReconcileStore::<i32, i32>::new(
Config::default()
.with_port(port)
.with_listen_addr(dated_addr)
.with_net(net),
)
.await
.with_tombstone_timeout(Duration::from_millis(50));
let mirror = ReconcileMirror::<i32, i32>::new(
Config::default()
.with_port(port)
.with_listen_addr(mirror_addr)
.with_net(net),
)
.await
.with_seed(dated_addr);
dated.insert(1, 11);
dated.insert(2, 22);
let dated_task = tokio::spawn(dated.clone().run());
let mirror_task = tokio::spawn(mirror.clone().run());
assert_until!(mirror.get(&1).as_deref() == Some(&11));
assert_until!(mirror.get(&2).as_deref() == Some(&22));
dated.remove(&1);
let with_tombstone = dated.fingerprint(..);
assert_until!(dated.fingerprint(..) != with_tombstone);
assert_eq!(dated.get(&2).as_deref(), Some(&22));
dated_task.abort();
mirror_task.abort();
}