test(core): PairTransport helper
This commit is contained in:
@@ -0,0 +1,97 @@
|
|||||||
|
//! Shared, test-only helper: two `PairTransport`s wired back-to-back as if they
|
||||||
|
//! were peers on a datagram link. A `send` on one side surfaces as a `Frame`
|
||||||
|
//! on the other; `connect`/`disconnect` broadcast `Contact`/`Lost`.
|
||||||
|
//!
|
||||||
|
//! Each side owns its own inbound queue (`inbox`) and holds a shared handle to
|
||||||
|
//! the other side's queue (`peer_inbox`), so outbound frames land in the peer's
|
||||||
|
//! queue — just like frames crossing a real link. `std` is fine here; this is a
|
||||||
|
//! test fixture, not `tines-core` proper.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use tines_core::transport::{Event, FrameBuf, SendError, Transport};
|
||||||
|
|
||||||
|
/// A pair of in-memory transports connected back-to-back for tests.
|
||||||
|
///
|
||||||
|
/// Addresses are `0` and `1`; the first handle handed back by [`PairTransport::pair`]
|
||||||
|
/// is `0`, the second is `1`.
|
||||||
|
pub struct PairTransport {
|
||||||
|
/// Ourselves: `0` or `1`.
|
||||||
|
me: u8,
|
||||||
|
/// Address of the peer this side talks to.
|
||||||
|
other: u8,
|
||||||
|
/// Our own inbound queue.
|
||||||
|
inbox: Rc<RefCell<VecDeque<Event<u8>>>>,
|
||||||
|
/// The peer's inbound queue, where our `send`s land.
|
||||||
|
peer_inbox: Rc<RefCell<VecDeque<Event<u8>>>>,
|
||||||
|
/// Configured MTU.
|
||||||
|
mtu: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PairTransport {
|
||||||
|
/// Build a connected pair. Returns `(addr 0, addr 1)`.
|
||||||
|
pub fn pair(mtu: usize) -> (PairTransport, PairTransport) {
|
||||||
|
let inbox0: Rc<RefCell<VecDeque<Event<u8>>>> = Rc::new(RefCell::new(VecDeque::new()));
|
||||||
|
let inbox1: Rc<RefCell<VecDeque<Event<u8>>>> = Rc::new(RefCell::new(VecDeque::new()));
|
||||||
|
|
||||||
|
let a = PairTransport {
|
||||||
|
me: 0,
|
||||||
|
other: 1,
|
||||||
|
inbox: inbox0.clone(),
|
||||||
|
peer_inbox: inbox1.clone(),
|
||||||
|
mtu,
|
||||||
|
};
|
||||||
|
let b = PairTransport {
|
||||||
|
me: 1,
|
||||||
|
other: 0,
|
||||||
|
inbox: inbox1.clone(),
|
||||||
|
peer_inbox: inbox0.clone(),
|
||||||
|
mtu,
|
||||||
|
};
|
||||||
|
(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Announce that the peer is reachable.
|
||||||
|
///
|
||||||
|
/// A real contact is symmetric: when two peers meet, each independently
|
||||||
|
/// observes it and calls `connect()` on its own transport, so this enqueues
|
||||||
|
/// `Contact(other)` on *this* side's queue only. (Broadcasting onto the
|
||||||
|
/// peer's queue as well would crowd out the peer's own `Contact` and any
|
||||||
|
/// in-flight frames — the paired peer learns of the contact via its own
|
||||||
|
/// `connect()`, as the test in `tests/pair.rs` exercises.)
|
||||||
|
pub fn connect(&mut self) {
|
||||||
|
let other = self.other;
|
||||||
|
self.inbox.borrow_mut().push_back(Event::Contact(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Announce that the peer is unreachable.
|
||||||
|
#[allow(dead_code)] // required by the transport interface; used by sim harness
|
||||||
|
pub fn disconnect(&mut self) {
|
||||||
|
let other = self.other;
|
||||||
|
self.inbox.borrow_mut().push_back(Event::Lost(other));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transport for PairTransport {
|
||||||
|
type Addr = u8;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Option<Event<Self::Addr>> {
|
||||||
|
self.inbox.borrow_mut().pop_front()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&mut self, to: &Self::Addr, frame: &[u8]) -> Result<(), SendError> {
|
||||||
|
if *to != self.other {
|
||||||
|
return Err(SendError::Unreachable);
|
||||||
|
}
|
||||||
|
let buf = FrameBuf::from_slice(frame).map_err(|_| SendError::TooLarge)?;
|
||||||
|
let event = Event::Frame(self.me, buf);
|
||||||
|
self.peer_inbox.borrow_mut().push_back(event);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mtu(&self) -> usize {
|
||||||
|
self.mtu
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
mod common;
|
||||||
|
use common::PairTransport;
|
||||||
|
|
||||||
|
use tines_core::transport::{Event, FrameBuf, Transport};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pair_transport_connect_then_frame() {
|
||||||
|
let (mut a, mut b) = PairTransport::pair(1500);
|
||||||
|
a.connect();
|
||||||
|
assert_eq!(a.poll(), Some(Event::Contact(1)));
|
||||||
|
a.send(&1, b"hi").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
b.poll(),
|
||||||
|
Some(Event::Frame(0, FrameBuf::from_slice(b"hi").unwrap()))
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user