about summary refs log tree commit diff
path: root/src/test/ui/process
diff options
context:
space:
mode:
authorCaio <c410.f3r@gmail.com>2021-11-18 12:09:34 -0300
committerCaio <c410.f3r@gmail.com>2021-11-18 12:09:34 -0300
commit41d9abd76cd514aca23e3409fe6896a3a7d61d1a (patch)
treeaff7d6c42e88201c903006083095106fd082f16b /src/test/ui/process
parent6414e0b5b308d3ae27da83c6a25098cc8aadc1a9 (diff)
Move some tests to more reasonable directories
Diffstat (limited to 'src/test/ui/process')
-rw-r--r--src/test/ui/process/core-run-destroy.rs87
-rw-r--r--src/test/ui/process/multi-panic.rs37
-rw-r--r--src/test/ui/process/no-stdio.rs139
-rw-r--r--src/test/ui/process/try-wait.rs60
4 files changed, 323 insertions, 0 deletions
diff --git a/src/test/ui/process/core-run-destroy.rs b/src/test/ui/process/core-run-destroy.rs
new file mode 100644
index 00000000000..5fd418e6c86
--- /dev/null
+++ b/src/test/ui/process/core-run-destroy.rs
@@ -0,0 +1,87 @@
+// run-pass
+
+#![allow(unused_must_use)]
+#![allow(stable_features)]
+#![allow(deprecated)]
+#![allow(unused_imports)]
+// compile-flags:--test
+// ignore-emscripten no processes
+// ignore-sgx no processes
+// ignore-vxworks no 'cat' and 'sleep'
+
+// N.B., these tests kill child processes. Valgrind sees these children as leaking
+// memory, which makes for some *confusing* logs. That's why these are here
+// instead of in std.
+
+#![feature(rustc_private, duration)]
+
+extern crate libc;
+
+use std::process::{self, Command, Child, Output, Stdio};
+use std::str;
+use std::sync::mpsc::channel;
+use std::thread;
+use std::time::Duration;
+
+macro_rules! t {
+    ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("error: {}", e) })
+}
+
+#[test]
+fn test_destroy_once() {
+    let mut p = sleeper();
+    t!(p.kill());
+}
+
+#[cfg(unix)]
+pub fn sleeper() -> Child {
+    t!(Command::new("sleep").arg("1000").spawn())
+}
+#[cfg(windows)]
+pub fn sleeper() -> Child {
+    // There's a `timeout` command on windows, but it doesn't like having
+    // its output piped, so instead just ping ourselves a few times with
+    // gaps in between so we're sure this process is alive for awhile
+    t!(Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn())
+}
+
+#[test]
+fn test_destroy_twice() {
+    let mut p = sleeper();
+    t!(p.kill()); // this shouldn't crash...
+    let _ = p.kill(); // ...and nor should this (and nor should the destructor)
+}
+
+#[test]
+fn test_destroy_actually_kills() {
+    let cmd = if cfg!(windows) {
+        "cmd"
+    } else if cfg!(target_os = "android") {
+        "/system/bin/cat"
+    } else {
+        "cat"
+    };
+
+    // this process will stay alive indefinitely trying to read from stdin
+    let mut p = t!(Command::new(cmd)
+                           .stdin(Stdio::piped())
+                           .spawn());
+
+    t!(p.kill());
+
+    // Don't let this test time out, this should be quick
+    let (tx, rx) = channel();
+    thread::spawn(move|| {
+        thread::sleep_ms(1000);
+        if rx.try_recv().is_err() {
+            process::exit(1);
+        }
+    });
+    let code = t!(p.wait()).code();
+    if cfg!(windows) {
+        assert!(code.is_some());
+    } else {
+        assert!(code.is_none());
+    }
+    tx.send(());
+}
diff --git a/src/test/ui/process/multi-panic.rs b/src/test/ui/process/multi-panic.rs
new file mode 100644
index 00000000000..37e8b99c2f6
--- /dev/null
+++ b/src/test/ui/process/multi-panic.rs
@@ -0,0 +1,37 @@
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+fn check_for_no_backtrace(test: std::process::Output) {
+    assert!(!test.status.success());
+    let err = String::from_utf8_lossy(&test.stderr);
+    let mut it = err.lines();
+
+    assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked at")), Some(true));
+    assert_eq!(it.next(), Some("note: run with `RUST_BACKTRACE=1` \
+                                environment variable to display a backtrace"));
+    assert_eq!(it.next().map(|l| l.starts_with("thread 'main' panicked at")), Some(true));
+    assert_eq!(it.next(), None);
+}
+
+fn main() {
+    let args: Vec<String> = std::env::args().collect();
+    if args.len() > 1 && args[1] == "run_test" {
+        let _ = std::thread::spawn(|| {
+            panic!();
+        }).join();
+
+        panic!();
+    } else {
+        let test = std::process::Command::new(&args[0]).arg("run_test")
+                                                       .env_remove("RUST_BACKTRACE")
+                                                       .output()
+                                                       .unwrap();
+        check_for_no_backtrace(test);
+        let test = std::process::Command::new(&args[0]).arg("run_test")
+                                                       .env("RUST_BACKTRACE","0")
+                                                       .output()
+                                                       .unwrap();
+        check_for_no_backtrace(test);
+    }
+}
diff --git a/src/test/ui/process/no-stdio.rs b/src/test/ui/process/no-stdio.rs
new file mode 100644
index 00000000000..24985386a97
--- /dev/null
+++ b/src/test/ui/process/no-stdio.rs
@@ -0,0 +1,139 @@
+// run-pass
+// ignore-android
+// ignore-emscripten no processes
+// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+#![feature(rustc_private)]
+
+extern crate libc;
+
+use std::process::{Command, Stdio};
+use std::env;
+use std::io::{self, Read, Write};
+
+#[cfg(unix)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+    let doit = |a| {
+        let r = libc::dup(a);
+        assert!(r >= 0);
+        return r
+    };
+    let a = doit(0);
+    let b = doit(1);
+    let c = doit(2);
+
+    assert!(libc::close(0) >= 0);
+    assert!(libc::close(1) >= 0);
+    assert!(libc::close(2) >= 0);
+
+    let r = f();
+
+    assert!(libc::dup2(a, 0) >= 0);
+    assert!(libc::dup2(b, 1) >= 0);
+    assert!(libc::dup2(c, 2) >= 0);
+
+    return r
+}
+
+#[cfg(unix)]
+fn assert_fd_is_valid(fd: libc::c_int) {
+    if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
+        panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
+    }
+}
+
+#[cfg(windows)]
+fn assert_fd_is_valid(_fd: libc::c_int) {}
+
+#[cfg(windows)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+    type DWORD = u32;
+    type HANDLE = *mut u8;
+    type BOOL = i32;
+
+    const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
+    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+    const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+    extern "system" {
+        fn GetStdHandle(which: DWORD) -> HANDLE;
+        fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL;
+    }
+
+    let doit = |id| {
+        let handle = GetStdHandle(id);
+        assert!(handle != INVALID_HANDLE_VALUE);
+        assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0);
+        return handle
+    };
+
+    let a = doit(STD_INPUT_HANDLE);
+    let b = doit(STD_OUTPUT_HANDLE);
+    let c = doit(STD_ERROR_HANDLE);
+
+    let r = f();
+
+    let doit = |id, handle| {
+        assert!(SetStdHandle(id, handle) != 0);
+    };
+    doit(STD_INPUT_HANDLE, a);
+    doit(STD_OUTPUT_HANDLE, b);
+    doit(STD_ERROR_HANDLE, c);
+
+    return r
+}
+
+fn main() {
+    if env::args().len() > 1 {
+        // Writing to stdout & stderr should not panic.
+        println!("test");
+        assert!(io::stdout().write(b"test\n").is_ok());
+        assert!(io::stderr().write(b"test\n").is_ok());
+
+        // Stdin should be at EOF.
+        assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0);
+
+        // Standard file descriptors should be valid on UNIX:
+        assert_fd_is_valid(0);
+        assert_fd_is_valid(1);
+        assert_fd_is_valid(2);
+        return
+    }
+
+    // First, make sure reads/writes without stdio work if stdio itself is
+    // missing.
+    let (a, b, c) = unsafe {
+        without_stdio(|| {
+            let a = io::stdout().write(b"test\n");
+            let b = io::stderr().write(b"test\n");
+            let c = io::stdin().read(&mut [0; 10]);
+
+            (a, b, c)
+        })
+    };
+
+    assert_eq!(a.unwrap(), 5);
+    assert_eq!(b.unwrap(), 5);
+    assert_eq!(c.unwrap(), 0);
+
+    // Second, spawn a child and do some work with "null" descriptors to make
+    // sure it's ok
+    let me = env::current_exe().unwrap();
+    let status = Command::new(&me)
+                        .arg("next")
+                        .stdin(Stdio::null())
+                        .stdout(Stdio::null())
+                        .stderr(Stdio::null())
+                        .status().unwrap();
+    assert!(status.success(), "{} isn't a success", status);
+
+    // Finally, close everything then spawn a child to make sure everything is
+    // *still* ok.
+    let status = unsafe {
+        without_stdio(|| Command::new(&me).arg("next").status())
+    }.unwrap();
+    assert!(status.success(), "{} isn't a success", status);
+}
diff --git a/src/test/ui/process/try-wait.rs b/src/test/ui/process/try-wait.rs
new file mode 100644
index 00000000000..692197210b1
--- /dev/null
+++ b/src/test/ui/process/try-wait.rs
@@ -0,0 +1,60 @@
+// run-pass
+
+#![allow(stable_features)]
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+#![feature(process_try_wait)]
+
+use std::env;
+use std::process::Command;
+use std::thread;
+use std::time::Duration;
+
+fn main() {
+    let args = env::args().collect::<Vec<_>>();
+    if args.len() != 1 {
+        match &args[1][..] {
+            "sleep" => thread::sleep(Duration::new(1_000, 0)),
+            _ => {}
+        }
+        return
+    }
+
+    let mut me = Command::new(env::current_exe().unwrap())
+                         .arg("sleep")
+                         .spawn()
+                         .unwrap();
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
+    let maybe_status = me.try_wait().unwrap();
+    assert!(maybe_status.is_none());
+
+    me.kill().unwrap();
+    me.wait().unwrap();
+
+    let status = me.try_wait().unwrap().unwrap();
+    assert!(!status.success());
+    let status = me.try_wait().unwrap().unwrap();
+    assert!(!status.success());
+
+    let mut me = Command::new(env::current_exe().unwrap())
+                         .arg("return-quickly")
+                         .spawn()
+                         .unwrap();
+    loop {
+        match me.try_wait() {
+            Ok(Some(res)) => {
+                assert!(res.success());
+                break
+            }
+            Ok(None) => {
+                thread::sleep(Duration::from_millis(1));
+            }
+            Err(e) => panic!("error in try_wait: {}", e),
+        }
+    }
+
+    let status = me.try_wait().unwrap().unwrap();
+    assert!(status.success());
+}