diff options
Diffstat (limited to 'tests/pipe.rs')
-rw-r--r-- | tests/pipe.rs | 131 |
1 files changed, 86 insertions, 45 deletions
diff --git a/tests/pipe.rs b/tests/pipe.rs index 1bf49f2..e09334b 100644 --- a/tests/pipe.rs +++ b/tests/pipe.rs @@ -2,7 +2,8 @@ fn test_pipe_basic() { use std::os::unix::io::FromRawFd as _; - let (read_fd, write_fd) = nix::unistd::pipe().unwrap(); + let (read_fd, write_fd) = + nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); let mut child_from = std::process::Command::new("seq"); child_from.args(["1", "10"]); @@ -13,56 +14,96 @@ fn test_pipe_basic() { child_to.stdout(std::process::Stdio::piped()); assert!(child_from.status().unwrap().success()); - nix::unistd::close(write_fd).unwrap(); + drop(child_from); let output = child_to.output().unwrap(); assert!(output.status.success()); assert_eq!(output.stdout, b"10\n9\n8\n7\n6\n5\n4\n3\n2\n1\n"); } -#[cfg(feature = "todo")] -// TODO (hangs because i'm still overriding the configured fds) -// #[test] +#[test] +fn test_pipe_blocking() { + use std::io::Read as _; + use std::os::unix::io::FromRawFd as _; + + let (read_fd, write_fd) = + nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + + let pty_from = pty_process::blocking::Pty::new().unwrap(); + let pts_from = pty_from.pts().unwrap(); + pty_from.resize(pty_process::Size::new(24, 80)).unwrap(); + let mut cmd_from = pty_process::blocking::Command::new("seq"); + cmd_from.args(["1", "10"]); + cmd_from.stdout(unsafe { std::process::Stdio::from_raw_fd(write_fd) }); + let mut child_from = cmd_from.spawn(&pts_from).unwrap(); + + let mut pty_to = pty_process::blocking::Pty::new().unwrap(); + let pts_to = pty_to.pts().unwrap(); + let mut cmd_to = pty_process::blocking::Command::new("tac"); + cmd_to.stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); + let mut child_to = cmd_to.spawn(&pts_to).unwrap(); + + assert!(child_from.wait().unwrap().success()); + drop(cmd_from); + + // wait for the `tac` process to finish generating output (we don't really + // have a good way to detect when that happens) + std::thread::sleep(std::time::Duration::from_millis(100)); + + let mut buf = [0u8; 1024]; + let bytes = pty_to.read(&mut buf).unwrap(); + assert_eq!( + &buf[..bytes], + b"10\r\n9\r\n8\r\n7\r\n6\r\n5\r\n4\r\n3\r\n2\r\n1\r\n" + ); + + assert!(child_to.wait().unwrap().success()); +} + +#[cfg(feature = "async")] +#[test] fn test_pipe_async() { - use async_std::io::ReadExt as _; use std::os::unix::io::FromRawFd as _; + use tokio::io::AsyncReadExt as _; + + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + let (read_fd, write_fd) = + nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + + let pty_from = pty_process::Pty::new().unwrap(); + let pts_from = pty_from.pts().unwrap(); + pty_from.resize(pty_process::Size::new(24, 80)).unwrap(); + let mut cmd_from = pty_process::Command::new("seq"); + cmd_from.args(["1", "10"]); + cmd_from.stdout(unsafe { + std::process::Stdio::from_raw_fd(write_fd) + }); + let mut child_from = cmd_from.spawn(&pts_from).unwrap(); + + let mut pty_to = pty_process::Pty::new().unwrap(); + let pts_to = pty_to.pts().unwrap(); + let mut cmd_to = pty_process::Command::new("tac"); + cmd_to + .stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); + let mut child_to = cmd_to.spawn(&pts_to).unwrap(); + + assert!(child_from.wait().await.unwrap().success()); + drop(cmd_from); + + // wait for the `tac` process to finish generating output (we + // don't really have a good way to detect when that happens) + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + + let mut buf = [0u8; 1024]; + let bytes = pty_to.read(&mut buf).await.unwrap(); + assert_eq!( + &buf[..bytes], + b"10\r\n9\r\n8\r\n7\r\n6\r\n5\r\n4\r\n3\r\n2\r\n1\r\n" + ); - let (status_from, status_to) = async_std::task::block_on(async { - let (read_fd, write_fd) = nix::unistd::pipe().unwrap(); - - let pty_from = pty_process::async_std::Pty::new().unwrap(); - pty_from.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut cmd_from = pty_process::async_std::Command::new("seq"); - cmd_from.args(["1", "10"]); - cmd_from - .stdout(unsafe { std::process::Stdio::from_raw_fd(write_fd) }); - let mut child_from = cmd_from.spawn(pty_from).unwrap(); - - let pty_to = pty_process::async_std::Pty::new().unwrap(); - pty_to.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut cmd_to = pty_process::async_std::Command::new("tac"); - cmd_to.stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); - let mut child_to = cmd_to.spawn(pty_to).unwrap(); - - // the pty will echo the written bytes back immediately, but the - // subprocess needs to generate its own output, which takes time, so - // we can't just read immediately (we may just get the echoed bytes). - // because the output generation is happening in the subprocess, we - // also don't have any way to know when (or if!) the subprocess will - // decide to send its output, so sleeping is the best we can do. - async_std::task::sleep(std::time::Duration::from_secs(1)).await; - - let mut buf = [0u8; 1024]; - let bytes = child_to.pty().read(&mut buf).await.unwrap(); - assert_eq!( - &buf[..bytes], - b"10\r\n9\r\n8\r\n7\r\n6\r\n5\r\n4\r\n3\r\n2\r\n1\r\n" - ); - - ( - child_from.status().await.unwrap(), - child_to.status().await.unwrap(), - ) - }); - assert_eq!(status_from.code().unwrap(), 0); - assert_eq!(status_to.code().unwrap(), 0); + assert!(child_to.wait().await.unwrap().success()); + }); } |