mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-08 00:00:13 +02:00
test: Added read_error() and write_error() (#2337)
Enable testing of edge cases caused by io errors.
This commit is contained in:
+64
-2
@@ -27,6 +27,7 @@ use futures_core::ready;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::task::{self, Poll, Waker};
|
use std::task::{self, Poll, Waker};
|
||||||
use std::{cmp, io};
|
use std::{cmp, io};
|
||||||
|
|
||||||
@@ -57,6 +58,10 @@ enum Action {
|
|||||||
Read(Vec<u8>),
|
Read(Vec<u8>),
|
||||||
Write(Vec<u8>),
|
Write(Vec<u8>),
|
||||||
Wait(Duration),
|
Wait(Duration),
|
||||||
|
// Wrapped in Arc so that Builder can be cloned and Send.
|
||||||
|
// Mock is not cloned as does not need to check Rc for ref counts.
|
||||||
|
ReadError(Option<Arc<io::Error>>),
|
||||||
|
WriteError(Option<Arc<io::Error>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -83,6 +88,16 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sequence a `read` operation that produces an error.
|
||||||
|
///
|
||||||
|
/// The next operation in the mock's script will be to expect a `read` call
|
||||||
|
/// and return `error`.
|
||||||
|
pub fn read_error(&mut self, error: io::Error) -> &mut Self {
|
||||||
|
let error = Some(error.into());
|
||||||
|
self.actions.push_back(Action::ReadError(error));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sequence a `write` operation.
|
/// Sequence a `write` operation.
|
||||||
///
|
///
|
||||||
/// The next operation in the mock's script will be to expect a `write`
|
/// The next operation in the mock's script will be to expect a `write`
|
||||||
@@ -92,6 +107,16 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sequence a `write` operation that produces an error.
|
||||||
|
///
|
||||||
|
/// The next operation in the mock's script will be to expect a `write`
|
||||||
|
/// call that provides `error`.
|
||||||
|
pub fn write_error(&mut self, error: io::Error) -> &mut Self {
|
||||||
|
let error = Some(error.into());
|
||||||
|
self.actions.push_back(Action::WriteError(error));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sequence a wait.
|
/// Sequence a wait.
|
||||||
///
|
///
|
||||||
/// The next operation in the mock's script will be to wait without doing so
|
/// The next operation in the mock's script will be to wait without doing so
|
||||||
@@ -128,6 +153,16 @@ impl Handle {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sequence a `read` operation error.
|
||||||
|
///
|
||||||
|
/// The next operation in the mock's script will be to expect a `read` call
|
||||||
|
/// and return `error`.
|
||||||
|
pub fn read_error(&mut self, error: io::Error) -> &mut Self {
|
||||||
|
let error = Some(error.into());
|
||||||
|
self.tx.send(Action::ReadError(error)).unwrap();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sequence a `write` operation.
|
/// Sequence a `write` operation.
|
||||||
///
|
///
|
||||||
/// The next operation in the mock's script will be to expect a `write`
|
/// The next operation in the mock's script will be to expect a `write`
|
||||||
@@ -136,6 +171,16 @@ impl Handle {
|
|||||||
self.tx.send(Action::Write(buf.into())).unwrap();
|
self.tx.send(Action::Write(buf.into())).unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sequence a `write` operation error.
|
||||||
|
///
|
||||||
|
/// The next operation in the mock's script will be to expect a `write`
|
||||||
|
/// call error.
|
||||||
|
pub fn write_error(&mut self, error: io::Error) -> &mut Self {
|
||||||
|
let error = Some(error.into());
|
||||||
|
self.tx.send(Action::WriteError(error)).unwrap();
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
@@ -174,6 +219,12 @@ impl Inner {
|
|||||||
// Return the number of bytes read
|
// Return the number of bytes read
|
||||||
Ok(n)
|
Ok(n)
|
||||||
}
|
}
|
||||||
|
Some(&mut Action::ReadError(ref mut err)) => {
|
||||||
|
// As the
|
||||||
|
let err = err.take().expect("Should have been removed from actions.");
|
||||||
|
let err = Arc::try_unwrap(err).expect("There are no other references.");
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// Either waiting or expecting a write
|
// Either waiting or expecting a write
|
||||||
Err(io::ErrorKind::WouldBlock.into())
|
Err(io::ErrorKind::WouldBlock.into())
|
||||||
@@ -193,6 +244,12 @@ impl Inner {
|
|||||||
return Err(io::ErrorKind::WouldBlock.into());
|
return Err(io::ErrorKind::WouldBlock.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(&mut Action::WriteError(ref mut err)) = self.action() {
|
||||||
|
let err = err.take().expect("Should have been removed from actions.");
|
||||||
|
let err = Arc::try_unwrap(err).expect("There are no other references.");
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
for i in 0..self.actions.len() {
|
for i in 0..self.actions.len() {
|
||||||
match self.actions[i] {
|
match self.actions[i] {
|
||||||
Action::Write(ref mut expect) => {
|
Action::Write(ref mut expect) => {
|
||||||
@@ -210,7 +267,7 @@ impl Inner {
|
|||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::Wait(..) => {
|
Action::Wait(..) | Action::WriteError(..) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -258,6 +315,11 @@ impl Inner {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Action::ReadError(ref mut error) | Action::WriteError(ref mut error) => {
|
||||||
|
if error.is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _action = self.actions.pop_front();
|
let _action = self.actions.pop_front();
|
||||||
@@ -272,7 +334,7 @@ impl Inner {
|
|||||||
impl Mock {
|
impl Mock {
|
||||||
fn maybe_wakeup_reader(&mut self) {
|
fn maybe_wakeup_reader(&mut self) {
|
||||||
match self.inner.action() {
|
match self.inner.action() {
|
||||||
Some(&mut Action::Read(_)) | None => {
|
Some(&mut Action::Read(_)) | Some(&mut Action::ReadError(_)) | None => {
|
||||||
if let Some(waker) = self.inner.read_wait.take() {
|
if let Some(waker) = self.inner.read_wait.take() {
|
||||||
waker.wake();
|
waker.wake();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
|
use std::io;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio_test::io::Builder;
|
use tokio_test::io::Builder;
|
||||||
|
|
||||||
@@ -16,6 +17,31 @@ async fn read() {
|
|||||||
assert_eq!(&buf[..n], b"world!");
|
assert_eq!(&buf[..n], b"world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn read_error() {
|
||||||
|
let error = io::Error::new(io::ErrorKind::Other, "cruel");
|
||||||
|
let mut mock = Builder::new()
|
||||||
|
.read(b"hello ")
|
||||||
|
.read_error(error)
|
||||||
|
.read(b"world!")
|
||||||
|
.build();
|
||||||
|
let mut buf = [0; 256];
|
||||||
|
|
||||||
|
let n = mock.read(&mut buf).await.expect("read 1");
|
||||||
|
assert_eq!(&buf[..n], b"hello ");
|
||||||
|
|
||||||
|
match mock.read(&mut buf).await {
|
||||||
|
Err(error) => {
|
||||||
|
assert_eq!(error.kind(), io::ErrorKind::Other);
|
||||||
|
assert_eq!("cruel", format!("{}", error));
|
||||||
|
}
|
||||||
|
Ok(_) => panic!("error not received"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = mock.read(&mut buf).await.expect("read 1");
|
||||||
|
assert_eq!(&buf[..n], b"world!");
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn write() {
|
async fn write() {
|
||||||
let mut mock = Builder::new().write(b"hello ").write(b"world!").build();
|
let mut mock = Builder::new().write(b"hello ").write(b"world!").build();
|
||||||
@@ -23,3 +49,24 @@ async fn write() {
|
|||||||
mock.write_all(b"hello ").await.expect("write 1");
|
mock.write_all(b"hello ").await.expect("write 1");
|
||||||
mock.write_all(b"world!").await.expect("write 2");
|
mock.write_all(b"world!").await.expect("write 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn write_error() {
|
||||||
|
let error = io::Error::new(io::ErrorKind::Other, "cruel");
|
||||||
|
let mut mock = Builder::new()
|
||||||
|
.write(b"hello ")
|
||||||
|
.write_error(error)
|
||||||
|
.write(b"world!")
|
||||||
|
.build();
|
||||||
|
mock.write_all(b"hello ").await.expect("write 1");
|
||||||
|
|
||||||
|
match mock.write_all(b"whoa").await {
|
||||||
|
Err(error) => {
|
||||||
|
assert_eq!(error.kind(), io::ErrorKind::Other);
|
||||||
|
assert_eq!("cruel", format!("{}", error));
|
||||||
|
}
|
||||||
|
Ok(_) => panic!("error not received"),
|
||||||
|
}
|
||||||
|
|
||||||
|
mock.write_all(b"world!").await.expect("write 2");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user