From 1895e6ca5338756bb3c8879ab3f6427ee476670a Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 3 Dec 2023 02:00:32 -0500 Subject: wip --- .github/workflows/tests.yaml | 12 ++++++------ src/pty.rs | 5 +++-- tests/basic.rs | 27 +++++++++++++++++---------- tests/behavior.rs | 33 ++++++++++++++++++++++++--------- tests/fds_async.rs | 11 +++++++---- tests/pipe.rs | 21 +++++++++++++++------ tests/split.rs | 24 ++++++++++++++---------- tests/winch.rs | 40 ++++++++++++++++++++++------------------ 8 files changed, 108 insertions(+), 65 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 5358d9e..4ac17d2 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo build --all-targets + - run: cargo build --all-targets --all-features build-musl: runs-on: ubuntu-latest steps: @@ -20,19 +20,19 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-musl - - run: TARGET_CC=clang-11 TARGET_AR=llvm-ar-11 cargo build --all-targets --target x86_64-unknown-linux-musl + - run: TARGET_CC=clang-11 TARGET_AR=llvm-ar-11 cargo build --all-targets --all-features --target x86_64-unknown-linux-musl build-macos: runs-on: macos-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo build --all-targets + - run: cargo build --all-targets --all-features test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo test + - run: cargo test --all-targets --all-features test-musl: runs-on: ubuntu-latest steps: @@ -41,13 +41,13 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-musl - - run: TARGET_CC=clang-11 TARGET_AR=llvm-ar-11 cargo test --target x86_64-unknown-linux-musl + - run: TARGET_CC=clang-11 TARGET_AR=llvm-ar-11 cargo test --target x86_64-unknown-linux-musl --all-targets --all-features test-macos: runs-on: macos-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo test + - run: cargo test --all-targets --all-features lint: runs-on: ubuntu-latest steps: diff --git a/src/pty.rs b/src/pty.rs index c9cac2c..b9b56ef 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -15,7 +15,6 @@ impl Pty { /// unable to put it into non-blocking mode. pub fn new() -> crate::Result { let pty = crate::sys::Pty::open()?; - pty.set_nonblocking()?; Ok(Self(tokio::io::unix::AsyncFd::new(pty)?)) } @@ -35,7 +34,9 @@ impl Pty { /// Returns an error if the device node to open could not be determined, /// or if the device node could not be opened. pub fn pts(&self) -> crate::Result { - Ok(Pts(self.0.get_ref().pts()?)) + let pts = Pts(self.0.get_ref().pts()?); + self.0.get_ref().set_nonblocking()?; + Ok(pts) } /// Splits a `Pty` into a read half and a write half, which can be used to diff --git a/tests/basic.rs b/tests/basic.rs index f6faa2e..55fdb24 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -5,10 +5,13 @@ fn test_cat_blocking() { use std::io::Write as _; let mut pty = pty_process::blocking::Pty::new().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut child = pty_process::blocking::Command::new("cat") - .spawn(&pty.pts().unwrap()) - .unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::blocking::Command::new("cat") + .spawn(&pts) + .unwrap() + }; pty.write_all(b"foo\n").unwrap(); @@ -28,9 +31,11 @@ async fn test_cat_async() { use tokio::io::AsyncWriteExt as _; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut child = pty_process::Command::new("cat").spawn(&pts).unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::Command::new("cat").spawn(&pts).unwrap() + }; let (pty_r, mut pty_w) = pty.split(); @@ -51,9 +56,11 @@ async fn test_yes_async() { use tokio::io::AsyncReadExt as _; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut child = pty_process::Command::new("yes").spawn(&pts).unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::Command::new("yes").spawn(&pts).unwrap() + }; let mut buf = [0u8; 3]; diff --git a/tests/behavior.rs b/tests/behavior.rs index 8712643..cbd5066 100644 --- a/tests/behavior.rs +++ b/tests/behavior.rs @@ -1,5 +1,8 @@ mod helpers; +// macos doesn't appear to support spawning a second process onto a pty which +// already had a process spawned onto it +#[cfg(not(target_os = "macos"))] #[test] fn test_multiple() { let pty = pty_process::blocking::Pty::new().unwrap(); @@ -28,6 +31,9 @@ fn test_multiple() { assert_eq!(status.code().unwrap(), 0); } +// macos doesn't appear to support spawning a second process onto a pty which +// already had a process spawned onto it +#[cfg(not(target_os = "macos"))] #[cfg(feature = "async")] #[tokio::test] async fn test_multiple_async() { @@ -60,6 +66,9 @@ async fn test_multiple_async() { assert_eq!(status.code().unwrap(), 0); } +// macos doesn't appear to support spawning a second process onto a pty which +// already had a process spawned onto it +#[cfg(not(target_os = "macos"))] #[test] fn test_multiple_configured() { use std::io::BufRead as _; @@ -129,6 +138,9 @@ fn test_multiple_configured() { assert_eq!(status.code().unwrap(), 0); } +// macos doesn't appear to support spawning a second process onto a pty which +// already had a process spawned onto it +#[cfg(not(target_os = "macos"))] #[cfg(feature = "async")] #[tokio::test] async fn test_multiple_configured_async() { @@ -246,16 +258,18 @@ async fn test_controlling_terminal_async() { use futures::stream::StreamExt as _; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::Command::new("perl") + .arg( + "-Eopen my $fh, '<', '/dev/tty' or die; \ + if (-t $fh) { say 'true' } else { say 'false' }", + ) + .spawn(&pts) + .unwrap() + }; let (pty_r, _) = pty.split(); - let mut child = pty_process::Command::new("perl") - .arg( - "-Eopen my $fh, '<', '/dev/tty' or die; \ - if (-t $fh) { say 'true' } else { say 'false' }", - ) - .spawn(&pts) - .unwrap(); let mut output = helpers::output_async(pty_r); assert_eq!(output.next().await.unwrap(), "true\r\n"); @@ -303,6 +317,7 @@ async fn test_session_leader_async() { assert_eq!(status.code().unwrap(), 0); } +#[cfg(not(target_os = "macos"))] fn pipe() -> (std::os::fd::OwnedFd, std::os::fd::OwnedFd) { use std::os::fd::FromRawFd as _; diff --git a/tests/fds_async.rs b/tests/fds_async.rs index 6f3bcde..c9bff62 100644 --- a/tests/fds_async.rs +++ b/tests/fds_async.rs @@ -5,7 +5,10 @@ mod helpers; fn test_fds_async() { use futures::stream::StreamExt as _; - check_open_fds(&[0, 1, 2]); + let mut expected = String::new(); + for fd in get_open_fds() { + expected.push_str(&format!("{}", fd)); + } let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() @@ -31,7 +34,7 @@ fn test_fds_async() { let (pty_r, _) = pty.split(); let mut output = helpers::output_async(pty_r); - assert_eq!(output.next().await.unwrap(), "012\r\n"); + assert_eq!(output.next().await.unwrap(), format!("{expected}\r\n")); let status = child.wait().await.unwrap(); assert_eq!(status.code().unwrap(), 0); @@ -56,7 +59,7 @@ fn test_fds_async() { let (pty_r, _) = pty.split(); let mut output = helpers::output_async(pty_r); - assert_eq!(output.next().await.unwrap(), "012\r\n"); + assert_eq!(output.next().await.unwrap(), format!("{expected}\r\n")); let status = child.wait().await.unwrap(); assert_eq!(status.code().unwrap(), 0); @@ -81,7 +84,7 @@ fn test_fds_async() { let (pty_r, _) = pty.split(); let mut output = helpers::output_async(pty_r); - assert_eq!(output.next().await.unwrap(), "012\r\n"); + assert_eq!(output.next().await.unwrap(), format!("{expected}\r\n")); let status = child.wait().await.unwrap(); assert_eq!(status.code().unwrap(), 0); diff --git a/tests/pipe.rs b/tests/pipe.rs index da2e1b0..de8c875 100644 --- a/tests/pipe.rs +++ b/tests/pipe.rs @@ -6,7 +6,10 @@ fn test_pipe_basic() { child_from.args(["1", "10"]); child_from.stdout(std::process::Stdio::from(write_fd)); - let mut child_to = std::process::Command::new("tac"); + let mut child_to = std::process::Command::new("perl"); + child_to + .arg("-nle") + .arg("unshift @a, $_; END { print for @a }"); child_to.stdin(std::process::Stdio::from(read_fd)); child_to.stdout(std::process::Stdio::piped()); @@ -33,15 +36,18 @@ fn test_pipe_blocking() { 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"); + let mut cmd_to = pty_process::blocking::Command::new("perl"); + cmd_to + .arg("-nle") + .arg("unshift @a, $_; END { print for @a }"); cmd_to.stdin(std::process::Stdio::from(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) + // wait for the `perl` 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]; @@ -71,14 +77,17 @@ async fn test_pipe_async() { 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"); + let mut cmd_to = pty_process::Command::new("perl"); + cmd_to + .arg("-nle") + .arg("unshift @a, $_; END { print for @a }"); cmd_to.stdin(std::process::Stdio::from(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 + // wait for the `perl` 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; diff --git a/tests/split.rs b/tests/split.rs index 4799c13..008e601 100644 --- a/tests/split.rs +++ b/tests/split.rs @@ -7,11 +7,13 @@ async fn test_split() { use tokio::io::AsyncWriteExt as _; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut cmd = pty_process::Command::new("perl"); - cmd.args(["-plE", "BEGIN { $SIG{WINCH} = sub { say 'WINCH' } }"]); - let mut child = cmd.spawn(&pts).unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + let mut cmd = pty_process::Command::new("perl"); + cmd.args(["-plE", "BEGIN { $SIG{WINCH} = sub { say 'WINCH' } }"]); + cmd.spawn(&pts).unwrap() + }; { pty.write_all(b"foo\n").await.unwrap(); @@ -46,11 +48,13 @@ async fn test_into_split() { use tokio::io::{AsyncBufReadExt as _, AsyncWriteExt as _}; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut cmd = pty_process::Command::new("perl"); - cmd.args(["-plE", "BEGIN { $SIG{WINCH} = sub { say 'WINCH' } }"]); - let mut child = cmd.spawn(&pts).unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + let mut cmd = pty_process::Command::new("perl"); + cmd.args(["-plE", "BEGIN { $SIG{WINCH} = sub { say 'WINCH' } }"]); + cmd.spawn(&pts).unwrap() + }; { pty.write_all(b"foo\n").await.unwrap(); diff --git a/tests/winch.rs b/tests/winch.rs index d97e9aa..4256b0d 100644 --- a/tests/winch.rs +++ b/tests/winch.rs @@ -5,15 +5,17 @@ fn test_winch_std() { use std::io::Write as _; let mut pty = pty_process::blocking::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut child = pty_process::blocking::Command::new("perl") - .args([ - "-E", - "$|++; $SIG{WINCH} = sub { say 'WINCH' }; say 'started'; <>", - ]) - .spawn(&pts) - .unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::blocking::Command::new("perl") + .args([ + "-E", + "$|++; $SIG{WINCH} = sub { say 'WINCH' }; say 'started'; <>", + ]) + .spawn(&pts) + .unwrap() + }; let mut output = helpers::output(&pty); assert_eq!(output.next().unwrap(), "started\r\n"); @@ -33,15 +35,17 @@ async fn test_winch_async() { use tokio::io::AsyncWriteExt as _; let mut pty = pty_process::Pty::new().unwrap(); - let pts = pty.pts().unwrap(); - pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let mut child = pty_process::Command::new("perl") - .args(&[ - "-E", - "$|++; $SIG{WINCH} = sub { say 'WINCH' }; say 'started'; <>", - ]) - .spawn(&pts) - .unwrap(); + let mut child = { + let pts = pty.pts().unwrap(); + pty.resize(pty_process::Size::new(24, 80)).unwrap(); + pty_process::Command::new("perl") + .args([ + "-E", + "$|++; $SIG{WINCH} = sub { say 'WINCH' }; say 'started'; <>", + ]) + .spawn(&pts) + .unwrap() + }; let (pty_r, mut pty_w) = pty.split(); let mut output = helpers::output_async(pty_r); -- cgit v1.2.3-54-g00ecf