diff options
| author | Felix Rath <felixr@archlinux.info> | 2016-08-06 00:53:10 +0200 |
|---|---|---|
| committer | Felix Rath <felixr@archlinux.info> | 2016-08-06 11:52:10 +0200 |
| commit | 9006913bf5c1ecfebbffd5c3417bd26c3d6c4aeb (patch) | |
| tree | b3bc60306af5bdac979e86f143f93ef1a346c8a6 /src | |
| parent | ecdd51b7bb7fd993acd2ff5dbd72209244b1e4aa (diff) | |
| download | rust-9006913bf5c1ecfebbffd5c3417bd26c3d6c4aeb.tar.gz rust-9006913bf5c1ecfebbffd5c3417bd26c3d6c4aeb.zip | |
add warning timeout for tests that run >1min
this makes it easier to identify hanging tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/libtest/lib.rs | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 248f6f98650..106c14850ca 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -42,6 +42,7 @@ #![feature(staged_api)] #![feature(question_mark)] #![feature(panic_unwind)] +#![feature(mpsc_recv_timeout)] extern crate getopts; extern crate term; @@ -73,6 +74,8 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Instant, Duration}; +const TEST_WARN_TIMEOUT_S: u64 = 60; + // to be used by rustc to compile tests in libtest pub mod test { pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, @@ -592,6 +595,10 @@ impl<T: Write> ConsoleTestState<T> { } } + pub fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { + self.write_plain(&format!("test {} has been running for over {} seconds\n", desc.name, TEST_WARN_TIMEOUT_S)) + } + pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> { match self.log_out { None => Ok(()), @@ -709,6 +716,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu match (*event).clone() { TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()), TeWait(ref test, padding) => st.write_test_start(test, padding), + TeTimeout(ref test) => st.write_timeout(test), TeResult(test, result, stdout) => { st.write_log(&test, &result)?; st.write_result(&result)?; @@ -830,6 +838,7 @@ enum TestEvent { TeFiltered(Vec<TestDesc>), TeWait(TestDesc, NamePadding), TeResult(TestDesc, TestResult, Vec<u8>), + TeTimeout(TestDesc), } pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>); @@ -838,6 +847,9 @@ pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>); fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()> { + use std::collections::HashMap; + use std::sync::mpsc::RecvTimeoutError; + let mut filtered_tests = filter_tests(opts, tests); if !opts.bench_benchmarks { filtered_tests = convert_benchmarks_to_tests(filtered_tests); @@ -867,6 +879,8 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> let (tx, rx) = channel::<MonitorMsg>(); + let mut running_tests: HashMap<TestDesc, Duration> = HashMap::new(); + while pending > 0 || !remaining.is_empty() { while pending < concurrency && !remaining.is_empty() { let test = remaining.pop().unwrap(); @@ -876,11 +890,43 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> // that hang forever. callback(TeWait(test.desc.clone(), test.testfn.padding()))?; } + running_tests.insert(test.desc.clone(), Duration::from_secs(TEST_WARN_TIMEOUT_S)); run_test(opts, !opts.run_tests, test, tx.clone()); pending += 1; } - let (desc, result, stdout) = rx.recv().unwrap(); + let mut res; + if let Some(min_timeout) = running_tests.values().min().cloned() { + loop { + let before = Instant::now(); + res = rx.recv_timeout(min_timeout); + let elapsed = Instant::now() - before; + + let mut to_remove = Vec::new(); + for (desc, time_left) in &mut running_tests { + if *time_left >= elapsed { + *time_left -= elapsed; + } else { + to_remove.push(desc.clone()); + callback(TeTimeout(desc.clone()))?; + } + } + + for rem in to_remove { + running_tests.remove(&rem); + } + + if res != Err(RecvTimeoutError::Timeout) { + break; + } + } + } else { + res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); + } + + let (desc, result, stdout) = res.unwrap(); + running_tests.remove(&desc); + if concurrency != 1 { callback(TeWait(desc.clone(), PadNone))?; } |
