#![cfg(feature = "net")]
mod e2e {
use bnb::{MessageDatagram, MessageStream, bin};
use std::io::Read;
use std::net::UdpSocket;
use std::time::Duration;
#[bin(big, magic = b"M")]
#[derive(Debug, Clone, PartialEq, Eq)]
enum Msg {
#[bin(magic = 0x01u8)]
Hi { n: u16 },
#[bin(magic = 0x02u8)]
Bye,
}
#[test]
fn message_stream_round_trips_multiple_messages() {
let mut out = MessageStream::new(Vec::new());
out.write_message(&Msg::Hi { n: 1 }).unwrap();
out.write_message(&Msg::Hi { n: 2 }).unwrap();
out.write_message(&Msg::Bye).unwrap();
let bytes = out.into_inner();
let mut inp = MessageStream::new(&bytes[..]);
assert_eq!(inp.read_message::<Msg>().unwrap(), Msg::Hi { n: 1 });
assert_eq!(inp.read_message::<Msg>().unwrap(), Msg::Hi { n: 2 });
assert_eq!(inp.read_message::<Msg>().unwrap(), Msg::Bye);
assert!(inp.read_message::<Msg>().is_err());
}
#[test]
fn message_stream_bounded_bounds_a_never_completing_frame() {
use bnb::ErrorKind;
let bytes = {
let mut out = MessageStream::new(Vec::new());
out.write_message(&Msg::Hi { n: 7 }).unwrap();
out.into_inner()
};
assert!(bytes.len() > 2);
let mut inp = MessageStream::bounded(&bytes[..], 2);
let err = inp.read_message::<Msg>().unwrap_err();
assert!(
matches!(err.kind, ErrorKind::BufferFull { cap: 2 }),
"expected BufferFull, got {err:?}"
);
}
struct Trickle<'a> {
data: &'a [u8],
chunk: usize,
}
impl Read for Trickle<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n = self.data.len().min(self.chunk).min(buf.len());
buf[..n].copy_from_slice(&self.data[..n]);
self.data = &self.data[n..];
Ok(n)
}
}
#[test]
fn message_stream_reassembles_across_partial_reads() {
let mut out = MessageStream::new(Vec::new());
out.write_message(&Msg::Hi { n: 0xABCD }).unwrap();
out.write_message(&Msg::Bye).unwrap();
let bytes = out.into_inner();
let mut inp = MessageStream::new(Trickle {
data: &bytes,
chunk: 1,
});
assert_eq!(inp.read_message::<Msg>().unwrap(), Msg::Hi { n: 0xABCD });
assert_eq!(inp.read_message::<Msg>().unwrap(), Msg::Bye);
}
#[test]
fn message_datagram_over_udp() {
let server_sock = UdpSocket::bind("127.0.0.1:0").unwrap();
server_sock
.set_read_timeout(Some(Duration::from_secs(5)))
.unwrap();
let server_addr = server_sock.local_addr().unwrap();
let mut server = MessageDatagram::new(server_sock);
let client_sock = UdpSocket::bind("127.0.0.1:0").unwrap();
client_sock
.set_read_timeout(Some(Duration::from_secs(5)))
.unwrap();
let mut client = MessageDatagram::new(client_sock);
client
.send_message(&Msg::Hi { n: 7 }, &server_addr)
.unwrap();
let (req, from) = server.recv_message::<Msg>().unwrap();
assert_eq!(req, Msg::Hi { n: 7 });
server.send_message(&Msg::Bye, &from).unwrap();
let (reply, _) = client.recv_message::<Msg>().unwrap();
assert_eq!(reply, Msg::Bye);
}
#[cfg(unix)]
#[test]
fn message_datagram_over_unix() {
use std::os::unix::net::UnixDatagram;
let dir = std::env::temp_dir();
let spath = dir.join(format!("bnb-net-srv-{}.sock", std::process::id()));
let cpath = dir.join(format!("bnb-net-cli-{}.sock", std::process::id()));
let _ = std::fs::remove_file(&spath);
let _ = std::fs::remove_file(&cpath);
let server_sock = UnixDatagram::bind(&spath).unwrap();
let server_addr = server_sock.local_addr().unwrap();
let mut server = MessageDatagram::new(server_sock);
let client = MessageDatagram::new(UnixDatagram::bind(&cpath).unwrap());
client
.send_message(&Msg::Hi { n: 9 }, &server_addr)
.unwrap();
let (req, _from) = server.recv_message::<Msg>().unwrap();
assert_eq!(req, Msg::Hi { n: 9 });
let _ = std::fs::remove_file(&spath);
let _ = std::fs::remove_file(&cpath);
}
}