Skip to content

Commit

Permalink
Add tests for _timeout methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Binlogo authored and matklad committed Dec 23, 2024
1 parent 60fb6cd commit 8ec06a6
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 5 deletions.
35 changes: 35 additions & 0 deletions examples/timeout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::time::Duration;

use anyhow::Result;
use xshell::{cmd, Shell};

fn main() -> Result<()> {
let sh = Shell::new()?;
let command = cmd!(sh, "sleep 5").timeout(Duration::from_secs(3));

// Run the command with a timeout
match command.run() {
Ok(_) => println!("Command completed successfully."),
Err(e) => eprintln!("Command failed: {}", e),
}

// Run the command with a timeout and get stdout
match command.read() {
Ok(output) => println!("Command output: {}", output),
Err(e) => eprintln!("Command failed: {}", e),
}

// Run the command with a timeout and get stderr
match command.read_stderr() {
Ok(output) => println!("Command stderr: {}", output),
Err(e) => eprintln!("Command failed: {}", e),
}

// Run the command with a timeout and get the full output
match command.output() {
Ok(output) => println!("Command completed successfully.{output:?}"),
Err(e) => eprintln!("Command failed: {}", e),
}

Ok(())
}
2 changes: 1 addition & 1 deletion src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use std::{
time::{Duration, Instant},
};

#[derive(Default)]
#[derive(Default, Debug)]
pub(crate) struct ExecResult {
pub(crate) stdout: Vec<u8>,
pub(crate) stderr: Vec<u8>,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ fn remove_dir_all(path: &Path) -> io::Result<()> {
if fs::remove_dir_all(path).is_ok() {
return Ok(());
}
std::thread::sleep(std::time::Duration::from_millis(10))
std::thread::xsleep(std::time::Duration::from_millis(10))
}
fs::remove_dir_all(path)
}
59 changes: 59 additions & 0 deletions tests/data/xsleep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::io::{self, Write};
use std::thread;
use std::time::Duration;

fn main() {
if let Err(err) = try_main() {
eprintln!("{err}");
std::process::exit(1);
}
}

fn try_main() -> io::Result<()> {
let mut sleep_seconds = 0;
let mut fail = false;
let mut suicide = false;

let mut args = std::env::args().skip(1).peekable();
while let Some(arg) = args.peek() {
match arg.as_str() {
"-f" => fail = true,
"-s" => suicide = true,
_ => break,
}
args.next();
}

if let Some(arg) = args.next() {
sleep_seconds = arg.parse().unwrap_or_else(|_| {
eprintln!("error: invalid number of seconds");
std::process::exit(1);
});
}

thread::sleep(Duration::from_secs(sleep_seconds));

if fail {
return Err(io::ErrorKind::Other.into());
}
if suicide {
#[cfg(unix)]
unsafe {
let pid = signals::getpid();
if pid > 0 {
signals::kill(pid, 9);
}
}
}

Ok(())
}

#[cfg(unix)]
mod signals {
use std::os::raw::c_int;
extern "C" {
pub fn kill(pid: c_int, sig: c_int) -> c_int;
pub fn getpid() -> c_int;
}
}
14 changes: 11 additions & 3 deletions tests/it/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod tidy;
mod env;
mod compile_failures;
mod timeout;

use std::{ffi::OsStr, path::Path};

