libcore: Do less blocking in the test runner

This commit is contained in:
Brian Anderson 2012-01-19 14:36:11 -08:00
parent 7a663032fb
commit 928e55815c

View File

@ -17,7 +17,6 @@ export tr_ok;
export tr_failed; export tr_failed;
export tr_ignored; export tr_ignored;
export run_tests_console; export run_tests_console;
export configure_test_task;
#[abi = "cdecl"] #[abi = "cdecl"]
native mod rustrt { native mod rustrt {
@ -192,6 +191,8 @@ enum testevent {
te_result(test_desc, test_result); te_result(test_desc, test_result);
} }
type monitor_msg = (test_desc, test_result);
fn run_tests(opts: test_opts, tests: [test_desc], fn run_tests(opts: test_opts, tests: [test_desc],
callback: fn@(testevent)) { callback: fn@(testevent)) {
@ -202,23 +203,27 @@ fn run_tests(opts: test_opts, tests: [test_desc],
// many tests that run in other processes we would be making a big mess. // many tests that run in other processes we would be making a big mess.
let concurrency = get_concurrency(); let concurrency = get_concurrency();
#debug("using %u test tasks", concurrency); #debug("using %u test tasks", concurrency);
let total = vec::len(filtered_tests); let total = vec::len(filtered_tests);
let run_idx = 0u; let run_idx = 0u;
let wait_idx = 0u; let wait_idx = 0u;
let futures = []; let done_idx = 0u;
while wait_idx < total { let p = comm::port();
while vec::len(futures) < concurrency && run_idx < total { let ch = comm::chan(p);
futures += [run_test(filtered_tests[run_idx])];
while done_idx < total {
while wait_idx < concurrency && run_idx < total {
run_test(vec::shift(filtered_tests), ch);
wait_idx += 1u;
run_idx += 1u; run_idx += 1u;
} }
let future = futures[0]; let (test, result) = comm::recv(p);
callback(te_wait(future.test)); callback(te_wait(test));
let result = future.wait(); callback(te_result(test, result));
callback(te_result(future.test, result)); wait_idx -= 1u;
futures = vec::slice(futures, 1u, vec::len(futures)); done_idx += 1u;
wait_idx += 1u;
} }
} }
@ -280,35 +285,34 @@ fn filter_tests(opts: test_opts,
type test_future = {test: test_desc, wait: fn@() -> test_result}; type test_future = {test: test_desc, wait: fn@() -> test_result};
fn run_test(test: test_desc) -> test_future { fn run_test(+test: test_desc, monitor_ch: comm::chan<monitor_msg>) {
if test.ignore { if test.ignore {
ret {test: test, wait: fn@() -> test_result { tr_ignored }}; comm::send(monitor_ch, (test, tr_ignored));
ret;
} }
let test_task = test_to_task(test.fn); task::spawn {||
ret {test: test,
wait: fn@() -> test_result { let testfn = test.fn;
alt task::join(test_task) { let test_task = task::spawn_joinable {||
task::tr_success { configure_test_task();
if test.should_fail { tr_failed } testfn();
else { tr_ok }
}
task::tr_failure {
if test.should_fail { tr_ok }
else { tr_failed }
}
}
}
}; };
let task_result = task::join(test_task);
let test_result = calc_result(test, task_result == task::tr_success);
comm::send(monitor_ch, (test, test_result));
};
} }
// We need to run our tests in another task in order to trap test failures. fn calc_result(test: test_desc, task_succeeded: bool) -> test_result {
// This function only works with functions that don't contain closures. if task_succeeded {
fn test_to_task(&&f: test_fn) -> task::joinable_task { if test.should_fail { tr_failed }
ret task::spawn_joinable(fn~[copy f]() { else { tr_ok }
configure_test_task(); } else {
f(); if test.should_fail { tr_ok }
}); else { tr_failed }
}
} }
// Call from within a test task to make sure it's set up correctly // Call from within a test task to make sure it's set up correctly
@ -330,9 +334,11 @@ mod tests {
ignore: true, ignore: true,
should_fail: false should_fail: false
}; };
let future = run_test(desc); let p = comm::port();
let result = future.wait(); let ch = comm::chan(p);
assert result != tr_ok; run_test(desc, ch);
let (_, res) = comm::recv(p);
assert res != tr_ok;
} }
#[test] #[test]
@ -344,8 +350,11 @@ mod tests {
ignore: true, ignore: true,
should_fail: false should_fail: false
}; };
let res = run_test(desc).wait(); let p = comm::port();
assert (res == tr_ignored); let ch = comm::chan(p);
run_test(desc, ch);
let (_, res) = comm::recv(p);
assert res == tr_ignored;
} }
#[test] #[test]
@ -358,7 +367,10 @@ mod tests {
ignore: false, ignore: false,
should_fail: true should_fail: true
}; };
let res = run_test(desc).wait(); let p = comm::port();
let ch = comm::chan(p);
run_test(desc, ch);
let (_, res) = comm::recv(p);
assert res == tr_ok; assert res == tr_ok;
} }
@ -371,7 +383,10 @@ mod tests {
ignore: false, ignore: false,
should_fail: true should_fail: true
}; };
let res = run_test(desc).wait(); let p = comm::port();
let ch = comm::chan(p);
run_test(desc, ch);
let (_, res) = comm::recv(p);
assert res == tr_failed; assert res == tr_failed;
} }