Skip to content

Commit

Permalink
Attempt to add a CtrlC-handler test.
Browse files Browse the repository at this point in the history
This does not work. It always kills the test runner process no matter what I do.
  • Loading branch information
zachlute committed Sep 14, 2018
1 parent 6a3f4b9 commit 1a4ca1d
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 5 deletions.
41 changes: 40 additions & 1 deletion src/cargo/util/process_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::path::Path;
use std::process::{Command, Output, Stdio};
use std::process::{Child, Command, Output, Stdio};

use jobserver::Client;
use shell_escape::escape;
Expand Down Expand Up @@ -150,6 +150,24 @@ impl ProcessBuilder {
}
}

/// Spawns the process as a child and returns a handle without waiting for completion.
pub fn spawn(&self) -> CargoResult<Child> {
let mut command = self.build_command();
let res = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn();

match res {
Err(e) => Err(process_error(
&format!("Could not spawn process: {}", e),
None,
None
).into()),
Ok(child) => Ok(child)
}
}

/// Replaces the current process with the target process.
///
/// On Unix, this executes the process using the unix syscall `execvp`, which will block
Expand Down Expand Up @@ -192,6 +210,27 @@ impl ProcessBuilder {
}
}

/// Waits on output from the given child process, or an error if non-zero exit status.
pub fn wait_with_output(&self, child : Child) -> CargoResult<Output> {
let output = child.wait_with_output().chain_err(|| {
process_error(
&format!("could not wait on process {}", self),
None,
None,
)
})?;

if output.status.success() {
Ok(output)
} else {
Err(process_error(
&format!("process didn't exit successfully: {}", self),
Some(output.status),
Some(&output),
).into())
}
}

/// Execute a command, passing each line of stdout and stderr to the supplied callbacks, which
/// can mutate the string data.
///
Expand Down
130 changes: 130 additions & 0 deletions tests/testsuite/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,3 +1029,133 @@ fn default_run_workspace() {
.with_stdout("run-a")
.run();
}

#[cfg(windows)]
mod windows {
use std::process::Command;
use std::thread;
use std::time::Duration;
use support::project;

use winapi::shared::minwindef::{FALSE, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler;

#[test]
fn ctrlc_handled_by_child() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["foo", "ctrlc-sender"]
"#)
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies.winapi]
version = "0.3"
features = [
"consoleapi",
"minwindef"
]
"#)
.file(
"foo/src/main.rs",
r#"
extern crate winapi;
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler;
unsafe extern "system" fn ctrlc_handler(_: DWORD) -> BOOL {
println!("Ctrl-C handled!");
FALSE
}
fn main() {
unsafe {
SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE);
}
println!("Running!");
std::thread::sleep(std::time::Duration::from_secs(5));
println!("Ended normally.");
}
"#)
.file(
"ctrlc-sender/Cargo.toml",
r#"
[package]
name = "ctrlc-sender"
version = "0.1.0"
[dependencies.winapi]
version = "0.3"
features = [
"consoleapi",
"minwindef"
]
"#)
.file(
"ctrlc-sender/src/main.rs",
r#"
extern crate winapi;
use winapi::shared::minwindef::{DWORD, FALSE, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler;
use winapi::um::wincon::{AttachConsole, FreeConsole, GenerateConsoleCtrlEvent};
fn main() {
let pid : i32 = std::env::args().nth(1).unwrap().parse().unwrap();
unsafe {
let pid = pid as DWORD;
FreeConsole();
AttachConsole(pid);
SetConsoleCtrlHandler(None, TRUE);
GenerateConsoleCtrlEvent(0, 0);
std::thread::sleep(std::time::Duration::from_secs(2));
FreeConsole();
SetConsoleCtrlHandler(None, FALSE);
}
}
"#)
.build();

p.cargo("build").run();

let mut run = p.cargo("run --bin foo");
let run = run
.with_status(0)
.with_stdout_contains("Ctrl-C handled!")
.with_stdout_does_not_contain("Ended normally.");

let child = run.spawn().unwrap();

// Give the process time to get into its loop.
thread::sleep(Duration::from_secs(1));

unsafe {
SetConsoleCtrlHandler(None, TRUE);
}

// Run the ctrlc-sender on the running cargo run process.
// Can't run it with Cargo, though. We're already running with Cargo.
Command::new(p.bin("ctrlc-sender"))
.arg(child.id().to_string())
.status()
.unwrap();

unsafe {
SetConsoleCtrlHandler(None, FALSE);
}

// Waiting will cause the output to be checked.
run.wait(child);
}
}

23 changes: 19 additions & 4 deletions tests/testsuite/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ use std::fs;
use std::io::prelude::*;
use std::os;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::process::{Child, Command, Output};
use std::str;
use std::time::Duration;
use std::usize;
Expand Down Expand Up @@ -727,7 +727,20 @@ impl Execs {
pub fn run(&mut self) {
self.ran = true;
let p = (&self.process_builder).clone().unwrap();
if let Err(e) = self.match_process(&p) {
if let Err(e) = self.match_process(&p, None) {
panic!("\nExpected: {:?}\n but: {}", self, e)
}
}

pub fn spawn(&mut self) -> CargoResult<Child> {
self.ran = true;
let p = (&self.process_builder).clone().unwrap();
p.spawn()
}

pub fn wait(&mut self, child : Child) {
let p = (&self.process_builder).clone().unwrap();
if let Err(e) = self.match_process(&p, Some(child)) {
panic!("\nExpected: {:?}\n but: {}", self, e)
}
}
Expand All @@ -739,9 +752,11 @@ impl Execs {
}
}

fn match_process(&self, process: &ProcessBuilder) -> MatchResult {
fn match_process(&self, process: &ProcessBuilder, child: Option<Child>) -> MatchResult {
println!("running {}", process);
let res = if self.stream_output {
let res = if let Some(child) = child {
process.wait_with_output(child)
} else if self.stream_output {
if env::var("CI").is_ok() {
panic!("`.stream()` is for local debugging")
}
Expand Down

0 comments on commit 1a4ca1d

Please sign in to comment.