feat(codec): compression support (#692)
* Initial compression support * Support configuring compression on `Server` * Minor clean up * Test that compression is actually happening * Clean up some todos * channels compressing requests * Move compression to be on the codecs * Test sending compressed request to server that doesn't support it * Clean up a bit * Compress server streams * Compress client streams * Bidirectional streaming compression * Handle receiving unsupported encoding * Clean up * Add note to future self * Support disabling compression for individual responses * Add docs * Add compression examples * Disable compression behind feature flag * Add some docs * Make flate2 optional dependency * Fix docs wording * Format * Reply with which encodings are supported * Convert tests to use mocked io * Fix lints * Use separate counters * Don't make a long stream * Address review feedback
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
use super::*;
|
||||
use tonic::Streaming;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn client_enabled_server_enabled() {
|
||||
let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);
|
||||
|
||||
let svc = test_server::TestServer::new(Svc::default()).send_gzip();
|
||||
|
||||
let response_bytes_counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
tokio::spawn({
|
||||
let response_bytes_counter = response_bytes_counter.clone();
|
||||
async move {
|
||||
Server::builder()
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(MapResponseBodyLayer::new(move |body| {
|
||||
util::CountBytesBody {
|
||||
inner: body,
|
||||
counter: response_bytes_counter.clone(),
|
||||
}
|
||||
}))
|
||||
.into_inner(),
|
||||
)
|
||||
.add_service(svc)
|
||||
.serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(
|
||||
MockStream(server),
|
||||
)]))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let mut client = test_client::TestClient::new(mock_io_channel(client).await).accept_gzip();
|
||||
|
||||
let res = client.compress_output_server_stream(()).await.unwrap();
|
||||
|
||||
assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip");
|
||||
|
||||
let mut stream: Streaming<SomeData> = res.into_inner();
|
||||
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.expect("stream empty")
|
||||
.expect("item was error");
|
||||
assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);
|
||||
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.expect("stream empty")
|
||||
.expect("item was error");
|
||||
assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn client_disabled_server_enabled() {
|
||||
let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);
|
||||
|
||||
let svc = test_server::TestServer::new(Svc::default()).send_gzip();
|
||||
|
||||
let response_bytes_counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
tokio::spawn({
|
||||
let response_bytes_counter = response_bytes_counter.clone();
|
||||
async move {
|
||||
Server::builder()
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(MapResponseBodyLayer::new(move |body| {
|
||||
util::CountBytesBody {
|
||||
inner: body,
|
||||
counter: response_bytes_counter.clone(),
|
||||
}
|
||||
}))
|
||||
.into_inner(),
|
||||
)
|
||||
.add_service(svc)
|
||||
.serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(
|
||||
MockStream(server),
|
||||
)]))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let mut client = test_client::TestClient::new(mock_io_channel(client).await);
|
||||
|
||||
let res = client.compress_output_server_stream(()).await.unwrap();
|
||||
|
||||
assert!(res.metadata().get("grpc-encoding").is_none());
|
||||
|
||||
let mut stream: Streaming<SomeData> = res.into_inner();
|
||||
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.expect("stream empty")
|
||||
.expect("item was error");
|
||||
assert!(response_bytes_counter.load(SeqCst) > UNCOMPRESSED_MIN_BODY_SIZE);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn client_enabled_server_disabled() {
|
||||
let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);
|
||||
|
||||
let svc = test_server::TestServer::new(Svc::default());
|
||||
|
||||
let response_bytes_counter = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
tokio::spawn({
|
||||
let response_bytes_counter = response_bytes_counter.clone();
|
||||
async move {
|
||||
Server::builder()
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(MapResponseBodyLayer::new(move |body| {
|
||||
util::CountBytesBody {
|
||||
inner: body,
|
||||
counter: response_bytes_counter.clone(),
|
||||
}
|
||||
}))
|
||||
.into_inner(),
|
||||
)
|
||||
.add_service(svc)
|
||||
.serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(
|
||||
MockStream(server),
|
||||
)]))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let mut client = test_client::TestClient::new(mock_io_channel(client).await).accept_gzip();
|
||||
|
||||
let res = client.compress_output_server_stream(()).await.unwrap();
|
||||
|
||||
assert!(res.metadata().get("grpc-encoding").is_none());
|
||||
|
||||
let mut stream: Streaming<SomeData> = res.into_inner();
|
||||
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.expect("stream empty")
|
||||
.expect("item was error");
|
||||
assert!(response_bytes_counter.load(SeqCst) > UNCOMPRESSED_MIN_BODY_SIZE);
|
||||
}
|
||||
Reference in New Issue
Block a user