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 |