use super::fixture::*;
use crate::{Headers, Method, Status, h2::frame::Frame, headers::hpack::PseudoHeaders};
use futures_lite::io::AsyncRead;
use std::{
pin::Pin,
task::{Context, Poll},
};
fn parks(fx: &mut DriverFixture) -> bool {
let waker = noop_waker();
fx.driver.park(&mut Context::from_waker(&waker))
}
#[test]
fn a_response_submitted_while_the_driver_sleeps_is_framed() {
let mut fx = DriverFixture::new_server();
fx.complete_handshake();
fx.peer_open_stream(1, Method::Get, "/", true);
let _conn = match fx.tick() {
Poll::Ready(Some(Ok(conn))) => conn,
other => panic!("expected Conn yielded for stream 1, got {other:?}"),
};
assert!(fx.tick().is_pending());
assert!(parks(&mut fx), "nothing has been submitted yet");
let pseudos = PseudoHeaders::default().with_status(Status::Ok);
let _submit = fx.connection.submit_send(1, pseudos, Headers::new(), None);
assert!(
!parks(&mut fx),
"a submitted response must keep the driver awake"
);
let _ = fx.tick();
let frames = fx.next_outbound_frames();
assert!(
frames.iter().any(|f| matches!(
f,
Frame::Headers {
stream_id: 1,
end_stream: true,
..
}
)),
"expected the response HEADERS(END_STREAM) on stream 1, got {frames:?}",
);
}
#[test]
fn a_ping_queued_while_the_driver_sleeps_is_sent() {
let mut fx = DriverFixture::new_server();
fx.complete_handshake();
assert!(fx.tick().is_pending());
let connection = fx.connection.clone();
let _ping = connection.send_ping(*b"pingpong");
assert!(!parks(&mut fx), "a queued PING must keep the driver awake");
let _ = fx.tick();
let frames = fx.next_outbound_frames();
assert!(
frames.iter().any(|f| matches!(
f,
Frame::Ping {
opaque_data,
ack: false,
} if opaque_data == b"pingpong"
)),
"expected the queued PING, got {frames:?}",
);
}
#[test]
fn a_client_stream_signaled_before_pickup_is_serviced_once() {
let mut fx = DriverFixture::new_client();
fx.complete_handshake_client();
let pseudos = PseudoHeaders::default()
.with_method(Method::Get)
.with_path("/")
.with_scheme("http")
.with_authority("test");
let (id, _submit, mut transport) = fx
.connection
.open_stream(pseudos, Headers::new(), None)
.expect("open_stream on a running client connection");
let waker = noop_waker();
let mut buf = [0; 8];
assert!(
Pin::new(&mut transport)
.poll_read(&mut Context::from_waker(&waker), &mut buf)
.is_pending(),
"no response yet",
);
assert!(!parks(&mut fx), "a new stream must keep the driver awake");
let _ = fx.tick();
let frames = fx.next_outbound_frames();
let headers = frames
.iter()
.filter(|f| matches!(f, Frame::Headers { stream_id, .. } if *stream_id == id))
.count();
assert_eq!(headers, 1, "request HEADERS framed once; got {frames:?}");
assert!(
frames
.iter()
.any(|f| matches!(f, Frame::WindowUpdate { stream_id, .. } if *stream_id == id)),
"read intent should raise stream {id}'s window; got {frames:?}",
);
}