test(core): close deferred coverage gaps
This commit is contained in:
@@ -1036,6 +1036,86 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid_addressed_obs_is_accepted() {
|
||||||
|
let mut ex = Exchange::new(ME);
|
||||||
|
let mut store = MemStore::new();
|
||||||
|
ex.on_event(Event::Contact(1), &mut store, 0);
|
||||||
|
// A well-formed, non-expired addressed obs addressed to us IS stored.
|
||||||
|
let mut o = obs([2; 16], 7, 0, None, b"t", b"hi");
|
||||||
|
o.to = Some(ME);
|
||||||
|
o.lifetime_ms = Some(1000);
|
||||||
|
let id = o.id();
|
||||||
|
let frame = Frame::Obs {
|
||||||
|
from: [2; 16],
|
||||||
|
obs: o.clone(),
|
||||||
|
};
|
||||||
|
assert!(
|
||||||
|
ex.on_event(Event::Frame(1, frame_bytes(&frame)), &mut store, 0)
|
||||||
|
.is_some(),
|
||||||
|
"a valid addressed obs must be accepted"
|
||||||
|
);
|
||||||
|
assert!(store.contains(&id));
|
||||||
|
assert_eq!(store.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn addressing_invariant_violation_reverse_is_dropped() {
|
||||||
|
let mut ex = Exchange::new(ME);
|
||||||
|
let mut store = MemStore::new();
|
||||||
|
ex.on_event(Event::Contact(1), &mut store, 0);
|
||||||
|
// to = None but lifetime_ms = Some: the invariant is violated in the
|
||||||
|
// reverse direction, so this frame is malformed and must be dropped.
|
||||||
|
let mut o = obs([2; 16], 7, 0, None, b"t", b"hi");
|
||||||
|
o.to = None;
|
||||||
|
o.lifetime_ms = Some(100);
|
||||||
|
let frame = Frame::Obs {
|
||||||
|
from: [2; 16],
|
||||||
|
obs: o.clone(),
|
||||||
|
};
|
||||||
|
assert!(ex
|
||||||
|
.on_event(Event::Frame(1, frame_bytes(&frame)), &mut store, 0)
|
||||||
|
.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
store.len(),
|
||||||
|
0,
|
||||||
|
"an invariant-violating frame must not be stored"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expired_addressed_obs_is_not_forwarded() {
|
||||||
|
let mut ex = Exchange::new(ME);
|
||||||
|
let mut store = MemStore::new();
|
||||||
|
// An addressed obs already past its lifetime, inserted directly so it
|
||||||
|
// bypasses the receive-side reject (this tests the FORWARD path).
|
||||||
|
let mut o = obs([2; 16], 7, 0, None, b"t", b"hi");
|
||||||
|
o.to = Some([3; 16]);
|
||||||
|
o.lifetime_ms = Some(100);
|
||||||
|
o.age_ms = 200;
|
||||||
|
let id = o.id();
|
||||||
|
store.insert(o, 0).unwrap();
|
||||||
|
|
||||||
|
// A peer whose NodeId we learn (not the recipient, so epidemic applies).
|
||||||
|
ex.on_event(Event::Contact(1), &mut store, 0);
|
||||||
|
let bits = heapless::Vec::from_slice(&[0u8; consts::SUMMARY_BYTES]).unwrap();
|
||||||
|
let sum = Frame::Summary {
|
||||||
|
from: [2; 16],
|
||||||
|
salt: 0,
|
||||||
|
bits,
|
||||||
|
};
|
||||||
|
ex.on_event(Event::Frame(1, frame_bytes(&sum)), &mut store, 0);
|
||||||
|
|
||||||
|
// The expired obs must never be forwarded to any peer.
|
||||||
|
assert!(
|
||||||
|
drain_addressed_obs(&mut ex, &store, Some([3; 16])).is_none(),
|
||||||
|
"an expired addressed obs must not be forwarded"
|
||||||
|
);
|
||||||
|
// It is still held (expiry is checked at select/forward time, not
|
||||||
|
// retroactively removed here).
|
||||||
|
assert!(store.contains(&id));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn addressed_obs_not_in_summary() {
|
fn addressed_obs_not_in_summary() {
|
||||||
let mut ex = Exchange::new(ME);
|
let mut ex = Exchange::new(ME);
|
||||||
|
|||||||
@@ -419,5 +419,15 @@ mod tests {
|
|||||||
// The broadcast survives even though it shares topic/observer with the
|
// The broadcast survives even though it shares topic/observer with the
|
||||||
// dropped addressed observations.
|
// dropped addressed observations.
|
||||||
assert!(s.contains(&broadcast_id));
|
assert!(s.contains(&broadcast_id));
|
||||||
|
// The three youngest addressed (seq 0..2, ages 10/20/30) survive along
|
||||||
|
// with the broadcast (seq 100); seq 3..9 are dropped.
|
||||||
|
let mut seqs = std::collections::BTreeSet::new();
|
||||||
|
s.for_each_topic(b"t", 0, &mut |o| {
|
||||||
|
seqs.insert(o.seq);
|
||||||
|
});
|
||||||
|
assert_eq!(
|
||||||
|
seqs,
|
||||||
|
std::collections::BTreeSet::from_iter([0u64, 1, 2, 100])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -275,3 +275,33 @@ fn belief_excludes_addressed_to_others() {
|
|||||||
);
|
);
|
||||||
assert_eq!(belief.observer, [1; 16]);
|
assert_eq!(belief.observer, [1; 16]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn observe_to_rejects_oversized_payload() {
|
||||||
|
let (a, _b) = PairTransport::pair(1500);
|
||||||
|
let mut node = Node::new([1u8; 16], 0, MemStore::new(), a);
|
||||||
|
|
||||||
|
let oversized_payload = vec![0u8; consts::MAX_PAYLOAD + 1];
|
||||||
|
assert_eq!(
|
||||||
|
node.observe_to([2; 16], 5000, b"task", &oversized_payload, None, 0),
|
||||||
|
Err(ObserveError::TooLarge)
|
||||||
|
);
|
||||||
|
assert_eq!(node.store().len(), 0);
|
||||||
|
assert_eq!(node.next_seq(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn belief_includes_addressed_to_me() {
|
||||||
|
let (a, _b) = PairTransport::pair(1500);
|
||||||
|
let mut node = Node::new([1u8; 16], 0, MemStore::new(), a);
|
||||||
|
|
||||||
|
// An addressed message *to me* is part of my app-facing view.
|
||||||
|
node.observe_to([1; 16], 10_000, b"door", b"for-me", None, 10)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let belief = node
|
||||||
|
.belief(b"door", &LatestWins, 100_000)
|
||||||
|
.expect("door belief exists");
|
||||||
|
assert_eq!(belief.payload, Payload::from_slice(b"for-me").unwrap());
|
||||||
|
assert_eq!(belief.observer, [1; 16]);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user