Keep reading buffered test process output after it has exited (#2923)

This commit is contained in:
teor 2021-10-21 11:40:39 +10:00 committed by GitHub
parent 595d75d5fb
commit 3db5ecb80e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 14 additions and 6 deletions

View File

@ -8,11 +8,11 @@ use tracing::instrument;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::process::ExitStatusExt; use std::os::unix::process::ExitStatusExt;
use std::{ use std::{
convert::Infallible as NoDir, convert::Infallible as NoDir,
fmt::{self, Write as _}, fmt::{self, Write as _},
io::BufRead, io::{BufRead, BufReader, Lines, Read, Write as _},
io::{BufReader, Lines, Read},
path::Path, path::Path,
process::{Child, ChildStderr, ChildStdout, Command, ExitStatus, Output, Stdio}, process::{Child, ChildStderr, ChildStdout, Command, ExitStatus, Output, Stdio},
time::{Duration, Instant}, time::{Duration, Instant},
@ -286,10 +286,17 @@ impl<T> TestChild<T> {
L: Iterator<Item = std::io::Result<String>>, L: Iterator<Item = std::io::Result<String>>,
{ {
let re = regex::Regex::new(regex).expect("regex must be valid"); let re = regex::Regex::new(regex).expect("regex must be valid");
while !self.past_deadline() && self.is_running() {
// We don't check `is_running` here,
// because we want to read to the end of the buffered output,
// even if the child process has exited.
while !self.past_deadline() {
let line = if let Some(line) = lines.next() { let line = if let Some(line) = lines.next() {
line? line?
} else { } else {
// When the child process closes its output,
// and we've read all of the buffered output,
// stop checking for any more output.
break; break;
}; };
@ -297,14 +304,15 @@ impl<T> TestChild<T> {
// can be preserved. May cause weird reordering for stdout / stderr. // can be preserved. May cause weird reordering for stdout / stderr.
// Uses stdout even if the original lines were from stderr. // Uses stdout even if the original lines were from stderr.
if self.bypass_test_capture { if self.bypass_test_capture {
// send lines to the terminal (or process stdout file redirect) // Send lines directly to the terminal (or process stdout file redirect).
use std::io::Write;
#[allow(clippy::explicit_write)] #[allow(clippy::explicit_write)]
writeln!(std::io::stdout(), "{}", line).unwrap(); writeln!(std::io::stdout(), "{}", line).unwrap();
} else { } else {
// if the test fails, the test runner captures and displays it // If the test fails, the test runner captures and displays this output.
println!("{}", line); println!("{}", line);
} }
// Some OSes require a flush to send all output to the terminal.
std::io::stdout().lock().flush()?;
if re.is_match(&line) { if re.is_match(&line) {
return Ok(()); return Ok(());