Index: base/test/launcher/unit_test_launcher.cc |
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc |
index 7ab96fce6a0cf8bc56e2c8b5b80061fa22527280..c5dbc4d2b7da00ff4612d6c0888c24bc22a9c86d 100644 |
--- a/base/test/launcher/unit_test_launcher.cc |
+++ b/base/test/launcher/unit_test_launcher.cc |
@@ -228,17 +228,23 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
bool was_timeout, |
const std::string& output) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- std::vector<std::string> tests_to_relaunch_after_interruption; |
+ std::vector<std::string> tests_to_relaunch; |
ProcessTestResults(callback_state.test_launcher, |
callback_state.test_names, |
callback_state.output_file, |
output, |
exit_code, |
was_timeout, |
- &tests_to_relaunch_after_interruption); |
- |
- RunBatch(callback_state.test_launcher, |
- tests_to_relaunch_after_interruption); |
+ &tests_to_relaunch); |
+ |
+ // Relaunch requested tests in parallel, but only use single |
+ // test per batch for more precise results (crashes, test passes |
+ // but non-zero exit codes etc). |
+ for (size_t i = 0; i < tests_to_relaunch.size(); i++) { |
+ std::vector<std::string> batch; |
+ batch.push_back(tests_to_relaunch[i]); |
+ RunBatch(callback_state.test_launcher, batch); |
+ } |
// The temporary file's directory is also temporary. |
DeleteFile(callback_state.output_file.DirName(), true); |
@@ -251,7 +257,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
bool was_timeout, |
const std::string& output) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- std::vector<std::string> tests_to_relaunch_after_interruption; |
+ std::vector<std::string> tests_to_relaunch; |
bool called_any_callbacks = |
ProcessTestResults(callback_state.test_launcher, |
callback_state.test_names, |
@@ -259,11 +265,11 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
output, |
exit_code, |
was_timeout, |
- &tests_to_relaunch_after_interruption); |
+ &tests_to_relaunch); |
// There is only one test, there cannot be other tests to relaunch |
// due to a crash. |
- DCHECK(tests_to_relaunch_after_interruption.empty()); |
+ DCHECK(tests_to_relaunch.empty()); |
// There is only one test, we should have called back with its result. |
DCHECK(called_any_callbacks); |
@@ -286,7 +292,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
const std::string& output, |
int exit_code, |
bool was_timeout, |
- std::vector<std::string>* tests_to_relaunch_after_interruption) { |
+ std::vector<std::string>* tests_to_relaunch) { |
std::vector<TestResult> test_results; |
bool crashed = false; |
bool have_test_results = |
@@ -303,6 +309,9 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
bool had_interrupted_test = false; |
+ // Results to be reported back to the test launcher. |
+ std::vector<TestResult> final_results; |
+ |
for (size_t i = 0; i < test_names.size(); i++) { |
if (ContainsKey(results_map, test_names[i])) { |
TestResult test_result = results_map[test_names[i]]; |
@@ -329,10 +338,9 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
} |
test_result.output_snippet = |
GetTestOutputSnippet(test_result, output); |
- test_launcher->OnTestFinished(test_result); |
- called_any_callback = true; |
+ final_results.push_back(test_result); |
} else if (had_interrupted_test) { |
- tests_to_relaunch_after_interruption->push_back(test_names[i]); |
+ tests_to_relaunch->push_back(test_names[i]); |
} else { |
// TODO(phajdan.jr): Explicitly pass the info that the test didn't |
// run for a mysterious reason. |
@@ -342,17 +350,54 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { |
test_result.status = TestResult::TEST_UNKNOWN; |
test_result.output_snippet = |
GetTestOutputSnippet(test_result, output); |
- test_launcher->OnTestFinished(test_result); |
- called_any_callback = true; |
+ final_results.push_back(test_result); |
} |
} |
// TODO(phajdan.jr): Handle the case where processing XML output |
// indicates a crash but none of the test results is marked as crashing. |
- // TODO(phajdan.jr): Handle the case where the exit code is non-zero |
- // but results file indicates that all tests passed (e.g. crash during |
- // shutdown). |
+ if (final_results.empty()) |
+ return false; |
+ |
+ bool has_non_success_test = false; |
+ for (size_t i = 0; i < final_results.size(); i++) { |
+ if (final_results[i].status != TestResult::TEST_SUCCESS) { |
+ has_non_success_test = true; |
+ break; |
+ } |
+ } |
+ |
+ if (!has_non_success_test && exit_code != 0) { |
+ // This is a bit surprising case: all tests are marked as successful, |
+ // but the exit code was not zero. This can happen e.g. under memory |
+ // tools that report leaks this way. |
+ |
+ if (final_results.size() == 1) { |
+ // Easy case. One test only so we know the non-zero exit code |
+ // was caused by that one test. |
+ final_results[0].status = TestResult::TEST_FAILURE_ON_EXIT; |
+ } else { |
+ // Harder case. Discard the results and request relaunching all |
+ // tests without batching. This will trigger above branch on |
+ // relaunch leading to more precise results. |
+ LOG(WARNING) << "Not sure which test caused non-zero exit code, " |
+ << "relaunching all of them without batching."; |
+ |
+ for (size_t i = 0; i < final_results.size(); i++) |
+ tests_to_relaunch->push_back(final_results[i].full_name); |
+ |
+ return false; |
+ } |
+ } |
+ |
+ for (size_t i = 0; i < final_results.size(); i++) { |
+ // Fix the output snippet after possible changes to the test result. |
+ final_results[i].output_snippet = |
+ GetTestOutputSnippet(final_results[i], output); |
+ test_launcher->OnTestFinished(final_results[i]); |
+ called_any_callback = true; |
+ } |
} else { |
fprintf(stdout, |
"Failed to get out-of-band test success data, " |