| 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/launcher/test_launcher.h" | 5 #include "base/test/launcher/test_launcher.h" |
| 6 | 6 |
| 7 #if defined(OS_POSIX) | 7 #if defined(OS_POSIX) |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #endif | 9 #endif |
| 10 | 10 |
| 11 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/environment.h" | 14 #include "base/environment.h" |
| 15 #include "base/file_util.h" | 15 #include "base/file_util.h" |
| 16 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
| 17 #include "base/format_macros.h" | 17 #include "base/format_macros.h" |
| 18 #include "base/lazy_instance.h" | 18 #include "base/lazy_instance.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/memory/scoped_ptr.h" | 20 #include "base/memory/scoped_ptr.h" |
| 21 #include "base/message_loop/message_loop.h" | 21 #include "base/message_loop/message_loop.h" |
| 22 #include "base/process/kill.h" | 22 #include "base/process/kill.h" |
| 23 #include "base/process/launch.h" | 23 #include "base/process/launch.h" |
| 24 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
| 25 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
| 26 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
| 27 #include "base/test/launcher/test_results_tracker.h" | 27 #include "base/test/launcher/test_results_tracker.h" |
| 28 #include "base/test/sequenced_worker_pool_owner.h" |
| 28 #include "base/test/test_switches.h" | 29 #include "base/test/test_switches.h" |
| 29 #include "base/test/test_timeouts.h" | 30 #include "base/test/test_timeouts.h" |
| 30 #include "base/threading/thread_checker.h" | 31 #include "base/threading/thread_checker.h" |
| 31 #include "base/time/time.h" | 32 #include "base/time/time.h" |
| 32 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
| 33 | 34 |
| 34 #if defined(OS_MACOSX) | 35 #if defined(OS_MACOSX) |
| 35 #include "base/mac/scoped_nsautorelease_pool.h" | 36 #include "base/mac/scoped_nsautorelease_pool.h" |
| 36 #endif | 37 #endif |
| 37 | 38 |
| 38 namespace base { | 39 namespace base { |
| 39 | 40 |
| 40 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . | 41 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . |
| 41 using ::operator<<; | 42 using ::operator<<; |
| 42 | 43 |
| 43 // The environment variable name for the total number of test shards. | 44 // The environment variable name for the total number of test shards. |
| 44 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; | 45 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; |
| 45 // The environment variable name for the test shard index. | 46 // The environment variable name for the test shard index. |
| 46 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; | 47 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; |
| 47 | 48 |
| 48 namespace { | 49 namespace { |
| 49 | 50 |
| 51 // Maximum time of no output after which we print list of processes still |
| 52 // running. This deliberately doesn't use TestTimeouts (which is otherwise |
| 53 // a recommended solution), because they can be increased. This would defeat |
| 54 // the purpose of this timeout, which is 1) to avoid buildbot "no output for |
| 55 // X seconds" timeout killing the process 2) help communicate status of |
| 56 // the test launcher to people looking at the output (no output for a long |
| 57 // time is mysterious and gives no info about what is happening) 3) help |
| 58 // debugging in case the process hangs anyway. |
| 59 const int kOutputTimeoutSeconds = 15; |
| 60 |
| 50 // Set of live launch test processes with corresponding lock (it is allowed | 61 // Set of live launch test processes with corresponding lock (it is allowed |
| 51 // for callers to launch processes on different threads). | 62 // for callers to launch processes on different threads). |
| 52 LazyInstance<std::set<ProcessHandle> > g_live_process_handles | 63 LazyInstance<std::map<ProcessHandle, CommandLine> > g_live_processes |
| 53 = LAZY_INSTANCE_INITIALIZER; | 64 = LAZY_INSTANCE_INITIALIZER; |
| 54 LazyInstance<Lock> g_live_process_handles_lock = LAZY_INSTANCE_INITIALIZER; | 65 LazyInstance<Lock> g_live_processes_lock = LAZY_INSTANCE_INITIALIZER; |
| 55 | 66 |
| 56 #if defined(OS_POSIX) | 67 #if defined(OS_POSIX) |
| 57 // Self-pipe that makes it possible to do complex shutdown handling | 68 // Self-pipe that makes it possible to do complex shutdown handling |
| 58 // outside of the signal handler. | 69 // outside of the signal handler. |
| 59 int g_shutdown_pipe[2] = { -1, -1 }; | 70 int g_shutdown_pipe[2] = { -1, -1 }; |
| 60 | 71 |
| 61 void ShutdownPipeSignalHandler(int signal) { | 72 void ShutdownPipeSignalHandler(int signal) { |
| 62 HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1)); | 73 HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1)); |
| 63 } | 74 } |
| 64 | 75 |
| 65 void KillSpawnedTestProcesses() { | 76 void KillSpawnedTestProcesses() { |
| 66 // Keep the lock until exiting the process to prevent further processes | 77 // Keep the lock until exiting the process to prevent further processes |
| 67 // from being spawned. | 78 // from being spawned. |
| 68 AutoLock lock(g_live_process_handles_lock.Get()); | 79 AutoLock lock(g_live_processes_lock.Get()); |
| 69 | 80 |
| 70 fprintf(stdout, | 81 fprintf(stdout, |
| 71 "Sending SIGTERM to %" PRIuS " child processes... ", | 82 "Sending SIGTERM to %" PRIuS " child processes... ", |
| 72 g_live_process_handles.Get().size()); | 83 g_live_processes.Get().size()); |
| 73 fflush(stdout); | 84 fflush(stdout); |
| 74 | 85 |
| 75 for (std::set<ProcessHandle>::iterator i = | 86 for (std::map<ProcessHandle, CommandLine>::iterator i = |
| 76 g_live_process_handles.Get().begin(); | 87 g_live_processes.Get().begin(); |
| 77 i != g_live_process_handles.Get().end(); | 88 i != g_live_processes.Get().end(); |
| 78 ++i) { | 89 ++i) { |
| 79 kill((-1) * (*i), SIGTERM); // Send the signal to entire process group. | 90 // Send the signal to entire process group. |
| 91 kill((-1) * (i->first), SIGTERM); |
| 80 } | 92 } |
| 81 | 93 |
| 82 fprintf(stdout, | 94 fprintf(stdout, |
| 83 "done.\nGiving processes a chance to terminate cleanly... "); | 95 "done.\nGiving processes a chance to terminate cleanly... "); |
| 84 fflush(stdout); | 96 fflush(stdout); |
| 85 | 97 |
| 86 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); | 98 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); |
| 87 | 99 |
| 88 fprintf(stdout, "done.\n"); | 100 fprintf(stdout, "done.\n"); |
| 89 fflush(stdout); | 101 fflush(stdout); |
| 90 | 102 |
| 91 fprintf(stdout, | 103 fprintf(stdout, |
| 92 "Sending SIGKILL to %" PRIuS " child processes... ", | 104 "Sending SIGKILL to %" PRIuS " child processes... ", |
| 93 g_live_process_handles.Get().size()); | 105 g_live_processes.Get().size()); |
| 94 fflush(stdout); | 106 fflush(stdout); |
| 95 | 107 |
| 96 for (std::set<ProcessHandle>::iterator i = | 108 for (std::map<ProcessHandle, CommandLine>::iterator i = |
| 97 g_live_process_handles.Get().begin(); | 109 g_live_processes.Get().begin(); |
| 98 i != g_live_process_handles.Get().end(); | 110 i != g_live_processes.Get().end(); |
| 99 ++i) { | 111 ++i) { |
| 100 kill((-1) * (*i), SIGKILL); // Send the signal to entire process group. | 112 // Send the signal to entire process group. |
| 113 kill((-1) * (i->first), SIGKILL); |
| 101 } | 114 } |
| 102 | 115 |
| 103 fprintf(stdout, "done.\n"); | 116 fprintf(stdout, "done.\n"); |
| 104 fflush(stdout); | 117 fflush(stdout); |
| 105 } | 118 } |
| 106 | 119 |
| 107 // I/O watcher for the reading end of the self-pipe above. | 120 // I/O watcher for the reading end of the self-pipe above. |
| 108 // Terminates any launched child processes and exits the process. | 121 // Terminates any launched child processes and exits the process. |
| 109 class SignalFDWatcher : public MessageLoopForIO::Watcher { | 122 class SignalFDWatcher : public MessageLoopForIO::Watcher { |
| 110 public: | 123 public: |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 // Returns if no more pattern can be found. | 200 // Returns if no more pattern can be found. |
| 188 if (cur_pattern == NULL) { | 201 if (cur_pattern == NULL) { |
| 189 return false; | 202 return false; |
| 190 } | 203 } |
| 191 | 204 |
| 192 // Skips the pattern separater (the ':' character). | 205 // Skips the pattern separater (the ':' character). |
| 193 cur_pattern++; | 206 cur_pattern++; |
| 194 } | 207 } |
| 195 } | 208 } |
| 196 | 209 |
| 210 void RunCallback( |
| 211 const TestLauncher::LaunchChildGTestProcessCallback& callback, |
| 212 int exit_code, |
| 213 const TimeDelta& elapsed_time, |
| 214 bool was_timeout, |
| 215 const std::string& output) { |
| 216 callback.Run(exit_code, elapsed_time, was_timeout, output); |
| 217 } |
| 218 |
| 219 void DoLaunchChildTestProcess( |
| 220 const CommandLine& command_line, |
| 221 base::TimeDelta timeout, |
| 222 scoped_refptr<MessageLoopProxy> message_loop_proxy, |
| 223 const TestLauncher::LaunchChildGTestProcessCallback& callback) { |
| 224 TimeTicks start_time = TimeTicks::Now(); |
| 225 |
| 226 // Redirect child process output to a file. |
| 227 base::FilePath output_file; |
| 228 CHECK(file_util::CreateTemporaryFile(&output_file)); |
| 229 |
| 230 LaunchOptions options; |
| 231 #if defined(OS_WIN) |
| 232 // Make the file handle inheritable by the child. |
| 233 SECURITY_ATTRIBUTES sa_attr; |
| 234 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 235 sa_attr.lpSecurityDescriptor = NULL; |
| 236 sa_attr.bInheritHandle = TRUE; |
| 237 |
| 238 win::ScopedHandle handle(CreateFile(output_file.value().c_str(), |
| 239 GENERIC_WRITE, |
| 240 FILE_SHARE_READ | FILE_SHARE_DELETE, |
| 241 &sa_attr, |
| 242 OPEN_EXISTING, |
| 243 FILE_ATTRIBUTE_TEMPORARY, |
| 244 NULL)); |
| 245 CHECK(handle.IsValid()); |
| 246 options.inherit_handles = true; |
| 247 options.stdin_handle = INVALID_HANDLE_VALUE; |
| 248 options.stdout_handle = handle.Get(); |
| 249 options.stderr_handle = handle.Get(); |
| 250 #elif defined(OS_POSIX) |
| 251 options.new_process_group = true; |
| 252 |
| 253 int output_file_fd = open(output_file.value().c_str(), O_RDWR); |
| 254 CHECK_GE(output_file_fd, 0); |
| 255 |
| 256 file_util::ScopedFD output_file_fd_closer(&output_file_fd); |
| 257 |
| 258 base::FileHandleMappingVector fds_mapping; |
| 259 fds_mapping.push_back(std::make_pair(output_file_fd, STDOUT_FILENO)); |
| 260 fds_mapping.push_back(std::make_pair(output_file_fd, STDERR_FILENO)); |
| 261 options.fds_to_remap = &fds_mapping; |
| 262 #endif |
| 263 |
| 264 bool was_timeout = false; |
| 265 int exit_code = LaunchChildTestProcessWithOptions( |
| 266 command_line, options, timeout, &was_timeout); |
| 267 |
| 268 #if defined(OS_WIN) |
| 269 FlushFileBuffers(handle.Get()); |
| 270 handle.Close(); |
| 271 #elif defined(OS_POSIX) |
| 272 output_file_fd_closer.reset(); |
| 273 #endif |
| 274 |
| 275 std::string output_file_contents; |
| 276 CHECK(base::ReadFileToString(output_file, &output_file_contents)); |
| 277 |
| 278 if (!base::DeleteFile(output_file, false)) { |
| 279 // This needs to be non-fatal at least for Windows. |
| 280 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); |
| 281 } |
| 282 |
| 283 // Run target callback on the thread it was originating from, not on |
| 284 // a worker pool thread. |
| 285 message_loop_proxy->PostTask( |
| 286 FROM_HERE, |
| 287 Bind(&RunCallback, |
| 288 callback, |
| 289 exit_code, |
| 290 TimeTicks::Now() - start_time, |
| 291 was_timeout, |
| 292 output_file_contents)); |
| 293 } |
| 294 |
| 197 } // namespace | 295 } // namespace |
| 198 | 296 |
| 199 const char kGTestFilterFlag[] = "gtest_filter"; | 297 const char kGTestFilterFlag[] = "gtest_filter"; |
| 200 const char kGTestHelpFlag[] = "gtest_help"; | 298 const char kGTestHelpFlag[] = "gtest_help"; |
| 201 const char kGTestListTestsFlag[] = "gtest_list_tests"; | 299 const char kGTestListTestsFlag[] = "gtest_list_tests"; |
| 202 const char kGTestRepeatFlag[] = "gtest_repeat"; | 300 const char kGTestRepeatFlag[] = "gtest_repeat"; |
| 203 const char kGTestRunDisabledTestsFlag[] = "gtest_also_run_disabled_tests"; | 301 const char kGTestRunDisabledTestsFlag[] = "gtest_also_run_disabled_tests"; |
| 204 const char kGTestOutputFlag[] = "gtest_output"; | 302 const char kGTestOutputFlag[] = "gtest_output"; |
| 205 | 303 |
| 206 TestLauncherDelegate::~TestLauncherDelegate() { | 304 TestLauncherDelegate::~TestLauncherDelegate() { |
| 207 } | 305 } |
| 208 | 306 |
| 209 TestLauncher::TestLauncher(TestLauncherDelegate* launcher_delegate) | 307 TestLauncher::TestLauncher(TestLauncherDelegate* launcher_delegate, |
| 308 size_t parallel_jobs) |
| 210 : launcher_delegate_(launcher_delegate), | 309 : launcher_delegate_(launcher_delegate), |
| 211 total_shards_(1), | 310 total_shards_(1), |
| 212 shard_index_(0), | 311 shard_index_(0), |
| 213 cycles_(1), | 312 cycles_(1), |
| 214 test_started_count_(0), | 313 test_started_count_(0), |
| 215 test_finished_count_(0), | 314 test_finished_count_(0), |
| 216 test_success_count_(0), | 315 test_success_count_(0), |
| 217 test_broken_count_(0), | 316 test_broken_count_(0), |
| 218 retry_count_(0), | 317 retry_count_(0), |
| 219 retry_limit_(3), // TODO(phajdan.jr): Make a flag control this. | 318 retry_limit_(3), // TODO(phajdan.jr): Make a flag control this. |
| 220 run_result_(true) { | 319 run_result_(true), |
| 320 watchdog_timer_(FROM_HERE, |
| 321 TimeDelta::FromSeconds(kOutputTimeoutSeconds), |
| 322 this, |
| 323 &TestLauncher::OnOutputTimeout), |
| 324 worker_pool_owner_( |
| 325 new SequencedWorkerPoolOwner(parallel_jobs, "test_launcher")) { |
| 221 } | 326 } |
| 222 | 327 |
| 223 TestLauncher::~TestLauncher() { | 328 TestLauncher::~TestLauncher() { |
| 329 worker_pool_owner_->pool()->Shutdown(); |
| 224 } | 330 } |
| 225 | 331 |
| 226 bool TestLauncher::Run(int argc, char** argv) { | 332 bool TestLauncher::Run(int argc, char** argv) { |
| 227 if (!Init()) | 333 if (!Init()) |
| 228 return false; | 334 return false; |
| 229 | 335 |
| 230 #if defined(OS_POSIX) | 336 #if defined(OS_POSIX) |
| 231 CHECK_EQ(0, pipe(g_shutdown_pipe)); | 337 CHECK_EQ(0, pipe(g_shutdown_pipe)); |
| 232 | 338 |
| 233 struct sigaction action; | 339 struct sigaction action; |
| 234 memset(&action, 0, sizeof(action)); | 340 memset(&action, 0, sizeof(action)); |
| 235 sigemptyset(&action.sa_mask); | 341 sigemptyset(&action.sa_mask); |
| 236 action.sa_handler = &ShutdownPipeSignalHandler; | 342 action.sa_handler = &ShutdownPipeSignalHandler; |
| 237 | 343 |
| 238 CHECK_EQ(0, sigaction(SIGINT, &action, NULL)); | 344 CHECK_EQ(0, sigaction(SIGINT, &action, NULL)); |
| 239 CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL)); | 345 CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL)); |
| 240 CHECK_EQ(0, sigaction(SIGTERM, &action, NULL)); | 346 CHECK_EQ(0, sigaction(SIGTERM, &action, NULL)); |
| 241 | 347 |
| 242 MessageLoopForIO::FileDescriptorWatcher controller; | 348 MessageLoopForIO::FileDescriptorWatcher controller; |
| 243 SignalFDWatcher watcher; | 349 SignalFDWatcher watcher; |
| 244 | 350 |
| 245 CHECK(MessageLoopForIO::current()->WatchFileDescriptor( | 351 CHECK(MessageLoopForIO::current()->WatchFileDescriptor( |
| 246 g_shutdown_pipe[0], | 352 g_shutdown_pipe[0], |
| 247 true, | 353 true, |
| 248 MessageLoopForIO::WATCH_READ, | 354 MessageLoopForIO::WATCH_READ, |
| 249 &controller, | 355 &controller, |
| 250 &watcher)); | 356 &watcher)); |
| 251 #endif // defined(OS_POSIX) | 357 #endif // defined(OS_POSIX) |
| 252 | 358 |
| 359 // Start the watchdog timer. |
| 360 watchdog_timer_.Reset(); |
| 361 |
| 253 MessageLoop::current()->PostTask( | 362 MessageLoop::current()->PostTask( |
| 254 FROM_HERE, | 363 FROM_HERE, |
| 255 Bind(&TestLauncher::RunTestIteration, Unretained(this))); | 364 Bind(&TestLauncher::RunTestIteration, Unretained(this))); |
| 256 | 365 |
| 257 MessageLoop::current()->Run(); | 366 MessageLoop::current()->Run(); |
| 258 | 367 |
| 259 if (cycles_ != 1) | 368 if (cycles_ != 1) |
| 260 results_tracker_.PrintSummaryOfAllIterations(); | 369 results_tracker_.PrintSummaryOfAllIterations(); |
| 261 | 370 |
| 262 MaybeSaveSummaryAsJSON(); | 371 MaybeSaveSummaryAsJSON(); |
| 263 | 372 |
| 264 return run_result_; | 373 return run_result_; |
| 265 } | 374 } |
| 266 | 375 |
| 376 void TestLauncher::LaunchChildGTestProcess( |
| 377 const CommandLine& command_line, |
| 378 const std::string& wrapper, |
| 379 base::TimeDelta timeout, |
| 380 const LaunchChildGTestProcessCallback& callback) { |
| 381 DCHECK(thread_checker_.CalledOnValidThread()); |
| 382 |
| 383 // Record the exact command line used to launch the child. |
| 384 CommandLine new_command_line( |
| 385 PrepareCommandLineForGTest(command_line, wrapper)); |
| 386 |
| 387 worker_pool_owner_->pool()->PostWorkerTask( |
| 388 FROM_HERE, |
| 389 Bind(&DoLaunchChildTestProcess, |
| 390 new_command_line, |
| 391 timeout, |
| 392 MessageLoopProxy::current(), |
| 393 Bind(&TestLauncher::OnLaunchTestProcessFinished, |
| 394 Unretained(this), |
| 395 callback))); |
| 396 } |
| 397 |
| 267 void TestLauncher::OnTestFinished(const TestResult& result) { | 398 void TestLauncher::OnTestFinished(const TestResult& result) { |
| 268 ++test_finished_count_; | 399 ++test_finished_count_; |
| 269 | 400 |
| 270 bool print_snippet = false; | 401 bool print_snippet = false; |
| 271 std::string print_test_stdio("auto"); | 402 std::string print_test_stdio("auto"); |
| 272 if (CommandLine::ForCurrentProcess()->HasSwitch( | 403 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 273 switches::kTestLauncherPrintTestStdio)) { | 404 switches::kTestLauncherPrintTestStdio)) { |
| 274 print_test_stdio = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 405 print_test_stdio = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 275 switches::kTestLauncherPrintTestStdio); | 406 switches::kTestLauncherPrintTestStdio); |
| 276 } | 407 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 status_line.append("(SKIPPED)"); | 445 status_line.append("(SKIPPED)"); |
| 315 } else if (result.status == TestResult::TEST_UNKNOWN) { | 446 } else if (result.status == TestResult::TEST_UNKNOWN) { |
| 316 status_line.append("(UNKNOWN)"); | 447 status_line.append("(UNKNOWN)"); |
| 317 } else { | 448 } else { |
| 318 // Fail very loudly so it's not ignored. | 449 // Fail very loudly so it's not ignored. |
| 319 CHECK(false) << "Unhandled test result status: " << result.status; | 450 CHECK(false) << "Unhandled test result status: " << result.status; |
| 320 } | 451 } |
| 321 fprintf(stdout, "%s\n", status_line.c_str()); | 452 fprintf(stdout, "%s\n", status_line.c_str()); |
| 322 fflush(stdout); | 453 fflush(stdout); |
| 323 | 454 |
| 455 // We just printed a status line, reset the watchdog timer. |
| 456 watchdog_timer_.Reset(); |
| 457 |
| 324 if (test_finished_count_ == test_started_count_) { | 458 if (test_finished_count_ == test_started_count_) { |
| 325 if (!tests_to_retry_.empty() && retry_count_ < retry_limit_) { | 459 if (!tests_to_retry_.empty() && retry_count_ < retry_limit_) { |
| 326 retry_count_++; | 460 retry_count_++; |
| 327 | 461 |
| 328 std::vector<std::string> test_names(tests_to_retry_.begin(), | 462 std::vector<std::string> test_names(tests_to_retry_.begin(), |
| 329 tests_to_retry_.end()); | 463 tests_to_retry_.end()); |
| 330 | 464 |
| 331 tests_to_retry_.clear(); | 465 tests_to_retry_.clear(); |
| 332 | 466 |
| 333 size_t retry_started_count = | 467 size_t retry_started_count = |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 test_broken_count_ = 0; | 664 test_broken_count_ = 0; |
| 531 retry_count_ = 0; | 665 retry_count_ = 0; |
| 532 tests_to_retry_.clear(); | 666 tests_to_retry_.clear(); |
| 533 results_tracker_.OnTestIterationStarting(); | 667 results_tracker_.OnTestIterationStarting(); |
| 534 launcher_delegate_->OnTestIterationStarting(); | 668 launcher_delegate_->OnTestIterationStarting(); |
| 535 | 669 |
| 536 MessageLoop::current()->PostTask( | 670 MessageLoop::current()->PostTask( |
| 537 FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this))); | 671 FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this))); |
| 538 } | 672 } |
| 539 | 673 |
| 540 void TestLauncher::OnAllTestsStarted() { | |
| 541 } | |
| 542 | |
| 543 void TestLauncher::MaybeSaveSummaryAsJSON() { | 674 void TestLauncher::MaybeSaveSummaryAsJSON() { |
| 544 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 675 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 545 if (command_line->HasSwitch(switches::kTestLauncherSummaryOutput)) { | 676 if (command_line->HasSwitch(switches::kTestLauncherSummaryOutput)) { |
| 546 FilePath summary_path(command_line->GetSwitchValuePath( | 677 FilePath summary_path(command_line->GetSwitchValuePath( |
| 547 switches::kTestLauncherSummaryOutput)); | 678 switches::kTestLauncherSummaryOutput)); |
| 548 if (!results_tracker_.SaveSummaryAsJSON(summary_path)) { | 679 if (!results_tracker_.SaveSummaryAsJSON(summary_path)) { |
| 549 LOG(ERROR) << "Failed to save test launcher output summary."; | 680 LOG(ERROR) << "Failed to save test launcher output summary."; |
| 550 } | 681 } |
| 551 } | 682 } |
| 552 } | 683 } |
| 553 | 684 |
| 685 void TestLauncher::OnLaunchTestProcessFinished( |
| 686 const LaunchChildGTestProcessCallback& callback, |
| 687 int exit_code, |
| 688 const TimeDelta& elapsed_time, |
| 689 bool was_timeout, |
| 690 const std::string& output) { |
| 691 DCHECK(thread_checker_.CalledOnValidThread()); |
| 692 |
| 693 callback.Run(exit_code, elapsed_time, was_timeout, output); |
| 694 } |
| 695 |
| 696 void TestLauncher::OnOutputTimeout() { |
| 697 DCHECK(thread_checker_.CalledOnValidThread()); |
| 698 |
| 699 AutoLock lock(g_live_processes_lock.Get()); |
| 700 |
| 701 fprintf(stdout, "Still waiting for the following processes to finish:\n"); |
| 702 |
| 703 for (std::map<ProcessHandle, CommandLine>::iterator i = |
| 704 g_live_processes.Get().begin(); |
| 705 i != g_live_processes.Get().end(); |
| 706 ++i) { |
| 707 #if defined(OS_WIN) |
| 708 fwprintf(stdout, L"\t%s\n", i->second.GetCommandLineString().c_str()); |
| 709 #else |
| 710 fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str()); |
| 711 #endif |
| 712 } |
| 713 |
| 714 fflush(stdout); |
| 715 |
| 716 // Arm the timer again - otherwise it would fire only once. |
| 717 watchdog_timer_.Reset(); |
| 718 } |
| 719 |
| 554 std::string GetTestOutputSnippet(const TestResult& result, | 720 std::string GetTestOutputSnippet(const TestResult& result, |
| 555 const std::string& full_output) { | 721 const std::string& full_output) { |
| 556 size_t run_pos = full_output.find(std::string("[ RUN ] ") + | 722 size_t run_pos = full_output.find(std::string("[ RUN ] ") + |
| 557 result.full_name); | 723 result.full_name); |
| 558 if (run_pos == std::string::npos) | 724 if (run_pos == std::string::npos) |
| 559 return std::string(); | 725 return std::string(); |
| 560 | 726 |
| 561 size_t end_pos = full_output.find(std::string("[ FAILED ] ") + | 727 size_t end_pos = full_output.find(std::string("[ FAILED ] ") + |
| 562 result.full_name, | 728 result.full_name, |
| 563 run_pos); | 729 run_pos); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 658 | 824 |
| 659 new_options.job_handle = job_handle.Get(); | 825 new_options.job_handle = job_handle.Get(); |
| 660 #endif // defined(OS_WIN) | 826 #endif // defined(OS_WIN) |
| 661 | 827 |
| 662 base::ProcessHandle process_handle; | 828 base::ProcessHandle process_handle; |
| 663 | 829 |
| 664 { | 830 { |
| 665 // Note how we grab the lock before the process possibly gets created. | 831 // Note how we grab the lock before the process possibly gets created. |
| 666 // This ensures that when the lock is held, ALL the processes are registered | 832 // This ensures that when the lock is held, ALL the processes are registered |
| 667 // in the set. | 833 // in the set. |
| 668 AutoLock lock(g_live_process_handles_lock.Get()); | 834 AutoLock lock(g_live_processes_lock.Get()); |
| 669 | 835 |
| 670 if (!base::LaunchProcess(command_line, new_options, &process_handle)) | 836 if (!base::LaunchProcess(command_line, new_options, &process_handle)) |
| 671 return -1; | 837 return -1; |
| 672 | 838 |
| 673 g_live_process_handles.Get().insert(process_handle); | 839 g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); |
| 674 } | 840 } |
| 675 | 841 |
| 676 int exit_code = 0; | 842 int exit_code = 0; |
| 677 if (!base::WaitForExitCodeWithTimeout(process_handle, | 843 if (!base::WaitForExitCodeWithTimeout(process_handle, |
| 678 &exit_code, | 844 &exit_code, |
| 679 timeout)) { | 845 timeout)) { |
| 680 *was_timeout = true; | 846 *was_timeout = true; |
| 681 exit_code = -1; // Set a non-zero exit code to signal a failure. | 847 exit_code = -1; // Set a non-zero exit code to signal a failure. |
| 682 | 848 |
| 683 // Ensure that the process terminates. | 849 // Ensure that the process terminates. |
| 684 base::KillProcess(process_handle, -1, true); | 850 base::KillProcess(process_handle, -1, true); |
| 685 } | 851 } |
| 686 | 852 |
| 687 { | 853 { |
| 688 // Note how we grab the log before issuing a possibly broad process kill. | 854 // Note how we grab the log before issuing a possibly broad process kill. |
| 689 // Other code parts that grab the log kill processes, so avoid trying | 855 // Other code parts that grab the log kill processes, so avoid trying |
| 690 // to do that twice and trigger all kinds of log messages. | 856 // to do that twice and trigger all kinds of log messages. |
| 691 AutoLock lock(g_live_process_handles_lock.Get()); | 857 AutoLock lock(g_live_processes_lock.Get()); |
| 692 | 858 |
| 693 #if defined(OS_POSIX) | 859 #if defined(OS_POSIX) |
| 694 if (exit_code != 0) { | 860 if (exit_code != 0) { |
| 695 // On POSIX, in case the test does not exit cleanly, either due to a crash | 861 // On POSIX, in case the test does not exit cleanly, either due to a crash |
| 696 // or due to it timing out, we need to clean up any child processes that | 862 // or due to it timing out, we need to clean up any child processes that |
| 697 // it might have created. On Windows, child processes are automatically | 863 // it might have created. On Windows, child processes are automatically |
| 698 // cleaned up using JobObjects. | 864 // cleaned up using JobObjects. |
| 699 base::KillProcessGroup(process_handle); | 865 base::KillProcessGroup(process_handle); |
| 700 } | 866 } |
| 701 #endif | 867 #endif |
| 702 | 868 |
| 703 g_live_process_handles.Get().erase(process_handle); | 869 g_live_processes.Get().erase(process_handle); |
| 704 } | 870 } |
| 705 | 871 |
| 706 base::CloseProcessHandle(process_handle); | 872 base::CloseProcessHandle(process_handle); |
| 707 | 873 |
| 708 return exit_code; | 874 return exit_code; |
| 709 } | 875 } |
| 710 | 876 |
| 711 } // namespace base | 877 } // namespace base |
| OLD | NEW |