42
42
#![ feature( staged_api) ]
43
43
#![ feature( question_mark) ]
44
44
#![ feature( panic_unwind) ]
45
+ #![ feature( mpsc_recv_timeout) ]
45
46
46
47
extern crate getopts;
47
48
extern crate term;
@@ -73,6 +74,8 @@ use std::sync::{Arc, Mutex};
73
74
use std:: thread;
74
75
use std:: time:: { Instant , Duration } ;
75
76
77
+ const TEST_WARN_TIMEOUT_S : u64 = 60 ;
78
+
76
79
// to be used by rustc to compile tests in libtest
77
80
pub mod test {
78
81
pub use { Bencher , TestName , TestResult , TestDesc , TestDescAndFn , TestOpts , TrFailed ,
@@ -592,6 +595,10 @@ impl<T: Write> ConsoleTestState<T> {
592
595
}
593
596
}
594
597
598
+ 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 ) )
600
+ }
601
+
595
602
pub fn write_log ( & mut self , test : & TestDesc , result : & TestResult ) -> io:: Result < ( ) > {
596
603
match self . log_out {
597
604
None => Ok ( ( ) ) ,
@@ -709,6 +716,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
709
716
match ( * event) . clone ( ) {
710
717
TeFiltered ( ref filtered_tests) => st. write_run_start ( filtered_tests. len ( ) ) ,
711
718
TeWait ( ref test, padding) => st. write_test_start ( test, padding) ,
719
+ TeTimeout ( ref test) => st. write_timeout ( test) ,
712
720
TeResult ( test, result, stdout) => {
713
721
st. write_log ( & test, & result) ?;
714
722
st. write_result ( & result) ?;
@@ -830,6 +838,7 @@ enum TestEvent {
830
838
TeFiltered ( Vec < TestDesc > ) ,
831
839
TeWait ( TestDesc , NamePadding ) ,
832
840
TeResult ( TestDesc , TestResult , Vec < u8 > ) ,
841
+ TeTimeout ( TestDesc ) ,
833
842
}
834
843
835
844
pub type MonitorMsg = ( TestDesc , TestResult , Vec < u8 > ) ;
@@ -838,6 +847,9 @@ pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
838
847
fn run_tests < F > ( opts : & TestOpts , tests : Vec < TestDescAndFn > , mut callback : F ) -> io:: Result < ( ) >
839
848
where F : FnMut ( TestEvent ) -> io:: Result < ( ) >
840
849
{
850
+ use std:: collections:: HashMap ;
851
+ use std:: sync:: mpsc:: RecvTimeoutError ;
852
+
841
853
let mut filtered_tests = filter_tests ( opts, tests) ;
842
854
if !opts. bench_benchmarks {
843
855
filtered_tests = convert_benchmarks_to_tests ( filtered_tests) ;
@@ -867,6 +879,8 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) ->
867
879
868
880
let ( tx, rx) = channel :: < MonitorMsg > ( ) ;
869
881
882
+ let mut running_tests: HashMap < TestDesc , Duration > = HashMap :: new ( ) ;
883
+
870
884
while pending > 0 || !remaining. is_empty ( ) {
871
885
while pending < concurrency && !remaining. is_empty ( ) {
872
886
let test = remaining. pop ( ) . unwrap ( ) ;
@@ -876,11 +890,43 @@ fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) ->
876
890
// that hang forever.
877
891
callback ( TeWait ( test. desc . clone ( ) , test. testfn . padding ( ) ) ) ?;
878
892
}
893
+ running_tests. insert ( test. desc . clone ( ) , Duration :: from_secs ( TEST_WARN_TIMEOUT_S ) ) ;
879
894
run_test ( opts, !opts. run_tests , test, tx. clone ( ) ) ;
880
895
pending += 1 ;
881
896
}
882
897
883
- let ( desc, result, stdout) = rx. recv ( ) . unwrap ( ) ;
898
+ 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) ;
917
+ }
918
+
919
+ if res != Err ( RecvTimeoutError :: Timeout ) {
920
+ break ;
921
+ }
922
+ }
923
+ } else {
924
+ res = rx. recv ( ) . map_err ( |_| RecvTimeoutError :: Disconnected ) ;
925
+ }
926
+
927
+ let ( desc, result, stdout) = res. unwrap ( ) ;
928
+ running_tests. remove ( & desc) ;
929
+
884
930
if concurrency != 1 {
885
931
callback ( TeWait ( desc. clone ( ) , PadNone ) ) ?;
886
932
}
0 commit comments