#![cfg(test)]
use super::negotiator::Negotiator;
use super::{NegotiationError, Version};
use bytes::Bytes;
use futures::channel::mpsc;
use futures::prelude::*;
use futures::task::{Context, Poll};
use libp2prs_runtime::{
net::{TcpListener, TcpStream},
task,
};
use pin_project::__private::Pin;
use std::io;
#[derive(Debug)]
pub struct Memory<T> {
tx: mpsc::Sender<T>,
rx: mpsc::Receiver<T>,
recv_drian: Option<T>,
}
impl Memory<Bytes> {
pub fn pair() -> (Self, Self) {
let (tx1, rx1) = mpsc::channel(1);
let (tx2, rx2) = mpsc::channel(1);
(
Memory {
tx: tx1,
rx: rx2,
recv_drian: None,
},
Memory {
tx: tx2,
rx: rx1,
recv_drian: None,
},
)
}
fn drain(&mut self, buf: &mut [u8]) -> Option<usize> {
if let Some(b) = &mut self.recv_drian {
let n = ::std::cmp::min(buf.len(), b.len());
if n == 0 {
return None;
}
buf[..n].copy_from_slice(b[..n].as_ref());
*b = b.split_off(n);
Some(n)
} else {
None
}
}
}
impl AsyncRead for Memory<Bytes> {
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
let this = &mut *self;
if let Some(n) = this.drain(buf) {
return Poll::Ready(Ok(n));
}
let b = futures::ready!(Stream::poll_next(Pin::new(&mut this.rx), cx)).expect("recv next");
this.recv_drian.replace(b);
Poll::Ready(Ok(this.drain(buf).expect("must be Some(n)")))
}
}
impl AsyncWrite for Memory<Bytes> {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
log::debug!("write data: {:?}", buf);
futures::ready!(self.tx.poll_ready(cx)).expect("poll ready");
self.tx
.start_send(Bytes::copy_from_slice(buf))
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Poll::Ready(Ok(buf.len()))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
#[test]
fn select_proto_basic() {
async fn run(_version: Version) {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let listener_addr = listener.local_addr().unwrap();
let server = task::spawn(async move {
let connec = listener.accept().await.unwrap().0;
let protos = vec!["/proto11", "/proto2"];
let neg = Negotiator::new_with_protocols(protos);
let (proto, mut io) = neg.negotiate(connec).await.expect("negotiate");
assert_eq!(proto, "/proto2");
let mut out = vec![0; 32];
let n = io.read(&mut out).await.unwrap();
out.truncate(n);
assert_eq!(out, b"ping");
io.write_all(b"pong").await.unwrap();
io.flush().await.unwrap();
});
let client = task::spawn(async move {
let connec = TcpStream::connect(&listener_addr).await.unwrap();
let protos = vec!["/proto31", "/proto2"];
let neg = Negotiator::new_with_protocols(protos);
let (proto, mut io) = neg.select_one(connec).await.expect("select_one");
assert_eq!(proto, "/proto2");
io.write_all(b"ping").await.unwrap();
io.flush().await.unwrap();
let mut out = vec![0; 32];
let n = io.read(&mut out).await.unwrap();
out.truncate(n);
assert_eq!(out, b"pong");
});
server.await;
client.await;
}
task::block_on(run(Version::V1));
}
#[test]
fn no_protocol_found() {
async fn run(_version: Version) {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let listener_addr = listener.local_addr().unwrap();
let server = task::spawn(async move {
let connec = listener.accept().await.unwrap().0;
let protos = vec![b"/proto1", b"/proto2"];
let neg = Negotiator::new_with_protocols(protos);
assert!(neg.negotiate(connec).await.is_err());
});
let client = task::spawn(async move {
let connec = TcpStream::connect(&listener_addr).await.unwrap();
let protos = vec![b"/proto3", b"/proto4"];
let neg = Negotiator::new_with_protocols(protos);
match neg.select_one(connec).await {
Err(NegotiationError::Failed(_)) => {}
Ok(_) => {}
Err(_) => panic!(),
}
});
server.await;
client.await;
}
task::block_on(run(Version::V1));
}
#[test]
fn select_proto_serial() {
async fn run(_version: Version) {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let listener_addr = listener.local_addr().unwrap();
let server = task::spawn(async move {
let connec = listener.accept().await.unwrap().0;
let protos = vec![b"/proto1", b"/proto2"];
let neg = Negotiator::new_with_protocols(protos);
let (proto, _) = neg.negotiate(connec).await.expect("negotiate");
assert_eq!(proto, b"/proto2");
});
let client = task::spawn(async move {
let connec = TcpStream::connect(&listener_addr).await.unwrap();
let protos = vec![b"/proto3", b"/proto2"];
let neg = Negotiator::new_with_protocols(protos);
let (proto, _) = neg.select_one(connec).await.expect("select_one");
assert_eq!(proto, b"/proto2");
});
server.await;
client.await;
}
task::block_on(run(Version::V1));
}