Update to Tokio 0.2 (#428)

This commit is contained in:
Sean McArthur
2019-11-27 14:53:57 -08:00
committed by GitHub
parent 37b66e8981
commit 4398e169e8
53 changed files with 473 additions and 972 deletions

View File

@@ -9,7 +9,7 @@ edition = "2018"
h2 = { path = "../.." }
env_logger = { version = "0.5.3", default-features = false }
futures-preview = "=0.3.0-alpha.19"
futures = { version = "0.3", default-features = false }
honggfuzz = "0.5"
http = "0.1.3"
tokio = "=0.2.0-alpha.6"
http = { git = "https://github.com/hyperium/http" } #"0.1.3"
tokio = { version = "0.2", features = [] }

View File

@@ -7,9 +7,9 @@ edition = "2018"
[dependencies]
h2 = { path = "../..", features = ["unstable-stream", "unstable"] }
bytes = "0.4.7"
bytes = "0.5"
env_logger = "0.5.9"
futures-preview = "=0.3.0-alpha.19"
http = "0.1.5"
string = "0.2"
tokio = "=0.2.0-alpha.6"
futures = { version = "0.3", default-features = false }
http = { git = "https://github.com/hyperium/http" } #"0.1.3"
tokio = { version = "0.2", features = ["time"] }
tokio-test = "0.2"

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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>;

View File

@@ -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
}

View File

@@ -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
}
*/
}

View File

@@ -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,

View File

@@ -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![];

View File

