Skip to content

Commit e995061

Browse files
author
Felix Rath
committed
save an Instant for the timeout instead of a Duration
requires less bookkeeping. also move some functionality into functions, to keep the loop cleaner.
1 parent 9006913 commit e995061

File tree

1 file changed

+35
-24
lines changed

1 file changed

+35
-24
lines changed

src/libtest/lib.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,9 @@ impl<T: Write> ConsoleTestState<T> {
596596
}
597597

598598
pub fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
599-
self.write_plain(&format!("test {} has been running for over {} seconds\n", desc.name, TEST_WARN_TIMEOUT_S))
599+
self.write_plain(&format!("test {} has been running for over {} seconds\n",
600+
desc.name,
601+
TEST_WARN_TIMEOUT_S))
600602
}
601603

602604
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
@@ -879,7 +881,28 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) ->
879881

880882
let (tx, rx) = channel::<MonitorMsg>();
881883

882-
let mut running_tests: HashMap<TestDesc, Duration> = HashMap::new();
884+
let mut running_tests: HashMap<TestDesc, Instant> = HashMap::new();
885+
886+
fn get_timed_out_tests(running_tests: &mut HashMap<TestDesc, Instant>) -> Vec<TestDesc> {
887+
let now = Instant::now();
888+
let timed_out = running_tests.iter()
889+
.filter_map(|(desc, timeout)| if &now >= timeout { Some(desc.clone())} else { None })
890+
.collect();
891+
for test in &timed_out {
892+
running_tests.remove(test);
893+
}
894+
timed_out
895+
};
896+
897+
fn calc_timeout(running_tests: &HashMap<TestDesc, Instant>) -> Option<Duration> {
898+
running_tests.values().min().map(|next_timeout| {
899+
let now = Instant::now();
900+
if *next_timeout >= now {
901+
*next_timeout - now
902+
} else {
903+
Duration::new(0, 0)
904+
}})
905+
};
883906

884907
while pending > 0 || !remaining.is_empty() {
885908
while pending < concurrency && !remaining.is_empty() {
@@ -890,38 +913,26 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) ->
890913
// that hang forever.
891914
callback(TeWait(test.desc.clone(), test.testfn.padding()))?;
892915
}
893-
running_tests.insert(test.desc.clone(), Duration::from_secs(TEST_WARN_TIMEOUT_S));
916+
let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
917+
running_tests.insert(test.desc.clone(), timeout);
894918
run_test(opts, !opts.run_tests, test, tx.clone());
895919
pending += 1;
896920
}
897921

898922
let mut res;
899-
if let Some(min_timeout) = running_tests.values().min().cloned() {
900-
loop {
901-
let before = Instant::now();
902-
res = rx.recv_timeout(min_timeout);
903-
let elapsed = Instant::now() - before;
904-
905-
let mut to_remove = Vec::new();
906-
for (desc, time_left) in &mut running_tests {
907-
if *time_left >= elapsed {
908-
*time_left -= elapsed;
909-
} else {
910-
to_remove.push(desc.clone());
911-
callback(TeTimeout(desc.clone()))?;
912-
}
913-
}
914-
915-
for rem in to_remove {
916-
running_tests.remove(&rem);
923+
loop {
924+
if let Some(timeout) = calc_timeout(&running_tests) {
925+
res = rx.recv_timeout(timeout);
926+
for test in get_timed_out_tests(&mut running_tests) {
927+
callback(TeTimeout(test))?;
917928
}
918-
919929
if res != Err(RecvTimeoutError::Timeout) {
920930
break;
921931
}
932+
} else {
933+
res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
934+
break;
922935
}
923-
} else {
924-
res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
925936
}
926937

927938
let (desc, result, stdout) = res.unwrap();

0 commit comments

Comments
 (0)