summaryrefslogtreecommitdiffstats
path: root/src/simtest/timing.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-25 22:24:20 +0100
committertv <tv@krebsco.de>2026-10-25 22:24:20 +0100
commit0c8e2565b4c80c09f0ba5076b1e27762f2b16eeb (patch)
tree08e06fd15ab6555101f8fb0fa19f92a4a83166de /src/simtest/timing.rs
parentcd9f068270e2258c571bbc01465fcf39f054848b (diff)
add convergence over lossy-links test
Diffstat (limited to 'src/simtest/timing.rs')
-rw-r--r--src/simtest/timing.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/simtest/timing.rs b/src/simtest/timing.rs
index 2633235..df7849f 100644
--- a/src/simtest/timing.rs
+++ b/src/simtest/timing.rs
@@ -14,6 +14,8 @@ use crate::transport::{HeadsSummary, HelloRequest, Keepalive, ParsedMessage, Run
/// Long enough for anything that should happen within a few keepalives.
const SOON: Duration = Duration::from_secs(10);
+/// With lost messages: several reply timeouts (1 s, doubling) and heals in a row.
+const LOSSY: Duration = Duration::from_secs(30);
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn three_nodes_join_and_converge() {
@@ -74,6 +76,37 @@ async fn converges_with_duplicated_and_reordered_messages() {
assert!(sim.net.counts().duplicated > 0);
}
+/// Lost messages are made up for: sync messages by the reply timeout, sessions out of
+/// step by the keepalive heal. Joining under loss too: HELLOs are retried.
+#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
+async fn converges_over_lossy_links() {
+ let sim = Sim::new(5);
+ sim.net.set_default_link(LinkParams {
+ loss: 0.15,
+ duplicate: 0.05,
+ delay: (Duration::from_millis(1), Duration::from_millis(30)),
+ });
+ let a = sim.start("a", &[], Start::Genesis);
+ let b = sim.start("b", &["a"], Start::Join);
+ let c = sim.start("c", &["a"], Start::Join);
+ let (a, b, c) = (&a, &b, &c);
+ sim.wait_ready(&[a, b, c], LOSSY).await;
+
+ for round in 0..10 {
+ write(a, &format!("a/{round}"), json!(round)).await;
+ write(b, &format!("b/{round}"), json!(round)).await;
+ write(c, &format!("c/{round}"), json!(round)).await;
+ tokio::time::sleep(Duration::from_millis(50)).await;
+ }
+ sim.wait_converged(&[a, b, c], LOSSY).await;
+ for node in [a, b, c] {
+ for prefix in ["a", "b", "c"] {
+ assert_eq!(read(node, &format!("{prefix}/9")).await, Some(json!(9)));
+ }
+ }
+ assert!(sim.net.counts().lost > 0);
+}
+
/// A peer that hears nothing for `dormant_after` is dormant; once messages flow again
/// it is active, re-handshakes, and syncs what it missed.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]