@@ -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() {

View File

@@ -10,5 +10,5 @@ edition = "2018"
[dev-dependencies]
h2-support = { path = "../h2-support" }
log = "0.4.1"
futures-preview = "=0.3.0-alpha.19"
tokio = "=0.2.0-alpha.6"
futures = { version = "0.3", default-features = false, features = ["alloc"] }
tokio = { version = "0.2", features = ["macros", "tcp"] }

View File

@@ -418,7 +418,7 @@ async fn send_reset_notifies_recv_stream() {
// We don't want a join, since any of the other futures notifying
// will make the rx future polled again, but we are
// specifically testing that rx gets notified on its own.
let mut unordered = FuturesUnordered::<Pin<Box<dyn Future<Output = ()>>>>::new();
let unordered = FuturesUnordered::<Pin<Box<dyn Future<Output = ()>>>>::new();
unordered.push(Box::pin(rx));
unordered.push(Box::pin(tx));
@@ -754,7 +754,7 @@ async fn pending_send_request_gets_reset_by_peer_properly() {
let _ = env_logger::try_init();
let (io, mut srv) = mock::new();
let payload = vec![0; (frame::DEFAULT_INITIAL_WINDOW_SIZE * 2) as usize];
let payload = Bytes::from(vec![0; (frame::DEFAULT_INITIAL_WINDOW_SIZE * 2) as usize]);
let max_frame_size = frame::DEFAULT_MAX_FRAME_SIZE as usize;
let srv = async {
@@ -811,7 +811,7 @@ async fn pending_send_request_gets_reset_by_peer_properly() {
};
// Send the data
stream.send_data(payload[..].into(), true).unwrap();
stream.send_data(payload.clone(), true).unwrap();
conn.drive(response).await;
drop(client);
drop(stream);
@@ -897,7 +897,7 @@ async fn notify_on_send_capacity() {
// This test ensures that the client gets notified when there is additional
// send capacity. In other words, when the server is ready to accept a new
// stream, the client is notified.
use futures::channel::oneshot;
use tokio::sync::oneshot;
let _ = env_logger::try_init();
@@ -1016,13 +1016,14 @@ async fn send_stream_poll_reset() {
async fn drop_pending_open() {
// This test checks that a stream queued for pending open behaves correctly when its
// client drops.
use tokio::sync::oneshot;
let _ = env_logger::try_init();
let (io, mut srv) = mock::new();
let (init_tx, init_rx) = futures::channel::oneshot::channel();
let (trigger_go_away_tx, trigger_go_away_rx) = futures::channel::oneshot::channel();
let (sent_go_away_tx, sent_go_away_rx) = futures::channel::oneshot::channel();
let (drop_tx, drop_rx) = futures::channel::oneshot::channel();
let (init_tx, init_rx) = oneshot::channel();
let (trigger_go_away_tx, trigger_go_away_rx) = oneshot::channel();
let (sent_go_away_tx, sent_go_away_rx) = oneshot::channel();
let (drop_tx, drop_rx) = oneshot::channel();
let mut settings = frame::Settings::default();
settings.set_max_concurrent_streams(Some(2));
@@ -1103,11 +1104,12 @@ async fn malformed_response_headers_dont_unlink_stream() {
// This test checks that receiving malformed headers frame on a stream with
// no remaining references correctly resets the stream, without prematurely
// unlinking it.
use tokio::sync::oneshot;
let _ = env_logger::try_init();
let (io, mut srv) = mock::new();
let (drop_tx, drop_rx) = futures::channel::oneshot::channel();
let (queued_tx, queued_rx) = futures::channel::oneshot::channel();
let (drop_tx, drop_rx) = oneshot::channel();
let (queued_tx, queued_rx) = oneshot::channel();
let srv = async move {
let settings = srv.assert_client_handshake().await;

View File

@@ -175,8 +175,7 @@ async fn read_continuation_frames() {
let expected = large
.iter()
.fold(HeaderMap::new(), |mut map, &(name, ref value)| {
use h2_support::frames::HttpTryInto;
map.append(name, value.as_str().try_into().unwrap());
map.append(name, value.parse().unwrap());
map
});
assert_eq!(head.headers, expected);

View File

@@ -27,10 +27,10 @@ async fn write_continuation_frames() {
let (mut client, mut conn) = client::handshake(io).await.expect("handshake");
let mut request = Request::builder();
request.uri("https://http2.akamai.com/");
request = request.uri("https://http2.akamai.com/");
for &(name, ref value) in &large {
request.header(name, &value[..]);
request = request.header(name, &value[..]);
}
let request = request.body(()).unwrap();

View File

@@ -9,7 +9,7 @@ use h2_support::util::yield_once;
async fn send_data_without_requesting_capacity() {
let _ = env_logger::try_init();
let payload = [0; 1024];
let payload = vec![0; 1024];
let mock = mock_io::Builder::new()
.handshake()
@@ -42,7 +42,7 @@ async fn send_data_without_requesting_capacity() {
assert_eq!(stream.capacity(), 0);
// Send the data
stream.send_data(payload[..].into(), true).unwrap();
stream.send_data(payload.into(), true).unwrap();
// Get the response
let resp = h2.run(response).await.unwrap();
@@ -93,17 +93,17 @@ async fn release_capacity_sends_window_update() {
let mut body = resp.into_parts().1;
// read some body to use up window size to below half
let buf = body.next().await.unwrap().unwrap();
let buf = body.data().await.unwrap().unwrap();
assert_eq!(buf.len(), payload_len);
let buf = body.next().await.unwrap().unwrap();
let buf = body.data().await.unwrap().unwrap();
assert_eq!(buf.len(), payload_len);
let buf = body.next().await.unwrap().unwrap();
let buf = body.data().await.unwrap().unwrap();
assert_eq!(buf.len(), payload_len);
body.flow_control().release_capacity(buf.len() * 2).unwrap();
let buf = body.next().await.unwrap().unwrap();
let buf = body.data().await.unwrap().unwrap();
assert_eq!(buf.len(), payload_len);
};
@@ -153,11 +153,11 @@ async fn release_capacity_of_small_amount_does_not_send_window_update() {
assert_eq!(resp.status(), StatusCode::OK);
let mut body = resp.into_parts().1;
assert!(!body.is_end_stream());
let buf = body.next().await.unwrap().unwrap();
let buf = body.data().await.unwrap().unwrap();
// read the small body and then release it
assert_eq!(buf.len(), 16);
body.flow_control().release_capacity(buf.len()).unwrap();
let buf = body.next().await;
let buf = body.data().await;
assert!(buf.is_none());
};
join(async move { h2.await.unwrap() }, req).await;
@@ -213,7 +213,7 @@ async fn recv_data_overflows_connection_window() {
let resp = client.send_request(request, true).unwrap().0.await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
let res = body.try_concat().await;
let res = util::concat(body).await;
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
@@ -274,7 +274,7 @@ async fn recv_data_overflows_stream_window() {
let resp = client.send_request(request, true).unwrap().0.await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
let res = body.try_concat().await;
let res = util::concat(body).await;
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
@@ -685,8 +685,7 @@ async fn reserved_capacity_assigned_in_multi_window_updates() {
#[tokio::test]
async fn connection_notified_on_released_capacity() {
use futures::channel::mpsc;
use futures::channel::oneshot;
use tokio::sync::{mpsc, oneshot};
let _ = env_logger::try_init();
let (io, mut srv) = mock::new();
@@ -695,7 +694,7 @@ async fn connection_notified_on_released_capacity() {
// notifications. This test is here, in part, to ensure that the connection
// receives the appropriate notifications to send out window updates.
let (tx, mut rx) = mpsc::unbounded();
let (tx, mut rx) = mpsc::unbounded_channel();
// Because threading is fun
let (settings_tx, settings_rx) = oneshot::channel();
@@ -744,11 +743,11 @@ async fn connection_notified_on_released_capacity() {
h2.drive(settings_rx).await.unwrap();
let request = Request::get("https://example.com/a").body(()).unwrap();
tx.unbounded_send(client.send_request(request, true).unwrap().0)
tx.send(client.send_request(request, true).unwrap().0)
.unwrap();
let request = Request::get("https://example.com/b").body(()).unwrap();
tx.unbounded_send(client.send_request(request, true).unwrap().0)
tx.send(client.send_request(request, true).unwrap().0)
.unwrap();
tokio::spawn(async move {
@@ -760,8 +759,8 @@ async fn connection_notified_on_released_capacity() {
});
// Get the two requests
let a = rx.next().await.unwrap();
let b = rx.next().await.unwrap();
let a = rx.recv().await.unwrap();
let b = rx.recv().await.unwrap();
// Get the first response
let response = a.await.unwrap();
@@ -769,7 +768,7 @@ async fn connection_notified_on_released_capacity() {
let (_, mut a) = response.into_parts();
// Get the next chunk
let chunk = a.next().await.unwrap();
let chunk = a.data().await.unwrap();
assert_eq!(16_384, chunk.unwrap().len());
// Get the second response
@@ -778,7 +777,7 @@ async fn connection_notified_on_released_capacity() {
let (_, mut b) = response.into_parts();
// Get the next chunk
let chunk = b.next().await.unwrap();
let chunk = b.data().await.unwrap();
assert_eq!(16_384, chunk.unwrap().len());
// Wait a bit
@@ -944,7 +943,6 @@ async fn recv_no_init_window_then_receive_some_init_window() {
async fn settings_lowered_capacity_returns_capacity_to_connection() {
use futures::channel::oneshot;
use futures::future::{select, Either};
use std::time::Instant;
let _ = env_logger::try_init();
let (io, mut srv) = mock::new();
@@ -976,11 +974,7 @@ async fn settings_lowered_capacity_returns_capacity_to_connection() {
//
// A timeout is used here to avoid blocking forever if there is a
// failure
let result = select(
rx2,
tokio::timer::delay(Instant::now() + Duration::from_secs(5)),
)
.await;
let result = select(rx2, tokio::time::delay_for(Duration::from_secs(5))).await;
if let Either::Right((_, _)) = result {
panic!("Timed out");
}
@@ -1012,11 +1006,7 @@ async fn settings_lowered_capacity_returns_capacity_to_connection() {
});
// Wait for server handshake to complete.
let result = select(
rx1,
tokio::timer::delay(Instant::now() + Duration::from_secs(5)),
)
.await;
let result = select(rx1, tokio::time::delay_for(Duration::from_secs(5))).await;
if let Either::Right((_, _)) = result {
panic!("Timed out");
}
@@ -1113,7 +1103,7 @@ async fn increase_target_window_size_after_using_some() {
// drive an empty future to allow the WINDOW_UPDATE
// to go out while the response capacity is still in use.
conn.drive(yield_once()).await;
let _res = conn.drive(res.into_body().try_concat()).await;
let _res = conn.drive(util::concat(res.into_body())).await;
conn.await.expect("client");
};
@@ -1156,7 +1146,7 @@ async fn decrease_target_window_size() {
let mut body = res.into_parts().1;
let mut cap = body.flow_control().clone();
let bytes = conn.drive(body.try_concat()).await.expect("concat");
let bytes = conn.drive(util::concat(body)).await.expect("concat");
assert_eq!(bytes.len(), 65_535);
cap.release_capacity(bytes.len()).unwrap();
conn.await.expect("conn");
@@ -1568,7 +1558,7 @@ async fn data_padding() {
let resp = response.await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_body();
let bytes = body.try_concat().await.unwrap();
let bytes = util::concat(body).await.unwrap();
assert_eq!(bytes.len(), 100);
};
join(async move { conn.await.expect("client") }, fut).await;

View File

@@ -26,8 +26,8 @@ impl Server {
{
let mk_data = Arc::new(mk_data);
let rt = tokio::runtime::Runtime::new().unwrap();
let listener = rt
let mut rt = tokio::runtime::Runtime::new().unwrap();
let mut listener = rt
.block_on(TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0))))
.unwrap();
let addr = listener.local_addr().unwrap();
@@ -35,8 +35,8 @@ impl Server {
let reqs2 = reqs.clone();
let join = thread::spawn(move || {
let server = async move {
let mut incoming = listener.incoming();
while let Some(socket) = incoming.next().await {
loop {
let socket = listener.accept().await.map(|(s, _)| s);
let reqs = reqs2.clone();
let mk_data = mk_data.clone();
tokio::spawn(async move {
@@ -140,7 +140,7 @@ fn hammer_client_concurrency() {
})
});
let rt = tokio::runtime::Runtime::new().unwrap();
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(tcp);
println!("...done");
}

View File

@@ -1,6 +1,6 @@
use futures::channel::oneshot;
use futures::future::join;
use futures::{StreamExt, TryStreamExt};
use futures::StreamExt;
use h2_support::assert_ping;
use h2_support::prelude::*;
@@ -84,7 +84,7 @@ async fn pong_has_highest_priority() {
assert_eq!(req.method(), "POST");
let body = req.into_parts().1;
let body = body.try_concat().await.expect("body");
let body = util::concat(body).await.expect("body");
assert_eq!(body.len(), data.len());
let res = Response::builder().status(200).body(()).unwrap();
stream.send_response(res, true).expect("response");

View File

@@ -8,7 +8,7 @@ use std::task::Context;
async fn single_stream_send_large_body() {
let _ = env_logger::try_init();
let payload = [0; 1024];
let payload = vec![0; 1024];
let mock = mock_io::Builder::new()
.handshake()
@@ -55,7 +55,7 @@ async fn single_stream_send_large_body() {
assert_eq!(stream.capacity(), payload.len());
// Send the data
stream.send_data(payload[..].into(), true).unwrap();
stream.send_data(payload.into(), true).unwrap();
// Get the response
let resp = h2.run(response).await.unwrap();
@@ -116,7 +116,7 @@ async fn multiple_streams_with_payload_greater_than_default_window() {
stream3.reserve_capacity(payload_clone.len());
assert_eq!(stream3.capacity(), 0);
stream1.send_data(payload_clone[..].into(), true).unwrap();
stream1.send_data(payload_clone.into(), true).unwrap();
// hold onto streams so they don't close
// stream1 doesn't close because response1 is used

View File

@@ -45,7 +45,7 @@ async fn recv_push_works() {
assert_eq!(request.into_parts().0.method, Method::GET);
let resp = response.await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let b = resp.into_body().try_concat().await.unwrap();
let b = util::concat(resp.into_body()).await.unwrap();
assert_eq!(b, "promised_data");
Ok(())
}

View File

@@ -1,7 +1,7 @@
#![deny(warnings)]
use futures::future::{join, poll_fn};
use futures::{StreamExt, TryStreamExt};
use futures::StreamExt;
use h2_support::prelude::*;
use tokio::io::AsyncWriteExt;
@@ -526,7 +526,7 @@ async fn abrupt_shutdown() {
let (req, tx) = srv.next().await.unwrap().expect("server receives request");
let req_fut = async move {
let body = req.into_body().try_concat().await;
let body = util::concat(req.into_body()).await;
drop(tx);
let err = body.expect_err("request body should error");
assert_eq!(
@@ -608,7 +608,7 @@ async fn graceful_shutdown() {
let body = req.into_parts().1;
let body = async move {
let buf = body.try_concat().await.unwrap();
let buf = util::concat(body).await.unwrap();
assert!(buf.is_empty());
let rsp = http::Response::builder().status(200).body(()).unwrap();

View File

@@ -5,6 +5,7 @@ use futures::{FutureExt, StreamExt, TryStreamExt};
use h2_support::prelude::*;
use h2_support::util::yield_once;
use std::task::Poll;
use tokio::sync::oneshot;
#[tokio::test]
async fn send_recv_headers_only() {
@@ -80,7 +81,7 @@ async fn send_recv_data() {
assert_eq!(stream.capacity(), 5);
// Send the data
stream.send_data("hello", true).unwrap();
stream.send_data("hello".as_bytes(), true).unwrap();
// Get the response
let resp = h2.run(response).await.unwrap();
@@ -204,7 +205,7 @@ async fn errors_if_recv_frame_exceeds_max_frame_size() {
let resp = client.get("https://example.com/").await.expect("response");
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
let res = body.try_concat().await;
let res = util::concat(body).await;
let err = res.unwrap_err();
assert_eq!(err.to_string(), "protocol error: frame with invalid size");
};
@@ -252,7 +253,7 @@ async fn configure_max_frame_size() {
let resp = client.get("https://example.com/").await.expect("response");
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
let buf = body.try_concat().await.expect("body");
let buf = util::concat(body).await.expect("body");
assert_eq!(buf.len(), 16_385);
};
@@ -313,7 +314,7 @@ async fn recv_goaway_finishes_processed_streams() {
.expect("response");
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_parts().1;
let buf = body.try_concat().await.expect("body");
let buf = util::concat(body).await.expect("body");
assert_eq!(buf.len(), 16_384);
};
@@ -702,7 +703,7 @@ async fn rst_while_closing() {
let (io, mut srv) = mock::new();
// Rendevous when we've queued a trailers frame
let (tx, rx) = crate::futures::channel::oneshot::channel();
let (tx, rx) = oneshot::channel();
let srv = async move {
let settings = srv.assert_client_handshake().await;
@@ -765,7 +766,7 @@ async fn rst_with_buffered_data() {
let (io, mut srv) = mock::new_with_write_capacity(73);
// Synchronize the client / server on response
let (tx, rx) = crate::futures::channel::oneshot::channel();
let (tx, rx) = oneshot::channel();
let srv = async move {
let settings = srv.assert_client_handshake().await;
@@ -817,7 +818,7 @@ async fn err_with_buffered_data() {
let (io, mut srv) = mock::new_with_write_capacity(73);
// Synchronize the client / server on response
let (tx, rx) = crate::futures::channel::oneshot::channel();
let (tx, rx) = oneshot::channel();
let srv = async move {
let settings = srv.assert_client_handshake().await;
@@ -872,7 +873,7 @@ async fn send_err_with_buffered_data() {
let (io, mut srv) = mock::new_with_write_capacity(73);
// Synchronize the client / server on response
let (tx, rx) = crate::futures::channel::oneshot::channel();
let (tx, rx) = oneshot::channel();
let srv = async move {
let settings = srv.assert_client_handshake().await;