Expand All @@ -11,12 +12,16 @@ fn setup() -> Shell {

let mut sh = Shell::new().unwrap();
let xecho_src = sh.current_dir().join("./tests/data/xecho.rs");
let xsleep_src = sh.current_dir().join("./tests/data/xsleep.rs");
let target_dir = sh.current_dir().join("./target/");

ONCE.call_once(|| {
cmd!(sh, "rustc {xecho_src} --out-dir {target_dir}")
.run()
.unwrap_or_else(|err| panic!("failed to install binaries from mock_bin: {}", err))
.unwrap_or_else(|err| panic!("failed to install binaries from mock_bin: {}", err));
cmd!(sh, "rustc {xsleep_src} --out-dir {target_dir}")
.run()
.unwrap_or_else(|err| panic!("failed to install binaries from mock_bin: {}", err));
});

sh.set_env_var("PATH", target_dir);
Expand Down Expand Up @@ -160,11 +165,14 @@ fn exit_status_signal() {
let sh = setup();

let err = cmd!(sh, "xecho -s").read().unwrap_err();
assert_eq!(err.to_string(), r#"command was terminated by a signal `xecho -s`: 9
assert_eq!(
err.to_string(),
r#"command was terminated by a signal `xecho -s`: 9
stdout suffix:
"#);
"#
);
}

#[test]
Expand Down
88 changes: 88 additions & 0 deletions tests/it/timeout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::setup;
use std::time::Duration;

use xshell::cmd;

#[test]
fn test_run_timeout_success() {
let sh = setup();
let command = cmd!(sh, "xsleep 1"); // Command that xsleeps for 1 second

// Run the command with a timeout of 3 seconds
let result = command.timeout(Duration::from_secs(3)).run();
assert!(result.is_ok(), "Command should complete successfully within the timeout");
}

#[test]
fn test_run_timeout_failure() {
let sh = setup();
let command = cmd!(sh, "xsleep 5"); // Command that xsleeps for 5 seconds

// Run the command with a timeout of 3 seconds
let result = command.timeout(Duration::from_secs(3)).run();
assert!(result.is_err(), "Command should fail due to timeout");
}

#[test]
fn test_read_timeout_success() {
let sh = setup();
let command = cmd!(sh, "xecho Hello, world!"); // Command that prints a message

// Run the command with a timeout of 3 seconds and read stdout
let result = command.timeout(Duration::from_secs(3)).read();
assert!(result.is_ok(), "Command should complete successfully within the timeout");
assert_eq!(result.unwrap(), "Hello, world!");
}

#[test]
fn test_read_timeout_failure() {
let sh = setup();
let command = cmd!(sh, "xsleep 5"); // Command that xsleeps for 5 seconds

// Run the command with a timeout of 3 seconds and read stdout
let result = command.timeout(Duration::from_secs(3)).read();
assert!(result.is_err(), "Command should fail due to timeout");
}

#[test]
fn test_read_stderr_timeout_success() {
let sh = setup();
let command = cmd!(sh, "xecho -e Error message"); // Command that prints an error message to stderr

// Run the command with a timeout of 3 seconds and read stderr
let result = command.timeout(Duration::from_secs(3)).read_stderr();
assert!(result.is_ok(), "Command should complete successfully within the timeout");
assert_eq!(result.unwrap(), "Error message");
}

#[test]
fn test_read_stderr_timeout_failure() {
let sh = setup();
let command = cmd!(sh, "xsleep 5"); // Command that xsleeps for 5 seconds

// Run the command with a timeout of 3 seconds and read stderr
let result = command.timeout(Duration::from_secs(3)).read_stderr();
assert!(result.is_err(), "Command should fail due to timeout");
}

#[test]
fn test_output_timeout_success() {
let sh = setup();
let command = cmd!(sh, "xecho Hello, world!"); // Command that prints a message

// Run the command with a timeout of 3 seconds and get the full output
let result = command.timeout(Duration::from_secs(3)).output();
assert!(result.is_ok(), "Command should complete successfully within the timeout");
let output = result.unwrap();
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "Hello, world!");
}

#[test]
fn test_output_timeout_failure() {
let sh = setup();
let command = cmd!(sh, "xsleep 5"); // Command that xsleeps for 5 seconds

// Run the command with a timeout of 3 seconds and get the full output
let result = command.timeout(Duration::from_secs(3)).output();
assert!(result.is_err(), "Command should fail due to timeout");
}

0 comments on commit 8ec06a6

Please sign in to comment.