From 6ec7f38cd7378a6d99ab4300a07763ab1722dcb4 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 19 Sep 2017 15:31:35 -0700 Subject: [PATCH] add test for client sending over max concurrent limit (#105) --- src/frame/settings.rs | 4 +++ tests/client_request.rs | 58 +++++++++++++++++++++++++++++++++++++ tests/support/src/frames.rs | 25 ++++++++++++++++ tests/support/src/mock.rs | 4 ++- 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/frame/settings.rs b/src/frame/settings.rs index f655a2f..b130f43 100644 --- a/src/frame/settings.rs +++ b/src/frame/settings.rs @@ -74,6 +74,10 @@ impl Settings { self.max_concurrent_streams } + pub fn set_max_concurrent_streams(&mut self, max: Option) { + self.max_concurrent_streams = max; + } + pub fn max_frame_size(&self) -> Option { self.max_frame_size } diff --git a/tests/client_request.rs b/tests/client_request.rs index ec4c721..5283453 100644 --- a/tests/client_request.rs +++ b/tests/client_request.rs @@ -111,6 +111,64 @@ fn request_stream_id_overflows() { h2.join(srv).wait().expect("wait"); } +#[test] +fn request_over_max_concurrent_streams_errors() { + let _ = ::env_logger::init(); + let (io, srv) = mock::new(); + + + let srv = srv.assert_client_handshake_with_settings( + frames::settings() + // super tiny server + .max_concurrent_streams(1) + ) + .unwrap() + .recv_settings() + .recv_frame( + frames::headers(1) + .request("POST", "https://example.com/") + ) + .send_frame(frames::headers(1).response(200)) + .close(); + + let h2 = Client::handshake(io) + .expect("handshake") + .and_then(|mut h2| { + let request = Request::builder() + .method(Method::POST) + .uri("https://example.com/") + .body(()) + .unwrap(); + + // first request is allowed + let req = h2.send_request(request, false) + .unwrap() + .unwrap(); + + // drive the connection some so we can receive the server settings + h2.drive(req) + }) + .and_then(|(mut h2, _)| { + + let request = Request::builder() + .method(Method::GET) + .uri("https://example.com/") + .body(()) + .unwrap(); + + // second stream is over max concurrent + assert!(h2.poll_ready().expect("poll_ready").is_not_ready()); + + let err = h2.send_request(request, true).unwrap_err(); + assert_eq!(err.to_string(), "user error: rejected"); + + h2.expect("h2") + }); + + + h2.join(srv).wait().expect("wait"); +} + #[test] #[ignore] fn request_without_scheme() {} diff --git a/tests/support/src/frames.rs b/tests/support/src/frames.rs index ba43e40..8890af8 100644 --- a/tests/support/src/frames.rs +++ b/tests/support/src/frames.rs @@ -58,6 +58,10 @@ pub fn reset(id: T) -> Mock Mock(frame::Reset::new(id.into(), frame::Reason::NoError)) } +pub fn settings() -> Mock { + Mock(frame::Settings::default()) +} + // === Generic helpers of all frame types pub struct Mock(T); @@ -230,6 +234,27 @@ impl From> for SendFrame { } } +// ==== Settings helpers + +impl Mock { + pub fn max_concurrent_streams(mut self, max: u32) -> Self { + self.0.set_max_concurrent_streams(Some(max)); + self + } +} + +impl From> for frame::Settings { + fn from(src: Mock) -> Self { + src.0 + } +} + +impl From> for SendFrame { + fn from(src: Mock) -> Self { + Frame::Settings(src.0) + } +} + // ==== "trait alias" for types that are HttpTryFrom and have Debug Errors ==== pub trait HttpTryInto { diff --git a/tests/support/src/mock.rs b/tests/support/src/mock.rs index 6bbc974..324baeb 100644 --- a/tests/support/src/mock.rs +++ b/tests/support/src/mock.rs @@ -113,9 +113,11 @@ impl Handle { } /// Perform the H2 handshake - pub fn assert_client_handshake_with_settings(mut self, settings: frame::Settings) + pub fn assert_client_handshake_with_settings(mut self, settings: T) -> Box> + where T: Into, { + let settings = settings.into(); // Send a settings frame self.send(settings.into()).unwrap();