2019-05-14 10:27:36 -07:00
|
|
|
#![deny(warnings, rust_2018_idioms)]
|
2018-01-31 21:06:42 -08:00
|
|
|
|
|
|
|
|
use std::collections::VecDeque;
|
2019-02-21 11:56:15 -08:00
|
|
|
use std::io::{self, Read};
|
2019-06-27 18:10:29 +01:00
|
|
|
use std::pin::Pin;
|
|
|
|
|
use std::task::Poll::{Pending, Ready};
|
|
|
|
|
use std::task::{Context, Poll};
|
|
|
|
|
|
|
|
|
|
use bytes::{Buf, BytesMut, IntoBuf};
|
|
|
|
|
use futures::Stream;
|
|
|
|
|
|
2019-05-14 10:27:36 -07:00
|
|
|
use tokio_codec::{Decoder, FramedRead};
|
|
|
|
|
use tokio_io::AsyncRead;
|
2019-06-27 18:10:29 +01:00
|
|
|
use tokio_test::assert_ready;
|
|
|
|
|
use tokio_test::task::MockTask;
|
2018-01-31 21:06:42 -08:00
|
|
|
|
|
|
|
|
macro_rules! mock {
|
|
|
|
|
($($x:expr,)*) => {{
|
|
|
|
|
let mut v = VecDeque::new();
|
|
|
|
|
v.extend(vec![$($x),*]);
|
|
|
|
|
Mock { calls: v }
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-27 18:10:29 +01:00
|
|
|
macro_rules! assert_read {
|
|
|
|
|
($e:expr, $n:expr) => {{
|
|
|
|
|
let val = assert_ready!($e);
|
|
|
|
|
assert_eq!(val.unwrap().unwrap(), $n);
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! pin {
|
|
|
|
|
($id:ident) => {
|
|
|
|
|
Pin::new(&mut $id)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-31 21:06:42 -08:00
|
|
|
struct U32Decoder;
|
|
|
|
|
|
|
|
|
|
impl Decoder for U32Decoder {
|
|
|
|
|
type Item = u32;
|
|
|
|
|
type Error = io::Error;
|
|
|
|
|
|
|
|
|
|
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
|
|
|
|
|
if buf.len() < 4 {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 20:47:21 +04:00
|
|
|
let n = buf.split_to(4).into_buf().get_u32_be();
|
2018-01-31 21:06:42 -08:00
|
|
|
Ok(Some(n))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_multi_frame_in_packet() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 1);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 2);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_multi_frame_across_packets() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Ok(b"\x00\x00\x00\x00".to_vec()),
|
|
|
|
|
Ok(b"\x00\x00\x00\x01".to_vec()),
|
|
|
|
|
Ok(b"\x00\x00\x00\x02".to_vec()),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 1);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 2);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_not_ready() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
|
|
|
|
|
Ok(b"\x00\x00\x00\x00".to_vec()),
|
|
|
|
|
Ok(b"\x00\x00\x00\x01".to_vec()),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert!(pin!(framed).poll_next(cx).is_pending());
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 1);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_partial_then_not_ready() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Ok(b"\x00\x00".to_vec()),
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
|
|
|
|
|
Ok(b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert!(pin!(framed).poll_next(cx).is_pending());
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 1);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 2);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_err() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::Other, "")),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
|
assert_ready!(pin!(framed).poll_next(cx))
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.kind()
|
|
|
|
|
)
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_partial_then_err() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Ok(b"\x00\x00".to_vec()),
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::Other, "")),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
|
assert_ready!(pin!(framed).poll_next(cx))
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.kind()
|
|
|
|
|
)
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn read_partial_would_block_then_err() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let mock = mock! {
|
|
|
|
|
Ok(b"\x00\x00".to_vec()),
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::WouldBlock, "")),
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::Other, "")),
|
|
|
|
|
};
|
|
|
|
|
let mut framed = FramedRead::new(mock, U32Decoder);
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert!(pin!(framed).poll_next(cx).is_pending());
|
|
|
|
|
assert_eq!(
|
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
|
assert_ready!(pin!(framed).poll_next(cx))
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.kind()
|
|
|
|
|
)
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn huge_size() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
let data = [0; 32 * 1024];
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut framed = FramedRead::new(Slice(&data[..]), BigDecoder);
|
2018-01-31 21:06:42 -08:00
|
|
|
|
2019-06-27 18:10:29 +01:00
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
|
|
|
|
|
struct BigDecoder;
|
|
|
|
|
|
|
|
|
|
impl Decoder for BigDecoder {
|
|
|
|
|
type Item = u32;
|
|
|
|
|
type Error = io::Error;
|
|
|
|
|
|
|
|
|
|
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<u32>> {
|
|
|
|
|
if buf.len() < 32 * 1024 {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
buf.split_to(32 * 1024);
|
|
|
|
|
Ok(Some(0))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn data_remaining_is_error() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
|
|
|
|
let slice = Slice(&[0; 5]);
|
|
|
|
|
let mut framed = FramedRead::new(slice, U32Decoder);
|
|
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).unwrap().is_err());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn multi_frames_on_eof() {
|
2019-06-27 18:10:29 +01:00
|
|
|
let mut task = MockTask::new();
|
2018-01-31 21:06:42 -08:00
|
|
|
struct MyDecoder(Vec<u32>);
|
|
|
|
|
|
|
|
|
|
impl Decoder for MyDecoder {
|
|
|
|
|
type Item = u32;
|
|
|
|
|
type Error = io::Error;
|
|
|
|
|
|
|
|
|
|
fn decode(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
|
|
|
|
|
unreachable!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn decode_eof(&mut self, _buf: &mut BytesMut) -> io::Result<Option<u32>> {
|
|
|
|
|
if self.0.is_empty() {
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Some(self.0.remove(0)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut framed = FramedRead::new(mock!(), MyDecoder(vec![0, 1, 2, 3]));
|
2019-06-27 18:10:29 +01:00
|
|
|
|
|
|
|
|
task.enter(|cx| {
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 0);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 1);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 2);
|
|
|
|
|
assert_read!(pin!(framed).poll_next(cx), 3);
|
|
|
|
|
assert!(assert_ready!(pin!(framed).poll_next(cx)).is_none());
|
|
|
|
|
});
|
2018-01-31 21:06:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===== Mock ======
|
|
|
|
|
|
|
|
|
|
struct Mock {
|
|
|
|
|
calls: VecDeque<io::Result<Vec<u8>>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Read for Mock {
|
|
|
|
|
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
|
|
|
|
match self.calls.pop_front() {
|
|
|
|
|
Some(Ok(data)) => {
|
|
|
|
|
debug_assert!(dst.len() >= data.len());
|
|
|
|
|
dst[..data.len()].copy_from_slice(&data[..]);
|
|
|
|
|
Ok(data.len())
|
|
|
|
|
}
|
|
|
|
|
Some(Err(e)) => Err(e),
|
|
|
|
|
None => Ok(0),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-27 18:10:29 +01:00
|
|
|
impl AsyncRead for Mock {
|
|
|
|
|
fn poll_read(
|
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
|
_cx: &mut Context<'_>,
|
|
|
|
|
buf: &mut [u8],
|
|
|
|
|
) -> Poll<io::Result<usize>> {
|
|
|
|
|
match Pin::get_mut(self).read(buf) {
|
|
|
|
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Pending,
|
|
|
|
|
other => Ready(other),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO this newtype is necessary because `&[u8]` does not currently implement `AsyncRead`
|
|
|
|
|
struct Slice<'a>(&'a [u8]);
|
|
|
|
|
|
|
|
|
|
impl<'a> AsyncRead for Slice<'a> {
|
|
|
|
|
fn poll_read(
|
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
|
_cx: &mut Context<'_>,
|
|
|
|
|
buf: &mut [u8],
|
|
|
|
|
) -> Poll<io::Result<usize>> {
|
|
|
|
|
Ready(Pin::get_mut(self).0.read(buf))
|
|
|
|
|
}
|
|
|
|
|
}
|