Update to Tokio 0.2 (#428)
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| use bytes::IntoBuf; | ||||
| use bytes::Buf; | ||||
| use h2::client::{ResponseFuture, SendRequest}; | ||||
| use http::Request; | ||||
|  | ||||
| @@ -11,8 +11,7 @@ pub trait SendRequestExt { | ||||
|  | ||||
| impl<B> SendRequestExt for SendRequest<B> | ||||
| where | ||||
|     B: IntoBuf + Unpin, | ||||
|     B::Buf: Unpin + 'static, | ||||
|     B: Buf + Unpin + 'static, | ||||
| { | ||||
|     fn get(&mut self, uri: &str) -> ResponseFuture { | ||||
|         let req = Request::builder() | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| use std::convert::TryInto; | ||||
| use std::fmt; | ||||
|  | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
| use http::{self, HeaderMap, HttpTryFrom}; | ||||
| use bytes::Bytes; | ||||
| use http::{self, HeaderMap}; | ||||
|  | ||||
| use super::SendFrame; | ||||
| use h2::frame::{self, Frame, StreamId}; | ||||
|  | ||||
| pub const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0]; | ||||
| @@ -25,9 +25,10 @@ where | ||||
| pub fn data<T, B>(id: T, buf: B) -> Mock<frame::Data> | ||||
| where | ||||
|     T: Into<StreamId>, | ||||
|     B: Into<Bytes>, | ||||
|     B: AsRef<[u8]>, | ||||
| { | ||||
|     Mock(frame::Data::new(id.into(), buf.into())) | ||||
|     let buf = Bytes::copy_from_slice(buf.as_ref()); | ||||
|     Mock(frame::Data::new(id.into(), buf)) | ||||
| } | ||||
|  | ||||
| pub fn push_promise<T1, T2>(id: T1, promised: T2) -> Mock<frame::PushPromise> | ||||
| @@ -100,8 +101,10 @@ where | ||||
| impl Mock<frame::Headers> { | ||||
|     pub fn request<M, U>(self, method: M, uri: U) -> Self | ||||
|     where | ||||
|         M: HttpTryInto<http::Method>, | ||||
|         U: HttpTryInto<http::Uri>, | ||||
|         M: TryInto<http::Method>, | ||||
|         M::Error: fmt::Debug, | ||||
|         U: TryInto<http::Uri>, | ||||
|         U::Error: fmt::Debug, | ||||
|     { | ||||
|         let method = method.try_into().unwrap(); | ||||
|         let uri = uri.try_into().unwrap(); | ||||
| @@ -112,7 +115,8 @@ impl Mock<frame::Headers> { | ||||
|  | ||||
|     pub fn response<S>(self, status: S) -> Self | ||||
|     where | ||||
|         S: HttpTryInto<http::StatusCode>, | ||||
|         S: TryInto<http::StatusCode>, | ||||
|         S::Error: fmt::Debug, | ||||
|     { | ||||
|         let status = status.try_into().unwrap(); | ||||
|         let (id, _, fields) = self.into_parts(); | ||||
| @@ -128,8 +132,10 @@ impl Mock<frame::Headers> { | ||||
|  | ||||
|     pub fn field<K, V>(self, key: K, value: V) -> Self | ||||
|     where | ||||
|         K: HttpTryInto<http::header::HeaderName>, | ||||
|         V: HttpTryInto<http::header::HeaderValue>, | ||||
|         K: TryInto<http::header::HeaderName>, | ||||
|         K::Error: fmt::Debug, | ||||
|         V: TryInto<http::header::HeaderValue>, | ||||
|         V::Error: fmt::Debug, | ||||
|     { | ||||
|         let (id, pseudo, mut fields) = self.into_parts(); | ||||
|         fields.insert(key.try_into().unwrap(), value.try_into().unwrap()); | ||||
| @@ -170,12 +176,6 @@ impl From<Mock<frame::Headers>> for frame::Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::Headers>> for SendFrame { | ||||
|     fn from(src: Mock<frame::Headers>) -> Self { | ||||
|         Frame::Headers(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Data helpers | ||||
|  | ||||
| impl Mock<frame::Data> { | ||||
| @@ -190,28 +190,15 @@ impl Mock<frame::Data> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::Data>> for SendFrame { | ||||
|     fn from(src: Mock<frame::Data>) -> Self { | ||||
|         let id = src.0.stream_id(); | ||||
|         let eos = src.0.is_end_stream(); | ||||
|         let is_padded = src.0.is_padded(); | ||||
|         let payload = src.0.into_payload(); | ||||
|         let mut frame = frame::Data::new(id, payload.into_buf()); | ||||
|         frame.set_end_stream(eos); | ||||
|         if is_padded { | ||||
|             frame.set_padded(); | ||||
|         } | ||||
|         Frame::Data(frame) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // PushPromise helpers | ||||
|  | ||||
| impl Mock<frame::PushPromise> { | ||||
|     pub fn request<M, U>(self, method: M, uri: U) -> Self | ||||
|     where | ||||
|         M: HttpTryInto<http::Method>, | ||||
|         U: HttpTryInto<http::Uri>, | ||||
|         M: TryInto<http::Method>, | ||||
|         M::Error: fmt::Debug, | ||||
|         U: TryInto<http::Uri>, | ||||
|         U::Error: fmt::Debug, | ||||
|     { | ||||
|         let method = method.try_into().unwrap(); | ||||
|         let uri = uri.try_into().unwrap(); | ||||
| @@ -229,8 +216,10 @@ impl Mock<frame::PushPromise> { | ||||
|  | ||||
|     pub fn field<K, V>(self, key: K, value: V) -> Self | ||||
|     where | ||||
|         K: HttpTryInto<http::header::HeaderName>, | ||||
|         V: HttpTryInto<http::header::HeaderValue>, | ||||
|         K: TryInto<http::header::HeaderName>, | ||||
|         K::Error: fmt::Debug, | ||||
|         V: TryInto<http::header::HeaderValue>, | ||||
|         V::Error: fmt::Debug, | ||||
|     { | ||||
|         let (id, promised, pseudo, mut fields) = self.into_parts(); | ||||
|         fields.insert(key.try_into().unwrap(), value.try_into().unwrap()); | ||||
| @@ -247,12 +236,6 @@ impl Mock<frame::PushPromise> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::PushPromise>> for SendFrame { | ||||
|     fn from(src: Mock<frame::PushPromise>) -> Self { | ||||
|         Frame::PushPromise(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // GoAway helpers | ||||
|  | ||||
| impl Mock<frame::GoAway> { | ||||
| @@ -281,12 +264,6 @@ impl Mock<frame::GoAway> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::GoAway>> for SendFrame { | ||||
|     fn from(src: Mock<frame::GoAway>) -> Self { | ||||
|         Frame::GoAway(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ==== Reset helpers | ||||
|  | ||||
| impl Mock<frame::Reset> { | ||||
| @@ -326,12 +303,6 @@ impl Mock<frame::Reset> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::Reset>> for SendFrame { | ||||
|     fn from(src: Mock<frame::Reset>) -> Self { | ||||
|         Frame::Reset(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ==== Settings helpers | ||||
|  | ||||
| impl Mock<frame::Settings> { | ||||
| @@ -357,12 +328,6 @@ impl From<Mock<frame::Settings>> for frame::Settings { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::Settings>> for SendFrame { | ||||
|     fn from(src: Mock<frame::Settings>) -> Self { | ||||
|         Frame::Settings(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ==== Ping helpers | ||||
|  | ||||
| impl Mock<frame::Ping> { | ||||
| @@ -371,29 +336,3 @@ impl Mock<frame::Ping> { | ||||
|         Mock(frame::Ping::pong(payload)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Mock<frame::Ping>> for SendFrame { | ||||
|     fn from(src: Mock<frame::Ping>) -> Self { | ||||
|         Frame::Ping(src.0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ==== "trait alias" for types that are HttpTryFrom and have Debug Errors ==== | ||||
|  | ||||
| pub trait HttpTryInto<T> { | ||||
|     type Error: fmt::Debug; | ||||
|  | ||||
|     fn try_into(self) -> Result<T, Self::Error>; | ||||
| } | ||||
|  | ||||
| impl<T, U> HttpTryInto<T> for U | ||||
| where | ||||
|     T: HttpTryFrom<U>, | ||||
|     T::Error: fmt::Debug, | ||||
| { | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn try_into(self) -> Result<T, Self::Error> { | ||||
|         T::try_from(self) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ pub mod raw; | ||||
|  | ||||
| pub mod frames; | ||||
| pub mod mock; | ||||
| pub mod mock_io; | ||||
| pub mod prelude; | ||||
| pub mod util; | ||||
|  | ||||
| @@ -21,7 +20,7 @@ pub type WindowSize = usize; | ||||
| pub const DEFAULT_WINDOW_SIZE: WindowSize = (1 << 16) - 1; | ||||
|  | ||||
| // This is our test Codec type | ||||
| pub type Codec<T> = h2::Codec<T, ::std::io::Cursor<::bytes::Bytes>>; | ||||
| pub type Codec<T> = h2::Codec<T, bytes::Bytes>; | ||||
|  | ||||
| // This is the frame type that is sent | ||||
| pub type SendFrame = h2::frame::Frame<::std::io::Cursor<::bytes::Bytes>>; | ||||
| pub type SendFrame = h2::frame::Frame<bytes::Bytes>; | ||||
|   | ||||
| @@ -9,7 +9,6 @@ use futures::{ready, Stream, StreamExt}; | ||||
| use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; | ||||
|  | ||||
| use super::assert::assert_frame_eq; | ||||
| use futures::executor::block_on; | ||||
| use std::pin::Pin; | ||||
| use std::sync::{Arc, Mutex}; | ||||
| use std::task::{Context, Poll, Waker}; | ||||
| @@ -324,20 +323,18 @@ impl AsyncWrite for Handle { | ||||
|  | ||||
| impl Drop for Handle { | ||||
|     fn drop(&mut self) { | ||||
|         block_on(async { | ||||
|             poll_fn(|cx| { | ||||
|                 assert!(self.codec.shutdown(cx).is_ready()); | ||||
|         // Shutdown *shouldn't* need a real Waker... | ||||
|         let waker = futures::task::noop_waker(); | ||||
|         let mut cx = Context::from_waker(&waker); | ||||
|         assert!(self.codec.shutdown(&mut cx).is_ready()); | ||||
|  | ||||
|                 let mut me = self.codec.get_mut().inner.lock().unwrap(); | ||||
|                 me.closed = true; | ||||
|         if let Ok(mut me) = self.codec.get_mut().inner.lock() { | ||||
|             me.closed = true; | ||||
|  | ||||
|                 if let Some(task) = me.rx_task.take() { | ||||
|                     task.wake(); | ||||
|                 } | ||||
|                 Poll::Ready(()) | ||||
|             }) | ||||
|             .await; | ||||
|         }); | ||||
|             if let Some(task) = me.rx_task.take() { | ||||
|                 task.wake(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -482,5 +479,5 @@ impl AsyncWrite for Pipe { | ||||
| } | ||||
|  | ||||
| pub async fn idle_ms(ms: u64) { | ||||
|     tokio::timer::delay(tokio::clock::now() + Duration::from_millis(ms)).await | ||||
|     tokio::time::delay_for(Duration::from_millis(ms)).await | ||||
| } | ||||
|   | ||||
| @@ -1,509 +0,0 @@ | ||||
| //! A mock type implementing [`Read`] and [`Write`]. | ||||
| //! | ||||
| //! Copied from https://github.com/carllerche/mock-io. | ||||
| //! | ||||
| //! TODO: | ||||
| //! - Either the mock-io crate should be released or this module should be | ||||
| //!   removed from h2. | ||||
| //! | ||||
| //! # Overview | ||||
| //! | ||||
| //! Provides a type that implements [`Read`] + [`Write`] that can be configured | ||||
| //! to handle an arbitrary sequence of read and write operations. This is useful | ||||
| //! for writing unit tests for networking services as using an actual network | ||||
| //! type is fairly non deterministic. | ||||
| //! | ||||
| //! # Usage | ||||
| //! | ||||
| //! Add the following to your `Cargo.toml` | ||||
| //! | ||||
| //! ```toml | ||||
| //! [dependencies] | ||||
| //! mock-io = { git = "https://github.com/carllerche/mock-io" } | ||||
| //! ``` | ||||
| //! | ||||
| //! Then use it in your project. For example, a test could be written: | ||||
| //! | ||||
| //! ``` | ||||
| //! use mock_io::{Builder, Mock}; | ||||
| //! use std::io::{Read, Write}; | ||||
| //! | ||||
| //! # /* | ||||
| //! #[test] | ||||
| //! # */ | ||||
| //! fn test_io() { | ||||
| //!     let mut mock = Builder::new() | ||||
| //!         .write(b"ping") | ||||
| //!         .read(b"pong") | ||||
| //!         .build(); | ||||
| //! | ||||
| //!    let n = mock.write(b"ping").unwrap(); | ||||
| //!    assert_eq!(n, 4); | ||||
| //! | ||||
| //!    let mut buf = vec![]; | ||||
| //!    mock.read_to_end(&mut buf).unwrap(); | ||||
| //! | ||||
| //!    assert_eq!(buf, b"pong"); | ||||
| //! } | ||||
| //! # pub fn main() { | ||||
| //! # test_io(); | ||||
| //! # } | ||||
| //! ``` | ||||
| //! | ||||
| //! Attempting to write data that the mock isn't expected will result in a | ||||
| //! panic. | ||||
| //! | ||||
| //! # Tokio | ||||
| //! | ||||
| //! `Mock` also supports tokio by implementing `AsyncRead` and `AsyncWrite`. | ||||
| //! When using `Mock` in context of a Tokio task, it will automatically switch | ||||
| //! to "async" behavior (this can also be set explicitly by calling `set_async` | ||||
| //! on `Builder`). | ||||
| //! | ||||
| //! In async mode, calls to read and write are non-blocking and the task using | ||||
| //! the mock is notified when the readiness state changes. | ||||
| //! | ||||
| //! # `io-dump` dump files | ||||
| //! | ||||
| //! `Mock` can also be configured from an `io-dump` file. By doing this, the | ||||
| //! mock value will replay a previously recorded behavior. This is useful for | ||||
| //! collecting a scenario from the real world and replying it as part of a test. | ||||
| //! | ||||
| //! [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html | ||||
| //! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html | ||||
|  | ||||
| #![allow(deprecated)] | ||||
|  | ||||
| use std::collections::VecDeque; | ||||
| use std::time::{Duration, Instant}; | ||||
| use std::{cmp, io}; | ||||
|  | ||||
| /// An I/O handle that follows a predefined script. | ||||
| /// | ||||
| /// This value is created by `Builder` and implements `Read + `Write`. It | ||||
| /// follows the scenario described by the builder and panics otherwise. | ||||
| #[derive(Debug)] | ||||
| pub struct Mock { | ||||
|     inner: Inner, | ||||
|     tokio: tokio_::Inner, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct Handle { | ||||
|     inner: tokio_::Handle, | ||||
| } | ||||
|  | ||||
| /// Builds `Mock` instances. | ||||
| #[derive(Debug, Clone, Default)] | ||||
| pub struct Builder { | ||||
|     // Sequence of actions for the Mock to take | ||||
|     actions: VecDeque<Action>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| enum Action { | ||||
|     Read(Vec<u8>), | ||||
|     Write(Vec<u8>), | ||||
|     Wait(Duration), | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| struct Inner { | ||||
|     actions: VecDeque<Action>, | ||||
|     waiting: Option<Instant>, | ||||
| } | ||||
|  | ||||
| impl Builder { | ||||
|     /// Return a new, empty `Builder. | ||||
|     pub fn new() -> Self { | ||||
|         Self::default() | ||||
|     } | ||||
|  | ||||
|     /// Sequence a `read` operation. | ||||
|     /// | ||||
|     /// The next operation in the mock's script will be to expect a `read` call | ||||
|     /// and return `buf`. | ||||
|     pub fn read(&mut self, buf: &[u8]) -> &mut Self { | ||||
|         self.actions.push_back(Action::Read(buf.into())); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Sequence a `write` operation. | ||||
|     /// | ||||
|     /// The next operation in the mock's script will be to expect a `write` | ||||
|     /// call. | ||||
|     pub fn write(&mut self, buf: &[u8]) -> &mut Self { | ||||
|         self.actions.push_back(Action::Write(buf.into())); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Sequence a wait. | ||||
|     /// | ||||
|     /// The next operation in the mock's script will be to wait without doing so | ||||
|     /// for `duration` amount of time. | ||||
|     pub fn wait(&mut self, duration: Duration) -> &mut Self { | ||||
|         let duration = cmp::max(duration, Duration::from_millis(1)); | ||||
|         self.actions.push_back(Action::Wait(duration)); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Build a `Mock` value according to the defined script. | ||||
|     pub fn build(&mut self) -> Mock { | ||||
|         let (mock, _) = self.build_with_handle(); | ||||
|         mock | ||||
|     } | ||||
|  | ||||
|     /// Build a `Mock` value paired with a handle | ||||
|     pub fn build_with_handle(&mut self) -> (Mock, Handle) { | ||||
|         let (tokio, handle) = tokio_::Inner::new(); | ||||
|  | ||||
|         let src = self.clone(); | ||||
|  | ||||
|         let mock = Mock { | ||||
|             inner: Inner { | ||||
|                 actions: src.actions, | ||||
|                 waiting: None, | ||||
|             }, | ||||
|             tokio: tokio, | ||||
|         }; | ||||
|  | ||||
|         let handle = Handle { inner: handle }; | ||||
|  | ||||
|         (mock, handle) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Handle { | ||||
|     /// Sequence a `read` operation. | ||||
|     /// | ||||
|     /// The next operation in the mock's script will be to expect a `read` call | ||||
|     /// and return `buf`. | ||||
|     pub fn read(&mut self, buf: &[u8]) -> &mut Self { | ||||
|         self.inner.read(buf); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Sequence a `write` operation. | ||||
|     /// | ||||
|     /// The next operation in the mock's script will be to expect a `write` | ||||
|     /// call. | ||||
|     pub fn write(&mut self, buf: &[u8]) -> &mut Self { | ||||
|         self.inner.write(buf); | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Inner { | ||||
|     fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { | ||||
|         match self.action() { | ||||
|             Some(&mut Action::Read(ref mut data)) => { | ||||
|                 // Figure out how much to copy | ||||
|                 let n = cmp::min(dst.len(), data.len()); | ||||
|  | ||||
|                 // Copy the data into the `dst` slice | ||||
|                 (&mut dst[..n]).copy_from_slice(&data[..n]); | ||||
|  | ||||
|                 // Drain the data from the source | ||||
|                 data.drain(..n); | ||||
|  | ||||
|                 // Return the number of bytes read | ||||
|                 Ok(n) | ||||
|             } | ||||
|             Some(_) => { | ||||
|                 // Either waiting or expecting a write | ||||
|                 Err(io::ErrorKind::WouldBlock.into()) | ||||
|             } | ||||
|             None => Ok(0), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn write(&mut self, mut src: &[u8]) -> io::Result<usize> { | ||||
|         let mut ret = 0; | ||||
|  | ||||
|         if self.actions.is_empty() { | ||||
|             return Err(io::ErrorKind::BrokenPipe.into()); | ||||
|         } | ||||
|  | ||||
|         match self.action() { | ||||
|             Some(&mut Action::Wait(..)) => { | ||||
|                 return Err(io::ErrorKind::WouldBlock.into()); | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|  | ||||
|         for i in 0..self.actions.len() { | ||||
|             match self.actions[i] { | ||||
|                 Action::Write(ref mut expect) => { | ||||
|                     let n = cmp::min(src.len(), expect.len()); | ||||
|  | ||||
|                     assert_eq!(&src[..n], &expect[..n]); | ||||
|  | ||||
|                     // Drop data that was matched | ||||
|                     expect.drain(..n); | ||||
|                     src = &src[n..]; | ||||
|  | ||||
|                     ret += n; | ||||
|  | ||||
|                     if src.is_empty() { | ||||
|                         return Ok(ret); | ||||
|                     } | ||||
|                 } | ||||
|                 Action::Wait(..) => { | ||||
|                     break; | ||||
|                 } | ||||
|                 _ => {} | ||||
|             } | ||||
|  | ||||
|             // TODO: remove write | ||||
|         } | ||||
|  | ||||
|         Ok(ret) | ||||
|     } | ||||
|  | ||||
|     fn remaining_wait(&mut self) -> Option<Duration> { | ||||
|         match self.action() { | ||||
|             Some(&mut Action::Wait(dur)) => Some(dur), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn action(&mut self) -> Option<&mut Action> { | ||||
|         loop { | ||||
|             if self.actions.is_empty() { | ||||
|                 return None; | ||||
|             } | ||||
|  | ||||
|             match self.actions[0] { | ||||
|                 Action::Read(ref mut data) => { | ||||
|                     if !data.is_empty() { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 Action::Write(ref mut data) => { | ||||
|                     if !data.is_empty() { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 Action::Wait(ref mut dur) => { | ||||
|                     if let Some(until) = self.waiting { | ||||
|                         let now = Instant::now(); | ||||
|  | ||||
|                         if now < until { | ||||
|                             break; | ||||
|                         } | ||||
|                     } else { | ||||
|                         self.waiting = Some(Instant::now() + *dur); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             let _action = self.actions.pop_front(); | ||||
|         } | ||||
|  | ||||
|         self.actions.front_mut() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // use tokio::*; | ||||
|  | ||||
| mod tokio_ { | ||||
|     use super::*; | ||||
|  | ||||
|     use futures::channel::mpsc; | ||||
|     use futures::{ready, FutureExt, Stream}; | ||||
|     use std::task::{Context, Poll, Waker}; | ||||
|     use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|     use tokio::timer::Delay; | ||||
|  | ||||
|     use std::pin::Pin; | ||||
|  | ||||
|     use std::io; | ||||
|  | ||||
|     #[derive(Debug)] | ||||
|     pub struct Inner { | ||||
|         sleep: Option<Delay>, | ||||
|         read_wait: Option<Waker>, | ||||
|         rx: mpsc::UnboundedReceiver<Action>, | ||||
|     } | ||||
|  | ||||
|     #[derive(Debug)] | ||||
|     pub struct Handle { | ||||
|         tx: mpsc::UnboundedSender<Action>, | ||||
|     } | ||||
|  | ||||
|     // ===== impl Handle ===== | ||||
|  | ||||
|     impl Handle { | ||||
|         pub fn read(&mut self, buf: &[u8]) { | ||||
|             self.tx.unbounded_send(Action::Read(buf.into())).unwrap(); | ||||
|         } | ||||
|  | ||||
|         pub fn write(&mut self, buf: &[u8]) { | ||||
|             self.tx.unbounded_send(Action::Write(buf.into())).unwrap(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // ===== impl Inner ===== | ||||
|  | ||||
|     impl Inner { | ||||
|         pub fn new() -> (Inner, Handle) { | ||||
|             let (tx, rx) = mpsc::unbounded(); | ||||
|  | ||||
|             let inner = Inner { | ||||
|                 sleep: None, | ||||
|                 read_wait: None, | ||||
|                 rx: rx, | ||||
|             }; | ||||
|  | ||||
|             let handle = Handle { tx }; | ||||
|  | ||||
|             (inner, handle) | ||||
|         } | ||||
|  | ||||
|         pub(super) fn poll_action(&mut self, cx: &mut Context) -> Poll<Option<Action>> { | ||||
|             Pin::new(&mut self.rx).poll_next(cx) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl Mock { | ||||
|         fn maybe_wakeup_reader(&mut self) { | ||||
|             match self.inner.action() { | ||||
|                 Some(&mut Action::Read(_)) | None => { | ||||
|                     if let Some(task) = self.tokio.read_wait.take() { | ||||
|                         task.wake(); | ||||
|                     } | ||||
|                 } | ||||
|                 _ => {} | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl AsyncRead for Mock { | ||||
|         fn poll_read( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut Context<'_>, | ||||
|             buf: &mut [u8], | ||||
|         ) -> Poll<io::Result<usize>> { | ||||
|             loop { | ||||
|                 if let Some(sleep) = &mut self.tokio.sleep { | ||||
|                     ready!(sleep.poll_unpin(cx)); | ||||
|                 } | ||||
|  | ||||
|                 // If a sleep is set, it has already fired | ||||
|                 self.tokio.sleep = None; | ||||
|  | ||||
|                 match self.inner.read(buf) { | ||||
|                     Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | ||||
|                         if let Some(rem) = self.inner.remaining_wait() { | ||||
|                             self.tokio.sleep = Some(tokio::timer::delay(Instant::now() + rem)); | ||||
|                         } else { | ||||
|                             self.tokio.read_wait = Some(cx.waker().clone()); | ||||
|                             return Poll::Pending; | ||||
|                         } | ||||
|                     } | ||||
|                     Ok(0) => { | ||||
|                         // TODO: Extract | ||||
|                         match self.tokio.poll_action(cx) { | ||||
|                             Poll::Ready(Some(action)) => { | ||||
|                                 self.inner.actions.push_back(action); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             Poll::Ready(None) => { | ||||
|                                 return Poll::Ready(Ok(0)); | ||||
|                             } | ||||
|                             Poll::Pending => { | ||||
|                                 return Poll::Pending; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     ret => return Poll::Ready(ret), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl AsyncWrite for Mock { | ||||
|         fn poll_write( | ||||
|             mut self: Pin<&mut Self>, | ||||
|             cx: &mut Context<'_>, | ||||
|             buf: &[u8], | ||||
|         ) -> Poll<Result<usize, io::Error>> { | ||||
|             loop { | ||||
|                 if let Some(sleep) = &mut self.tokio.sleep { | ||||
|                     ready!(sleep.poll_unpin(cx)); | ||||
|                 } | ||||
|  | ||||
|                 // If a sleep is set, it has already fired | ||||
|                 self.tokio.sleep = None; | ||||
|  | ||||
|                 match self.inner.write(buf) { | ||||
|                     Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | ||||
|                         if let Some(rem) = self.inner.remaining_wait() { | ||||
|                             self.tokio.sleep = Some(tokio::timer::delay(Instant::now() + rem)); | ||||
|                         } else { | ||||
|                             panic!("unexpected WouldBlock"); | ||||
|                         } | ||||
|                     } | ||||
|                     Ok(0) => { | ||||
|                         // TODO: Is this correct? | ||||
|                         if !self.inner.actions.is_empty() { | ||||
|                             return Poll::Pending; | ||||
|                         } | ||||
|  | ||||
|                         // TODO: Extract | ||||
|                         match self.tokio.poll_action(cx) { | ||||
|                             Poll::Ready(Some(action)) => { | ||||
|                                 self.inner.actions.push_back(action); | ||||
|                                 continue; | ||||
|                             } | ||||
|                             Poll::Ready(None) => { | ||||
|                                 panic!("unexpected write"); | ||||
|                             } | ||||
|                             Poll::Pending => return Poll::Pending, | ||||
|                         } | ||||
|                     } | ||||
|                     ret => { | ||||
|                         self.maybe_wakeup_reader(); | ||||
|                         return Poll::Ready(ret); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { | ||||
|             Poll::Ready(Ok(())) | ||||
|         } | ||||
|  | ||||
|         fn poll_shutdown( | ||||
|             self: Pin<&mut Self>, | ||||
|             _cx: &mut Context<'_>, | ||||
|         ) -> Poll<Result<(), io::Error>> { | ||||
|             Poll::Ready(Ok(())) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     TODO: Is this required? | ||||
|  | ||||
|     /// Returns `true` if called from the context of a futures-rs Task | ||||
|     pub fn is_task_ctx() -> bool { | ||||
|         use std::panic; | ||||
|  | ||||
|         // Save the existing panic hook | ||||
|         let h = panic::take_hook(); | ||||
|  | ||||
|         // Install a new one that does nothing | ||||
|         panic::set_hook(Box::new(|_| {})); | ||||
|  | ||||
|         // Attempt to call the fn | ||||
|         let r = panic::catch_unwind(|| task::current()).is_ok(); | ||||
|  | ||||
|         // Re-install the old one | ||||
|         panic::set_hook(h); | ||||
|  | ||||
|         // Return the result | ||||
|         r | ||||
|     } | ||||
|     */ | ||||
| } | ||||
| @@ -27,7 +27,7 @@ pub use super::{ | ||||
| pub use super::assert::assert_frame_eq; | ||||
|  | ||||
| // Re-export useful crates | ||||
| pub use super::mock_io; | ||||
| pub use tokio_test::io as mock_io; | ||||
| pub use {bytes, env_logger, futures, http, tokio::io as tokio_io}; | ||||
|  | ||||
| // Re-export primary future types | ||||
| @@ -42,7 +42,10 @@ pub use super::client_ext::SendRequestExt; | ||||
| // Re-export HTTP types | ||||
| pub use http::{uri, HeaderMap, Method, Request, Response, StatusCode, Version}; | ||||
|  | ||||
| pub use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf}; | ||||
| pub use bytes::{ | ||||
|     buf::{BufExt, BufMutExt}, | ||||
|     Buf, BufMut, Bytes, BytesMut, | ||||
| }; | ||||
|  | ||||
| pub use tokio::io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| @@ -61,7 +64,7 @@ pub trait MockH2 { | ||||
|     fn handshake(&mut self) -> &mut Self; | ||||
| } | ||||
|  | ||||
| impl MockH2 for super::mock_io::Builder { | ||||
| impl MockH2 for tokio_test::io::Builder { | ||||
|     fn handshake(&mut self) -> &mut Self { | ||||
|         self.write(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") | ||||
|             // Settings frame | ||||
| @@ -81,8 +84,7 @@ pub trait ClientExt { | ||||
| impl<T, B> ClientExt for client::Connection<T, B> | ||||
| where | ||||
|     T: AsyncRead + AsyncWrite + Unpin + 'static, | ||||
|     B: IntoBuf + Unpin + 'static, | ||||
|     B::Buf: Unpin, | ||||
|     B: Buf + Unpin + 'static, | ||||
| { | ||||
|     fn run<'a, F: Future + Unpin + 'a>( | ||||
|         &'a mut self, | ||||
|   | ||||
| @@ -7,7 +7,7 @@ macro_rules! raw_codec { | ||||
|             $fn:ident => [$($chunk:expr,)+]; | ||||
|         )* | ||||
|     ) => {{ | ||||
|         let mut b = $crate::mock_io::Builder::new(); | ||||
|         let mut b = $crate::prelude::mock_io::Builder::new(); | ||||
|  | ||||
|         $({ | ||||
|             let mut chunk = vec![]; | ||||
|   | ||||
| @@ -1,14 +1,21 @@ | ||||
| use h2; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use bytes::{BufMut, Bytes}; | ||||
| use futures::ready; | ||||
| use std::future::Future; | ||||
| use std::pin::Pin; | ||||
| use std::task::{Context, Poll}; | ||||
| use string::{String, TryFrom}; | ||||
|  | ||||
| pub fn byte_str(s: &str) -> String<Bytes> { | ||||
|     String::try_from(Bytes::from(s)).unwrap() | ||||
| pub fn byte_str(s: &str) -> h2::frame::BytesStr { | ||||
|     h2::frame::BytesStr::try_from(Bytes::copy_from_slice(s.as_bytes())).unwrap() | ||||
| } | ||||
|  | ||||
| pub async fn concat(mut body: h2::RecvStream) -> Result<Bytes, h2::Error> { | ||||
|     let mut vec = Vec::new(); | ||||
|     while let Some(chunk) = body.data().await { | ||||
|         vec.put(chunk?); | ||||
|     } | ||||
|     Ok(vec.into()) | ||||
| } | ||||
|  | ||||
| pub async fn yield_once() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user