diff --git a/tests-integration/Cargo.toml b/tests-integration/Cargo.toml index 82cdd4b24d6..5daeed08afd 100644 --- a/tests-integration/Cargo.toml +++ b/tests-integration/Cargo.toml @@ -58,3 +58,4 @@ tokio = { path = "../tokio" } tokio-test = { path = "../tokio-test", optional = true } doc-comment = "0.3.1" futures = { version = "0.3.0", features = ["async-await"] } +bytes = "1.0.0" diff --git a/tests-integration/tests/process_stdio.rs b/tests-integration/tests/process_stdio.rs index 3f8ebfbfaa9..cc7add40504 100644 --- a/tests-integration/tests/process_stdio.rs +++ b/tests-integration/tests/process_stdio.rs @@ -190,3 +190,54 @@ async fn pipe_from_one_command_to_another() { assert!(second_status.expect("second status").success()); assert!(third_status.expect("third status").success()); } + +#[tokio::test] +async fn vectored_writes() { + use bytes::{Buf, Bytes}; + use std::{io::IoSlice, pin::Pin}; + use tokio::io::AsyncWrite; + + let mut cat = cat().spawn().unwrap(); + let mut stdin = cat.stdin.take().unwrap(); + let mut stdout = cat.stdout.take().unwrap(); + + let write = async { + let mut input = Bytes::from_static(b"hello\n").chain(Bytes::from_static(b"world!\n")); + let mut writes_completed = 0; + + futures::future::poll_fn(|cx| loop { + let mut slices = [IoSlice::new(&[]); 2]; + let vectored = input.chunks_vectored(&mut slices); + if vectored == 0 { + return std::task::Poll::Ready(std::io::Result::Ok(())); + } + let n = futures::ready!(Pin::new(&mut stdin).poll_write_vectored(cx, &slices))?; + writes_completed += 1; + input.advance(n); + }) + .await?; + + drop(stdin); + + std::io::Result::Ok(writes_completed) + }; + + let read = async { + let mut buffer = Vec::with_capacity(6 + 7); + stdout.read_to_end(&mut buffer).await?; + std::io::Result::Ok(buffer) + }; + + let (write, read, status) = future::join3(write, read, cat.wait()).await; + + assert!(status.unwrap().success()); + + let writes_completed = write.unwrap(); + // on unix our small payload should always fit in whatever default sized pipe with a single + // syscall. if multiple are used, then the forwarding does not work, or we are on a platform + // for which the `std` does not support vectored writes. + #[cfg(target_family = "unix")] + assert_eq!(writes_completed, 1); + + assert_eq!(&read.unwrap(), b"hello\nworld!\n"); +}