| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/test/unit_test_launcher.h" | 5 #include "base/test/unit_test_launcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 struct TestLaunchInfo { | 92 struct TestLaunchInfo { |
| 93 std::string GetFullName() const { | 93 std::string GetFullName() const { |
| 94 return test_case_name + "." + test_name; | 94 return test_case_name + "." + test_name; |
| 95 } | 95 } |
| 96 | 96 |
| 97 std::string test_case_name; | 97 std::string test_case_name; |
| 98 std::string test_name; | 98 std::string test_name; |
| 99 TestResultCallback callback; | 99 TestResultCallback callback; |
| 100 }; | 100 }; |
| 101 | 101 |
| 102 virtual std::string GetTestNameForFiltering( |
| 103 const testing::TestCase* test_case, |
| 104 const testing::TestInfo* test_info) OVERRIDE { |
| 105 DCHECK(thread_checker_.CalledOnValidThread()); |
| 106 |
| 107 return std::string(test_case->name()) + "." + test_info->name(); |
| 108 } |
| 109 |
| 102 virtual bool ShouldRunTest(const testing::TestCase* test_case, | 110 virtual bool ShouldRunTest(const testing::TestCase* test_case, |
| 103 const testing::TestInfo* test_info) OVERRIDE { | 111 const testing::TestInfo* test_info) OVERRIDE { |
| 104 DCHECK(thread_checker_.CalledOnValidThread()); | 112 DCHECK(thread_checker_.CalledOnValidThread()); |
| 105 | 113 |
| 106 // There is no additional logic to disable specific tests. | 114 // There is no additional logic to disable specific tests. |
| 107 return true; | 115 return true; |
| 108 } | 116 } |
| 109 | 117 |
| 110 virtual void RunTest(const testing::TestCase* test_case, | 118 virtual void RunTest(const testing::TestCase* test_case, |
| 111 const testing::TestInfo* test_info, | 119 const testing::TestInfo* test_info, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 Bind(&UnitTestLauncherDelegate::GTestCallback, | 168 Bind(&UnitTestLauncherDelegate::GTestCallback, |
| 161 base::Unretained(this), | 169 base::Unretained(this), |
| 162 tests_, | 170 tests_, |
| 163 output_file)); | 171 output_file)); |
| 164 tests_.clear(); | 172 tests_.clear(); |
| 165 } | 173 } |
| 166 | 174 |
| 167 void GTestCallback(const std::vector<TestLaunchInfo>& tests, | 175 void GTestCallback(const std::vector<TestLaunchInfo>& tests, |
| 168 const FilePath& output_file, | 176 const FilePath& output_file, |
| 169 int exit_code, | 177 int exit_code, |
| 178 const TimeDelta& elapsed_time, |
| 170 bool was_timeout, | 179 bool was_timeout, |
| 171 const std::string& output) { | 180 const std::string& output) { |
| 172 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
| 173 std::vector<TestLaunchInfo> tests_to_relaunch_after_interruption; | 182 std::vector<TestLaunchInfo> tests_to_relaunch_after_interruption; |
| 174 bool called_any_callbacks = | 183 bool called_any_callbacks = |
| 175 ProcessTestResults(tests, | 184 ProcessTestResults(tests, |
| 176 output_file, | 185 output_file, |
| 177 output, | 186 output, |
| 178 exit_code, | 187 exit_code, |
| 179 was_timeout, | 188 was_timeout, |
| 180 &tests_to_relaunch_after_interruption); | 189 &tests_to_relaunch_after_interruption); |
| 181 | 190 |
| 182 for (size_t i = 0; i < tests_to_relaunch_after_interruption.size(); i++) | 191 for (size_t i = 0; i < tests_to_relaunch_after_interruption.size(); i++) |
| 183 tests_.push_back(tests_to_relaunch_after_interruption[i]); | 192 tests_.push_back(tests_to_relaunch_after_interruption[i]); |
| 184 RunRemainingTests(); | 193 RunRemainingTests(); |
| 185 | 194 |
| 186 if (called_any_callbacks) | 195 if (called_any_callbacks) |
| 187 parallel_launcher_.ResetOutputWatchdog(); | 196 parallel_launcher_.ResetOutputWatchdog(); |
| 188 | 197 |
| 189 // The temporary file's directory is also temporary. | 198 // The temporary file's directory is also temporary. |
| 190 DeleteFile(output_file.DirName(), true); | 199 DeleteFile(output_file.DirName(), true); |
| 191 } | 200 } |
| 192 | 201 |
| 193 static void MaybePrintTestOutputSnippet(const TestResult& result, | |
| 194 const std::string& full_output) { | |
| 195 if (result.status == TestResult::TEST_SUCCESS) | |
| 196 return; | |
| 197 | |
| 198 size_t run_pos = full_output.find(std::string("[ RUN ] ") + | |
| 199 result.GetFullName()); | |
| 200 if (run_pos == std::string::npos) | |
| 201 return; | |
| 202 | |
| 203 size_t end_pos = full_output.find(std::string("[ FAILED ] ") + | |
| 204 result.GetFullName(), | |
| 205 run_pos); | |
| 206 if (end_pos != std::string::npos) { | |
| 207 size_t newline_pos = full_output.find("\n", end_pos); | |
| 208 if (newline_pos != std::string::npos) | |
| 209 end_pos = newline_pos + 1; | |
| 210 } | |
| 211 | |
| 212 std::string snippet(full_output.substr(run_pos)); | |
| 213 if (end_pos != std::string::npos) | |
| 214 snippet = full_output.substr(run_pos, end_pos - run_pos); | |
| 215 | |
| 216 // TODO(phajdan.jr): Indent each line of the snippet so it's more | |
| 217 // noticeable. | |
| 218 fprintf(stdout, "%s", snippet.c_str()); | |
| 219 fflush(stdout); | |
| 220 } | |
| 221 | |
| 222 static bool ProcessTestResults( | 202 static bool ProcessTestResults( |
| 223 const std::vector<TestLaunchInfo>& tests, | 203 const std::vector<TestLaunchInfo>& tests, |
| 224 const base::FilePath& output_file, | 204 const base::FilePath& output_file, |
| 225 const std::string& output, | 205 const std::string& output, |
| 226 int exit_code, | 206 int exit_code, |
| 227 bool was_timeout, | 207 bool was_timeout, |
| 228 std::vector<TestLaunchInfo>* tests_to_relaunch_after_interruption) { | 208 std::vector<TestLaunchInfo>* tests_to_relaunch_after_interruption) { |
| 229 std::vector<TestResult> test_results; | 209 std::vector<TestResult> test_results; |
| 230 bool crashed = false; | 210 bool crashed = false; |
| 231 bool have_test_results = | 211 bool have_test_results = |
| (...skipping 16 matching lines...) Expand all Loading... |
| 248 if (test_result.status == TestResult::TEST_CRASH) { | 228 if (test_result.status == TestResult::TEST_CRASH) { |
| 249 had_interrupted_test = true; | 229 had_interrupted_test = true; |
| 250 | 230 |
| 251 if (was_timeout) { | 231 if (was_timeout) { |
| 252 // Fix up the test status: we forcibly kill the child process | 232 // Fix up the test status: we forcibly kill the child process |
| 253 // after the timeout, so from XML results it looks just like | 233 // after the timeout, so from XML results it looks just like |
| 254 // a crash. | 234 // a crash. |
| 255 test_result.status = TestResult::TEST_TIMEOUT; | 235 test_result.status = TestResult::TEST_TIMEOUT; |
| 256 } | 236 } |
| 257 } | 237 } |
| 258 MaybePrintTestOutputSnippet(test_result, output); | 238 PrintTestOutputSnippetOnFailure(test_result, output); |
| 259 tests[i].callback.Run(test_result); | 239 tests[i].callback.Run(test_result); |
| 260 called_any_callback = true; | 240 called_any_callback = true; |
| 261 } else if (had_interrupted_test) { | 241 } else if (had_interrupted_test) { |
| 262 tests_to_relaunch_after_interruption->push_back(tests[i]); | 242 tests_to_relaunch_after_interruption->push_back(tests[i]); |
| 263 } else { | 243 } else { |
| 264 // TODO(phajdan.jr): Explicitly pass the info that the test didn't | 244 // TODO(phajdan.jr): Explicitly pass the info that the test didn't |
| 265 // run for a mysterious reason. | 245 // run for a mysterious reason. |
| 266 LOG(ERROR) << "no test result for " << tests[i].GetFullName(); | 246 LOG(ERROR) << "no test result for " << tests[i].GetFullName(); |
| 267 TestResult test_result; | 247 TestResult test_result; |
| 268 test_result.test_case_name = tests[i].test_case_name; | 248 test_result.test_case_name = tests[i].test_case_name; |
| 269 test_result.test_name = tests[i].test_name; | 249 test_result.test_name = tests[i].test_name; |
| 270 test_result.status = TestResult::TEST_UNKNOWN; | 250 test_result.status = TestResult::TEST_UNKNOWN; |
| 271 MaybePrintTestOutputSnippet(test_result, output); | 251 PrintTestOutputSnippetOnFailure(test_result, output); |
| 272 tests[i].callback.Run(test_result); | 252 tests[i].callback.Run(test_result); |
| 273 called_any_callback = true; | 253 called_any_callback = true; |
| 274 } | 254 } |
| 275 } | 255 } |
| 276 | 256 |
| 277 // TODO(phajdan.jr): Handle the case where processing XML output | 257 // TODO(phajdan.jr): Handle the case where processing XML output |
| 278 // indicates a crash but none of the test results is marked as crashing. | 258 // indicates a crash but none of the test results is marked as crashing. |
| 279 | 259 |
| 280 // TODO(phajdan.jr): Handle the case where the exit code is non-zero | 260 // TODO(phajdan.jr): Handle the case where the exit code is non-zero |
| 281 // but results file indicates that all tests passed (e.g. crash during | 261 // but results file indicates that all tests passed (e.g. crash during |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 | 354 |
| 375 fprintf(stdout, | 355 fprintf(stdout, |
| 376 "Tests took %" PRId64 " seconds.\n", | 356 "Tests took %" PRId64 " seconds.\n", |
| 377 (base::TimeTicks::Now() - start_time).InSeconds()); | 357 (base::TimeTicks::Now() - start_time).InSeconds()); |
| 378 fflush(stdout); | 358 fflush(stdout); |
| 379 | 359 |
| 380 return exit_code; | 360 return exit_code; |
| 381 } | 361 } |
| 382 | 362 |
| 383 } // namespace base | 363 } // namespace base |
| OLD | NEW |