Add trailing metadata and fix test

This commit is contained in:
Lucio Franco
2019-08-28 20:09:43 -04:00
parent f750dfa111
commit bfab56d42d
4 changed files with 54 additions and 28 deletions
+10 -2
View File
@@ -418,6 +418,7 @@ pub async fn custom_metadata(client: &mut Client, assertions: &mut Vec<TestAsser
// format!("result={:?}", response.metadata().get_bin(key1)) // format!("result={:?}", response.metadata().get_bin(key1))
// )); // ));
let response = client let response = client
.full_duplex_call(req_stream) .full_duplex_call(req_stream)
.await .await
@@ -428,10 +429,17 @@ pub async fn custom_metadata(client: &mut Client, assertions: &mut Vec<TestAsser
response.metadata().get(key1) == Some(&value1), response.metadata().get(key1) == Some(&value1),
format!("result={:?}", response.metadata().get(key1)) format!("result={:?}", response.metadata().get(key1))
)); ));
let mut stream = response.into_inner();
// while let Some(_) = stream.next().await {}
let trailers = stream.trailers().await.unwrap().unwrap();
assertions.push(test_assert!( assertions.push(test_assert!(
"metadata bin must match in unary", "metadata bin must match in unary",
response.metadata().get_bin(key2) == Some(&value2), trailers.get_bin(key2) == Some(&value2),
format!("result={:?}", response.metadata().get_bin(key1)) format!("result={:?}", trailers.get_bin(key1))
)); ));
} }
+1 -3
View File
@@ -1,6 +1,4 @@
cargo run -p tonic-interop --bin client -- \ cargo run -p tonic-interop --bin client -- \
--test_case=empty_unary,large_unary,client_streaming,server_streaming,ping_pong,\ --test_case=empty_unary,large_unary,client_streaming,server_streaming,ping_pong,\
empty_stream,status_code_and_message,special_status_message,unimplemented_method,\ empty_stream,status_code_and_message,special_status_message,unimplemented_method,\
unimplemented_service unimplemented_service,custom_metadata
# DISABLED: ,custom_metadata
+42 -22
View File
@@ -19,6 +19,7 @@ pub struct Streaming<T> {
state: State, state: State,
direction: Direction, direction: Direction,
buf: BytesMut, buf: BytesMut,
trailers: Option<MetadataMap>,
} }
impl<T> Unpin for Streaming<T> {} impl<T> Unpin for Streaming<T> {}
@@ -44,14 +45,7 @@ impl<T> Streaming<T> {
B::Error: Into<crate::Error>, B::Error: Into<crate::Error>,
D: Decoder<Item = T, Error = Status> + Send + 'static, D: Decoder<Item = T, Error = Status> + Send + 'static,
{ {
Self { Self::new(decoder, body, Direction::Response(status_code))
decoder: Box::new(decoder),
body: BoxBody::map_from(body),
state: State::ReadHeader,
direction: Direction::Response(status_code),
// FIXME: update this with a reasonable size
buf: BytesMut::with_capacity(1024 * 1024),
}
} }
pub fn new_empty<B, D>(decoder: D, body: B) -> Self pub fn new_empty<B, D>(decoder: D, body: B) -> Self
@@ -61,17 +55,19 @@ impl<T> Streaming<T> {
B::Error: Into<crate::Error>, B::Error: Into<crate::Error>,
D: Decoder<Item = T, Error = Status> + Send + 'static, D: Decoder<Item = T, Error = Status> + Send + 'static,
{ {
Self { Self::new(decoder, body, Direction::EmptyResponse)
decoder: Box::new(decoder),
body: BoxBody::map_from(body),
state: State::ReadHeader,
direction: Direction::EmptyResponse,
// FIXME: update this with a reasonable size
buf: BytesMut::with_capacity(1024 * 1024),
}
} }
pub fn new_request<B, D>(decoder: D, body: B) -> Self pub fn new_request<B, D>(decoder: D, body: B) -> Self
where
B: Body + Send + 'static,
B::Data: Into<Bytes>,
B::Error: Into<crate::Error>,
D: Decoder<Item = T, Error = Status> + Send + 'static,
{
Self::new(decoder, body, Direction::Request)
}
fn new<B, D>(decoder: D, body: B, direction: Direction) -> Self
where where
B: Body + Send + 'static, B: Body + Send + 'static,
B::Data: Into<Bytes>, B::Data: Into<Bytes>,
@@ -82,23 +78,45 @@ impl<T> Streaming<T> {
decoder: Box::new(decoder), decoder: Box::new(decoder),
body: BoxBody::map_from(body), body: BoxBody::map_from(body),
state: State::ReadHeader, state: State::ReadHeader,
direction: Direction::Request, direction,
// FIXME: update this with a reasonable size // FIXME: update this with a reasonable size
buf: BytesMut::with_capacity(1024 * 1024), buf: BytesMut::with_capacity(1024 * 1024),
trailers: None,
} }
} }
} }
impl<T> Streaming<T> { impl<T> Streaming<T> {
// pub async fn message(&mut self) -> Option<Result<T::Item, Status>> { pub async fn message(&mut self) -> Option<Result<T, Status>> {
// future::poll_fn(|cx| Pin::new(&mut *self).poll_next(cx)).await future::poll_fn(|cx| Pin::new(&mut *self).poll_next(cx)).await
// } }
pub async fn trailers(&mut self) -> Result<Option<MetadataMap>, Status> { pub async fn trailers(mut self) -> Result<Option<MetadataMap>, Status> {
// Shortcut to see if we already pulled the trailers in the stream step
// we need to do that so that the stream can error on trailing grpc-status
if let Some(trailers) = self.trailers {
return Ok(Some(trailers));
}
// To fetch the trailers we must clear the body and drop it.
while let Some(res) = self.message().await {
res?;
}
// Since we call poll_trailers internally on poll_next we need to
// check if it got cached again.
if let Some(trailers) = self.trailers {
return Ok(Some(trailers));
}
// Trailers were not caught during poll_next and thus lets poll for
// them manually.
let map = let map =
future::poll_fn(|cx| unsafe { Pin::new_unchecked(&mut self.body) }.poll_trailers(cx)) future::poll_fn(|cx| unsafe { Pin::new_unchecked(&mut self.body) }.poll_trailers(cx))
.await .await
.map_err(|e| Status::from_error(&e))?; .map_err(|e| Status::from_error(&e))?;
Ok(map.map(MetadataMap::from_headers)) Ok(map.map(MetadataMap::from_headers))
} }
@@ -205,8 +223,10 @@ impl<T> Stream for Streaming<T> {
if let Direction::Response(status) = self.direction { if let Direction::Response(status) = self.direction {
match ready!(unsafe { Pin::new_unchecked(&mut self.body) }.poll_trailers(cx)) { match ready!(unsafe { Pin::new_unchecked(&mut self.body) }.poll_trailers(cx)) {
Ok(trailer) => { Ok(trailer) => {
if let Err(e) = crate::status::infer_grpc_status(trailer, status) { if let Err(e) = crate::status::infer_grpc_status(trailer.as_ref(), status) {
return Some(Err(e)).into(); return Some(Err(e)).into();
} else {
self.trailers = trailer.map(MetadataMap::from_headers);
} }
} }
Err(e) => { Err(e) => {
+1 -1
View File
@@ -312,7 +312,7 @@ impl Error for Status {}
/// Take the `Status` value from `trailers` if it is available, else from `status_code`. /// Take the `Status` value from `trailers` if it is available, else from `status_code`.
/// ///
pub(crate) fn infer_grpc_status( pub(crate) fn infer_grpc_status(
trailers: Option<HeaderMap>, trailers: Option<&HeaderMap>,
status_code: http::StatusCode, status_code: http::StatusCode,
) -> Result<(), Status> { ) -> Result<(), Status> {
if let Some(trailers) = trailers { if let Some(trailers) = trailers {