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 9a8b41f15a4d54a5d9d2ae925755f6947e63c0a8..a31b6db715466e7228a8acdd71ed65ff8dabc427 100644 |
--- a/base/test/launcher/unit_test_launcher.cc |
+++ b/base/test/launcher/unit_test_launcher.cc |
@@ -244,325 +244,302 @@ bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) { |
bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name, |
const std::string& test_name) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- // There is no additional logic to disable specific tests. |
- return true; |
- } |
+ // There is no additional logic to disable specific tests. |
+ return true; |
+} |
- size_t UnitTestLauncherDelegate::RunTests( |
- TestLauncher* test_launcher, |
- const std::vector<std::string>& test_names) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
+size_t UnitTestLauncherDelegate::RunTests( |
+ TestLauncher* test_launcher, |
+ const std::vector<std::string>& test_names) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- std::vector<std::string> batch; |
- for (size_t i = 0; i < test_names.size(); i++) { |
- batch.push_back(test_names[i]); |
+ std::vector<std::string> batch; |
+ for (size_t i = 0; i < test_names.size(); i++) { |
+ batch.push_back(test_names[i]); |
- if (batch.size() >= batch_limit_) { |
- RunBatch(test_launcher, batch); |
- batch.clear(); |
- } |
+ if (batch.size() >= batch_limit_) { |
+ RunBatch(test_launcher, batch); |
+ batch.clear(); |
} |
+ } |
- RunBatch(test_launcher, batch); |
+ RunBatch(test_launcher, batch); |
- return test_names.size(); |
- } |
+ return test_names.size(); |
+} |
- size_t UnitTestLauncherDelegate::RetryTests( |
- TestLauncher* test_launcher, |
- const std::vector<std::string>& test_names) { |
- MessageLoop::current()->PostTask( |
- FROM_HERE, |
- Bind(&UnitTestLauncherDelegate::RunSerially, |
- Unretained(this), |
- test_launcher, |
- test_names)); |
- return test_names.size(); |
- } |
+size_t UnitTestLauncherDelegate::RetryTests( |
+ TestLauncher* test_launcher, |
+ const std::vector<std::string>& test_names) { |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, Bind(&UnitTestLauncherDelegate::RunSerially, Unretained(this), |
+ test_launcher, test_names)); |
+ return test_names.size(); |
+} |
- void UnitTestLauncherDelegate::RunSerially( |
- TestLauncher* test_launcher, |
- const std::vector<std::string>& test_names) { |
- if (test_names.empty()) |
- return; |
- |
- std::vector<std::string> new_test_names(test_names); |
- std::string test_name(new_test_names.back()); |
- new_test_names.pop_back(); |
- |
- // Create a dedicated temporary directory to store the xml result data |
- // per run to ensure clean state and make it possible to launch multiple |
- // processes in parallel. |
- base::FilePath output_file; |
- CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file)); |
- output_file = output_file.AppendASCII("test_results.xml"); |
- |
- std::vector<std::string> current_test_names; |
- current_test_names.push_back(test_name); |
- CommandLine cmd_line( |
- GetCommandLineForChildGTestProcess(current_test_names, output_file)); |
- |
- GTestCallbackState callback_state; |
- callback_state.test_launcher = test_launcher; |
- callback_state.test_names = current_test_names; |
- callback_state.output_file = output_file; |
- |
- test_launcher->LaunchChildGTestProcess( |
- cmd_line, |
- std::string(), |
- TestTimeouts::test_launcher_timeout(), |
- use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0, |
- Bind(&UnitTestLauncherDelegate::SerialGTestCallback, |
- Unretained(this), |
- callback_state, |
- new_test_names)); |
- } |
+void UnitTestLauncherDelegate::RunSerially( |
+ TestLauncher* test_launcher, |
+ const std::vector<std::string>& test_names) { |
+ if (test_names.empty()) |
+ return; |
+ |
+ std::vector<std::string> new_test_names(test_names); |
+ std::string test_name(new_test_names.back()); |
+ new_test_names.pop_back(); |
+ |
+ // Create a dedicated temporary directory to store the xml result data |
+ // per run to ensure clean state and make it possible to launch multiple |
+ // processes in parallel. |
+ base::FilePath output_file; |
+ CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file)); |
+ output_file = output_file.AppendASCII("test_results.xml"); |
+ |
+ std::vector<std::string> current_test_names; |
+ current_test_names.push_back(test_name); |
+ CommandLine cmd_line( |
+ GetCommandLineForChildGTestProcess(current_test_names, output_file)); |
+ |
+ GTestCallbackState callback_state; |
+ callback_state.test_launcher = test_launcher; |
+ callback_state.test_names = current_test_names; |
+ callback_state.output_file = output_file; |
+ |
+ test_launcher->LaunchChildGTestProcess( |
+ cmd_line, std::string(), TestTimeouts::test_launcher_timeout(), |
+ use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0, |
+ Bind(&UnitTestLauncherDelegate::SerialGTestCallback, Unretained(this), |
+ callback_state, new_test_names)); |
+} |
- void UnitTestLauncherDelegate::RunBatch( |
- TestLauncher* test_launcher, |
- const std::vector<std::string>& test_names) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- if (test_names.empty()) |
- return; |
- |
- // Create a dedicated temporary directory to store the xml result data |
- // per run to ensure clean state and make it possible to launch multiple |
- // processes in parallel. |
- base::FilePath output_file; |
- CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file)); |
- output_file = output_file.AppendASCII("test_results.xml"); |
- |
- CommandLine cmd_line( |
- GetCommandLineForChildGTestProcess(test_names, output_file)); |
- |
- // Adjust the timeout depending on how many tests we're running |
- // (note that e.g. the last batch of tests will be smaller). |
- // TODO(phajdan.jr): Consider an adaptive timeout, which can change |
- // depending on how many tests ran and how many remain. |
- // Note: do NOT parse child's stdout to do that, it's known to be |
- // unreliable (e.g. buffering issues can mix up the output). |
- base::TimeDelta timeout = |
- test_names.size() * TestTimeouts::test_launcher_timeout(); |
- |
- GTestCallbackState callback_state; |
- callback_state.test_launcher = test_launcher; |
- callback_state.test_names = test_names; |
- callback_state.output_file = output_file; |
- |
- test_launcher->LaunchChildGTestProcess( |
- cmd_line, |
- std::string(), |
- timeout, |
- use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0, |
- Bind(&UnitTestLauncherDelegate::GTestCallback, |
- Unretained(this), |
- callback_state)); |
- } |
+void UnitTestLauncherDelegate::RunBatch( |
+ TestLauncher* test_launcher, |
+ const std::vector<std::string>& test_names) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- void UnitTestLauncherDelegate::GTestCallback( |
- const GTestCallbackState& callback_state, |
- int exit_code, |
- const TimeDelta& elapsed_time, |
- bool was_timeout, |
- const std::string& output) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- 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); |
- |
- // 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); |
- } |
+ if (test_names.empty()) |
+ return; |
+ |
+ // Create a dedicated temporary directory to store the xml result data |
+ // per run to ensure clean state and make it possible to launch multiple |
+ // processes in parallel. |
+ base::FilePath output_file; |
+ CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file)); |
+ output_file = output_file.AppendASCII("test_results.xml"); |
+ |
+ CommandLine cmd_line( |
+ GetCommandLineForChildGTestProcess(test_names, output_file)); |
+ |
+ // Adjust the timeout depending on how many tests we're running |
+ // (note that e.g. the last batch of tests will be smaller). |
+ // TODO(phajdan.jr): Consider an adaptive timeout, which can change |
+ // depending on how many tests ran and how many remain. |
+ // Note: do NOT parse child's stdout to do that, it's known to be |
+ // unreliable (e.g. buffering issues can mix up the output). |
+ base::TimeDelta timeout = |
+ test_names.size() * TestTimeouts::test_launcher_timeout(); |
+ |
+ GTestCallbackState callback_state; |
+ callback_state.test_launcher = test_launcher; |
+ callback_state.test_names = test_names; |
+ callback_state.output_file = output_file; |
+ |
+ test_launcher->LaunchChildGTestProcess( |
+ cmd_line, std::string(), timeout, |
+ use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0, |
+ Bind(&UnitTestLauncherDelegate::GTestCallback, Unretained(this), |
+ callback_state)); |
+} |
- // The temporary file's directory is also temporary. |
- DeleteFile(callback_state.output_file.DirName(), true); |
+void UnitTestLauncherDelegate::GTestCallback( |
+ const GTestCallbackState& callback_state, |
+ int exit_code, |
+ const TimeDelta& elapsed_time, |
+ bool was_timeout, |
+ const std::string& output) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ 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); |
+ |
+ // 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); |
} |
- void UnitTestLauncherDelegate::SerialGTestCallback( |
- const GTestCallbackState& callback_state, |
- const std::vector<std::string>& test_names, |
- int exit_code, |
- const TimeDelta& elapsed_time, |
- bool was_timeout, |
- const std::string& output) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- std::vector<std::string> tests_to_relaunch; |
- bool called_any_callbacks = |
- ProcessTestResults(callback_state.test_launcher, |
- callback_state.test_names, |
- callback_state.output_file, |
- output, |
- exit_code, |
- was_timeout, |
- &tests_to_relaunch); |
- |
- // There is only one test, there cannot be other tests to relaunch |
- // due to a crash. |
- DCHECK(tests_to_relaunch.empty()); |
- |
- // There is only one test, we should have called back with its result. |
- DCHECK(called_any_callbacks); |
- |
- // The temporary file's directory is also temporary. |
- DeleteFile(callback_state.output_file.DirName(), true); |
- |
- MessageLoop::current()->PostTask( |
- FROM_HERE, |
- Bind(&UnitTestLauncherDelegate::RunSerially, |
- Unretained(this), |
- callback_state.test_launcher, |
- test_names)); |
- } |
+ // The temporary file's directory is also temporary. |
+ DeleteFile(callback_state.output_file.DirName(), true); |
+} |
+ |
+void UnitTestLauncherDelegate::SerialGTestCallback( |
+ const GTestCallbackState& callback_state, |
+ const std::vector<std::string>& test_names, |
+ int exit_code, |
+ const TimeDelta& elapsed_time, |
+ bool was_timeout, |
+ const std::string& output) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ std::vector<std::string> tests_to_relaunch; |
+ bool called_any_callbacks = |
+ ProcessTestResults(callback_state.test_launcher, |
+ callback_state.test_names, callback_state.output_file, |
+ output, exit_code, was_timeout, &tests_to_relaunch); |
+ |
+ // There is only one test, there cannot be other tests to relaunch |
+ // due to a crash. |
+ DCHECK(tests_to_relaunch.empty()); |
+ |
+ // There is only one test, we should have called back with its result. |
+ DCHECK(called_any_callbacks); |
+ |
+ // The temporary file's directory is also temporary. |
+ DeleteFile(callback_state.output_file.DirName(), true); |
- // static |
- bool UnitTestLauncherDelegate::ProcessTestResults( |
- TestLauncher* test_launcher, |
- const std::vector<std::string>& test_names, |
- const base::FilePath& output_file, |
- const std::string& output, |
- int exit_code, |
- bool was_timeout, |
- std::vector<std::string>* tests_to_relaunch) { |
- std::vector<TestResult> test_results; |
- bool crashed = false; |
- bool have_test_results = |
- ProcessGTestOutput(output_file, &test_results, &crashed); |
- |
- bool called_any_callback = false; |
- |
- if (have_test_results) { |
- // TODO(phajdan.jr): Check for duplicates and mismatches between |
- // the results we got from XML file and tests we intended to run. |
- std::map<std::string, TestResult> results_map; |
- for (size_t i = 0; i < test_results.size(); i++) |
- results_map[test_results[i].full_name] = test_results[i]; |
- |
- 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]]; |
- if (test_result.status == TestResult::TEST_CRASH) { |
- had_interrupted_test = true; |
- |
- if (was_timeout) { |
- // Fix up the test status: we forcibly kill the child process |
- // after the timeout, so from XML results it looks just like |
- // a crash. |
- test_result.status = TestResult::TEST_TIMEOUT; |
- } |
- } else if (test_result.status == TestResult::TEST_SUCCESS || |
- test_result.status == TestResult::TEST_FAILURE) { |
- // We run multiple tests in a batch with a timeout applied |
- // to the entire batch. It is possible that with other tests |
- // running quickly some tests take longer than the per-test timeout. |
- // For consistent handling of tests independent of order and other |
- // factors, mark them as timing out. |
- if (test_result.elapsed_time > |
- TestTimeouts::test_launcher_timeout()) { |
- test_result.status = TestResult::TEST_TIMEOUT; |
- } |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, Bind(&UnitTestLauncherDelegate::RunSerially, Unretained(this), |
+ callback_state.test_launcher, test_names)); |
+} |
+ |
+// static |
+bool UnitTestLauncherDelegate::ProcessTestResults( |
+ TestLauncher* test_launcher, |
+ const std::vector<std::string>& test_names, |
+ const base::FilePath& output_file, |
+ const std::string& output, |
+ int exit_code, |
+ bool was_timeout, |
+ std::vector<std::string>* tests_to_relaunch) { |
+ std::vector<TestResult> test_results; |
+ bool crashed = false; |
+ bool have_test_results = |
+ ProcessGTestOutput(output_file, &test_results, &crashed); |
+ |
+ bool called_any_callback = false; |
+ |
+ if (have_test_results) { |
+ // TODO(phajdan.jr): Check for duplicates and mismatches between |
+ // the results we got from XML file and tests we intended to run. |
+ std::map<std::string, TestResult> results_map; |
+ for (size_t i = 0; i < test_results.size(); i++) |
+ results_map[test_results[i].full_name] = test_results[i]; |
+ |
+ 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]]; |
+ if (test_result.status == TestResult::TEST_CRASH) { |
+ had_interrupted_test = true; |
+ |
+ if (was_timeout) { |
+ // Fix up the test status: we forcibly kill the child process |
+ // after the timeout, so from XML results it looks just like |
+ // a crash. |
+ test_result.status = TestResult::TEST_TIMEOUT; |
+ } |
+ } else if (test_result.status == TestResult::TEST_SUCCESS || |
+ test_result.status == TestResult::TEST_FAILURE) { |
+ // We run multiple tests in a batch with a timeout applied |
+ // to the entire batch. It is possible that with other tests |
+ // running quickly some tests take longer than the per-test timeout. |
+ // For consistent handling of tests independent of order and other |
+ // factors, mark them as timing out. |
+ if (test_result.elapsed_time > |
+ TestTimeouts::test_launcher_timeout()) { |
+ test_result.status = TestResult::TEST_TIMEOUT; |
} |
- test_result.output_snippet = |
- GetTestOutputSnippet(test_result, output); |
- final_results.push_back(test_result); |
- } else if (had_interrupted_test) { |
- 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. |
- LOG(ERROR) << "no test result for " << test_names[i]; |
- TestResult test_result; |
- test_result.full_name = test_names[i]; |
- test_result.status = TestResult::TEST_UNKNOWN; |
- test_result.output_snippet = |
- GetTestOutputSnippet(test_result, output); |
- final_results.push_back(test_result); |
} |
+ test_result.output_snippet = GetTestOutputSnippet(test_result, output); |
+ final_results.push_back(test_result); |
+ } else if (had_interrupted_test) { |
+ 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. |
+ LOG(ERROR) << "no test result for " << test_names[i]; |
+ TestResult test_result; |
+ test_result.full_name = test_names[i]; |
+ test_result.status = TestResult::TEST_UNKNOWN; |
+ test_result.output_snippet = GetTestOutputSnippet(test_result, output); |
+ 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 processing XML output |
+ // indicates a crash but none of the test results is marked as crashing. |
- if (final_results.empty()) |
- return false; |
+ 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; |
- } |
+ 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; |
- } |
- } |
+ 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); |
- 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; |
+ return false; |
} |
- } else { |
- fprintf(stdout, |
- "Failed to get out-of-band test success data, " |
- "dumping full stdio below:\n%s\n", |
- output.c_str()); |
- fflush(stdout); |
+ } |
- // We do not have reliable details about test results (parsing test |
- // stdout is known to be unreliable), apply the executable exit code |
- // to all tests. |
- // TODO(phajdan.jr): Be smarter about this, e.g. retry each test |
- // individually. |
- for (size_t i = 0; i < test_names.size(); i++) { |
- TestResult test_result; |
- test_result.full_name = test_names[i]; |
- test_result.status = TestResult::TEST_UNKNOWN; |
- test_launcher->OnTestFinished(test_result); |
- called_any_callback = true; |
- } |
+ 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, " |
+ "dumping full stdio below:\n%s\n", |
+ output.c_str()); |
+ fflush(stdout); |
- return called_any_callback; |
+ // We do not have reliable details about test results (parsing test |
+ // stdout is known to be unreliable), apply the executable exit code |
+ // to all tests. |
+ // TODO(phajdan.jr): Be smarter about this, e.g. retry each test |
+ // individually. |
+ for (size_t i = 0; i < test_names.size(); i++) { |
+ TestResult test_result; |
+ test_result.full_name = test_names[i]; |
+ test_result.status = TestResult::TEST_UNKNOWN; |
+ test_launcher->OnTestFinished(test_result); |
+ called_any_callback = true; |
+ } |
} |
+ return called_any_callback; |
+} |
+ |
} // namespace base |