refactor(sim): move FrameBuf on dup; vary per-node obs; test disconnect/unreachable

This commit is contained in:
2026-10-17 23:58:15 -07:00
parent 1752bd23ff
commit 1257f227ce
3 changed files with 29 additions and 7 deletions
+15 -1
View File
@@ -3,7 +3,7 @@ use common::PairTransport;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use tines_core::observation::Payload; use tines_core::observation::Payload;
use tines_core::transport::{Event, FrameBuf, Transport}; use tines_core::transport::{Event, FrameBuf, SendError, Transport};
use tines_core::{consts, LatestWins, MemStore, Node, ObserveError, Store}; use tines_core::{consts, LatestWins, MemStore, Node, ObserveError, Store};
#[test] #[test]
@@ -206,3 +206,17 @@ fn third_party_observation_propagates_within_contact() {
); );
assert_eq!(nb.store().len(), 1); assert_eq!(nb.store().len(), 1);
} }
#[test]
fn pair_transport_disconnect_enqueues_lost() {
let (mut a, _b) = PairTransport::pair(1500);
a.disconnect();
assert_eq!(a.poll(), Some(Event::Lost(1)));
}
#[test]
fn pair_transport_send_rejects_unreachable() {
let (mut a, _b) = PairTransport::pair(1500);
// a's only peer is 1; sending to 2 is unreachable.
assert_eq!(a.send(&2, b"hi"), Err(SendError::Unreachable));
}
+3 -2
View File
@@ -57,10 +57,11 @@ impl Transport for SimTransport {
return Ok(()); return Ok(());
} }
let buf = FrameBuf::from_slice(frame).map_err(|_| SendError::TooLarge)?; let buf = FrameBuf::from_slice(frame).map_err(|_| SendError::TooLarge)?;
let dup = w.rng.gen::<f64>() < w.cfg.dup;
w.inboxes[*to].push_back(Event::Frame(self.me, buf.clone())); w.inboxes[*to].push_back(Event::Frame(self.me, buf.clone()));
w.frames_sent += 1; w.frames_sent += 1;
if w.rng.gen::<f64>() < w.cfg.dup { if dup {
w.inboxes[*to].push_back(Event::Frame(self.me, buf.clone())); w.inboxes[*to].push_back(Event::Frame(self.me, buf));
w.frames_sent += 1; w.frames_sent += 1;
} }
Ok(()) Ok(())
+11 -4
View File
@@ -72,12 +72,19 @@ type Scenario = (usize, ContactTrace, Vec<(usize, Vec<u8>, Vec<u8>)>);
fn scenario() -> impl Strategy<Value = Scenario> { fn scenario() -> impl Strategy<Value = Scenario> {
(2..=6usize).prop_flat_map(|nodes| { (2..=6usize).prop_flat_map(|nodes| {
let trace = proptest::collection::vec(contact(nodes), 1..=12usize); let trace = proptest::collection::vec(contact(nodes), 1..=12usize);
let obs = proptest::collection::vec(observation(), nodes..=nodes); // Each node publishes 0..=10 observations, flattened to (node, topic,
(trace, obs).prop_map(move |(contacts, per_node)| { // payload) triples so per-node counts vary across scenarios.
let per_node = proptest::collection::vec(
proptest::collection::vec(observation(), 0..=10usize),
nodes..=nodes,
);
(trace, per_node).prop_map(move |(contacts, per_node)| {
let trace = ContactTrace { contacts }; let trace = ContactTrace { contacts };
let mut list = Vec::new(); let mut list = Vec::new();
for (node, (topic, payload)) in per_node.into_iter().enumerate() { for (node, node_obs) in per_node.into_iter().enumerate() {
list.push((node, topic, payload)); for (topic, payload) in node_obs {
list.push((node, topic, payload));
}
} }
(nodes, trace, list) (nodes, trace, list)
}) })