summaryrefslogtreecommitdiffstats
path: root/src/simtest
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-26 06:09:02 +0100
committertv <tv@krebsco.de>2026-10-26 06:09:02 +0100
commitd8738b3a74591587b0efc00edae37e5d46a02d4b (patch)
tree0591869128a78ddd991a7c6d9410bf0e2ce81774 /src/simtest
parent3be4ec3aa0e076e5386cfd1b93b07d12c40a88cb (diff)
forgotten nodes cancel their own records
Diffstat (limited to 'src/simtest')
-rw-r--r--src/simtest/timing.rs39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/simtest/timing.rs b/src/simtest/timing.rs
index 4247090..06a2f12 100644
--- a/src/simtest/timing.rs
+++ b/src/simtest/timing.rs
@@ -375,3 +375,42 @@ async fn late_epoch_does_not_flip_a_peers_epoch() {
assert_eq!(a.local_epoch(), Epoch::GENESIS);
assert!(a.is_ready().await);
}
+
+/// A swarm-wide forget of a node that is alive: nobody forgets it, and it cancels the
+/// record itself.
+#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
+async fn forgotten_node_that_is_alive_cancels_its_record() {
+ use crate::document::store;
+ use crate::swarm::peer::forgotten_path;
+
+ let sim = Sim::new(9);
+ 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], SOON).await;
+
+ let record = forgotten_path(b.local_id());
+ let written = record.clone();
+ a.mutate_doc(move |doc| store::write_path(doc, &written, &json!({"at": 0, "by": "a"})))
+ .await
+ .expect("write forget record");
+
+ // The forget check runs every 5 s.
+ for node in [a, b, c] {
+ let record = record.clone();
+ sim.wait_until("the record is cancelled", SOON + SOON, move || {
+ let record = record.clone();
+ async move {
+ store::read_path(&node.doc.read().await.doc, &record)
+ .expect("read")
+ .is_none()
+ }
+ })
+ .await;
+ }
+ for node in [a, c] {
+ assert!(node.get_peer_state(b.local_id()).await.is_some());
+ }
+ sim.wait_converged(&[a, b, c], SOON).await;
+}