| 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 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | 221 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); |
| 222 iter != switches.end(); ++iter) { | 222 iter != switches.end(); ++iter) { |
| 223 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); | 223 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); |
| 224 } | 224 } |
| 225 | 225 |
| 226 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine | 226 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine |
| 227 // does not really support removing switches well, and trying to do that | 227 // does not really support removing switches well, and trying to do that |
| 228 // on a CommandLine with a wrapper is known to break. | 228 // on a CommandLine with a wrapper is known to break. |
| 229 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. | 229 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. |
| 230 #if defined(OS_WIN) | 230 #if defined(OS_WIN) |
| 231 new_command_line.PrependWrapper(ASCIIToWide(wrapper)); | 231 new_command_line.PrependWrapper(ASCIIToUTF16(wrapper)); |
| 232 #elif defined(OS_POSIX) | 232 #elif defined(OS_POSIX) |
| 233 new_command_line.PrependWrapper(wrapper); | 233 new_command_line.PrependWrapper(wrapper); |
| 234 #endif | 234 #endif |
| 235 | 235 |
| 236 return new_command_line; | 236 return new_command_line; |
| 237 } | 237 } |
| 238 | 238 |
| 239 // Launches a child process using |command_line|. If the child process is still | 239 // Launches a child process using |command_line|. If the child process is still |
| 240 // running after |timeout|, it is terminated and |*was_timeout| is set to true. | 240 // running after |timeout|, it is terminated and |*was_timeout| is set to true. |
| 241 // Returns exit code of the process. | 241 // Returns exit code of the process. |
| 242 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | 242 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 243 const LaunchOptions& options, | 243 const LaunchOptions& options, |
| 244 int flags, | 244 int flags, |
| 245 base::TimeDelta timeout, | 245 TimeDelta timeout, |
| 246 bool* was_timeout) { | 246 bool* was_timeout) { |
| 247 #if defined(OS_POSIX) | 247 #if defined(OS_POSIX) |
| 248 // Make sure an option we rely on is present - see LaunchChildGTestProcess. | 248 // Make sure an option we rely on is present - see LaunchChildGTestProcess. |
| 249 DCHECK(options.new_process_group); | 249 DCHECK(options.new_process_group); |
| 250 #endif | 250 #endif |
| 251 | 251 |
| 252 LaunchOptions new_options(options); | 252 LaunchOptions new_options(options); |
| 253 | 253 |
| 254 #if defined(OS_WIN) | 254 #if defined(OS_WIN) |
| 255 DCHECK(!new_options.job_handle); | 255 DCHECK(!new_options.job_handle); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 280 } | 280 } |
| 281 #endif // defined(OS_WIN) | 281 #endif // defined(OS_WIN) |
| 282 | 282 |
| 283 #if defined(OS_LINUX) | 283 #if defined(OS_LINUX) |
| 284 // To prevent accidental privilege sharing to an untrusted child, processes | 284 // To prevent accidental privilege sharing to an untrusted child, processes |
| 285 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this | 285 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this |
| 286 // new child will be privileged and trusted. | 286 // new child will be privileged and trusted. |
| 287 new_options.allow_new_privs = true; | 287 new_options.allow_new_privs = true; |
| 288 #endif | 288 #endif |
| 289 | 289 |
| 290 base::ProcessHandle process_handle; | 290 ProcessHandle process_handle; |
| 291 | 291 |
| 292 { | 292 { |
| 293 // Note how we grab the lock before the process possibly gets created. | 293 // Note how we grab the lock before the process possibly gets created. |
| 294 // This ensures that when the lock is held, ALL the processes are registered | 294 // This ensures that when the lock is held, ALL the processes are registered |
| 295 // in the set. | 295 // in the set. |
| 296 AutoLock lock(g_live_processes_lock.Get()); | 296 AutoLock lock(g_live_processes_lock.Get()); |
| 297 | 297 |
| 298 if (!base::LaunchProcess(command_line, new_options, &process_handle)) | 298 if (!LaunchProcess(command_line, new_options, &process_handle)) |
| 299 return -1; | 299 return -1; |
| 300 | 300 |
| 301 g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); | 301 g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); |
| 302 } | 302 } |
| 303 | 303 |
| 304 int exit_code = 0; | 304 int exit_code = 0; |
| 305 if (!base::WaitForExitCodeWithTimeout(process_handle, | 305 if (!WaitForExitCodeWithTimeout(process_handle, &exit_code, timeout)) { |
| 306 &exit_code, | |
| 307 timeout)) { | |
| 308 *was_timeout = true; | 306 *was_timeout = true; |
| 309 exit_code = -1; // Set a non-zero exit code to signal a failure. | 307 exit_code = -1; // Set a non-zero exit code to signal a failure. |
| 310 | 308 |
| 311 // Ensure that the process terminates. | 309 // Ensure that the process terminates. |
| 312 base::KillProcess(process_handle, -1, true); | 310 KillProcess(process_handle, -1, true); |
| 313 } | 311 } |
| 314 | 312 |
| 315 { | 313 { |
| 316 // Note how we grab the log before issuing a possibly broad process kill. | 314 // Note how we grab the log before issuing a possibly broad process kill. |
| 317 // Other code parts that grab the log kill processes, so avoid trying | 315 // Other code parts that grab the log kill processes, so avoid trying |
| 318 // to do that twice and trigger all kinds of log messages. | 316 // to do that twice and trigger all kinds of log messages. |
| 319 AutoLock lock(g_live_processes_lock.Get()); | 317 AutoLock lock(g_live_processes_lock.Get()); |
| 320 | 318 |
| 321 #if defined(OS_POSIX) | 319 #if defined(OS_POSIX) |
| 322 if (exit_code != 0) { | 320 if (exit_code != 0) { |
| 323 // On POSIX, in case the test does not exit cleanly, either due to a crash | 321 // On POSIX, in case the test does not exit cleanly, either due to a crash |
| 324 // or due to it timing out, we need to clean up any child processes that | 322 // or due to it timing out, we need to clean up any child processes that |
| 325 // it might have created. On Windows, child processes are automatically | 323 // it might have created. On Windows, child processes are automatically |
| 326 // cleaned up using JobObjects. | 324 // cleaned up using JobObjects. |
| 327 base::KillProcessGroup(process_handle); | 325 KillProcessGroup(process_handle); |
| 328 } | 326 } |
| 329 #endif | 327 #endif |
| 330 | 328 |
| 331 g_live_processes.Get().erase(process_handle); | 329 g_live_processes.Get().erase(process_handle); |
| 332 } | 330 } |
| 333 | 331 |
| 334 base::CloseProcessHandle(process_handle); | 332 CloseProcessHandle(process_handle); |
| 335 | 333 |
| 336 return exit_code; | 334 return exit_code; |
| 337 } | 335 } |
| 338 | 336 |
| 339 void RunCallback( | 337 void RunCallback( |
| 340 const TestLauncher::LaunchChildGTestProcessCallback& callback, | 338 const TestLauncher::LaunchChildGTestProcessCallback& callback, |
| 341 int exit_code, | 339 int exit_code, |
| 342 const TimeDelta& elapsed_time, | 340 const TimeDelta& elapsed_time, |
| 343 bool was_timeout, | 341 bool was_timeout, |
| 344 const std::string& output) { | 342 const std::string& output) { |
| 345 callback.Run(exit_code, elapsed_time, was_timeout, output); | 343 callback.Run(exit_code, elapsed_time, was_timeout, output); |
| 346 } | 344 } |
| 347 | 345 |
| 348 void DoLaunchChildTestProcess( | 346 void DoLaunchChildTestProcess( |
| 349 const CommandLine& command_line, | 347 const CommandLine& command_line, |
| 350 base::TimeDelta timeout, | 348 TimeDelta timeout, |
| 351 int flags, | 349 int flags, |
| 352 bool redirect_stdio, | 350 bool redirect_stdio, |
| 353 scoped_refptr<MessageLoopProxy> message_loop_proxy, | 351 scoped_refptr<MessageLoopProxy> message_loop_proxy, |
| 354 const TestLauncher::LaunchChildGTestProcessCallback& callback) { | 352 const TestLauncher::LaunchChildGTestProcessCallback& callback) { |
| 355 TimeTicks start_time = TimeTicks::Now(); | 353 TimeTicks start_time = TimeTicks::Now(); |
| 356 | 354 |
| 357 // Redirect child process output to a file. | 355 // Redirect child process output to a file. |
| 358 base::FilePath output_file; | 356 FilePath output_file; |
| 359 CHECK(base::CreateTemporaryFile(&output_file)); | 357 CHECK(CreateTemporaryFile(&output_file)); |
| 360 | 358 |
| 361 LaunchOptions options; | 359 LaunchOptions options; |
| 362 #if defined(OS_WIN) | 360 #if defined(OS_WIN) |
| 363 win::ScopedHandle handle; | 361 win::ScopedHandle handle; |
| 364 | 362 |
| 365 if (redirect_stdio) { | 363 if (redirect_stdio) { |
| 366 // Make the file handle inheritable by the child. | 364 // Make the file handle inheritable by the child. |
| 367 SECURITY_ATTRIBUTES sa_attr; | 365 SECURITY_ATTRIBUTES sa_attr; |
| 368 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); | 366 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 369 sa_attr.lpSecurityDescriptor = NULL; | 367 sa_attr.lpSecurityDescriptor = NULL; |
| 370 sa_attr.bInheritHandle = TRUE; | 368 sa_attr.bInheritHandle = TRUE; |
| 371 | 369 |
| 372 handle.Set(CreateFile(output_file.value().c_str(), | 370 handle.Set(CreateFile(output_file.value().c_str(), |
| 373 GENERIC_WRITE, | 371 GENERIC_WRITE, |
| 374 FILE_SHARE_READ | FILE_SHARE_DELETE, | 372 FILE_SHARE_READ | FILE_SHARE_DELETE, |
| 375 &sa_attr, | 373 &sa_attr, |
| 376 OPEN_EXISTING, | 374 OPEN_EXISTING, |
| 377 FILE_ATTRIBUTE_TEMPORARY, | 375 FILE_ATTRIBUTE_TEMPORARY, |
| 378 NULL)); | 376 NULL)); |
| 379 CHECK(handle.IsValid()); | 377 CHECK(handle.IsValid()); |
| 380 options.inherit_handles = true; | 378 options.inherit_handles = true; |
| 381 options.stdin_handle = INVALID_HANDLE_VALUE; | 379 options.stdin_handle = INVALID_HANDLE_VALUE; |
| 382 options.stdout_handle = handle.Get(); | 380 options.stdout_handle = handle.Get(); |
| 383 options.stderr_handle = handle.Get(); | 381 options.stderr_handle = handle.Get(); |
| 384 } | 382 } |
| 385 #elif defined(OS_POSIX) | 383 #elif defined(OS_POSIX) |
| 386 options.new_process_group = true; | 384 options.new_process_group = true; |
| 387 | 385 |
| 388 base::FileHandleMappingVector fds_mapping; | 386 FileHandleMappingVector fds_mapping; |
| 389 base::ScopedFD output_file_fd; | 387 ScopedFD output_file_fd; |
| 390 | 388 |
| 391 if (redirect_stdio) { | 389 if (redirect_stdio) { |
| 392 output_file_fd.reset(open(output_file.value().c_str(), O_RDWR)); | 390 output_file_fd.reset(open(output_file.value().c_str(), O_RDWR)); |
| 393 CHECK(output_file_fd.is_valid()); | 391 CHECK(output_file_fd.is_valid()); |
| 394 | 392 |
| 395 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); | 393 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); |
| 396 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); | 394 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); |
| 397 options.fds_to_remap = &fds_mapping; | 395 options.fds_to_remap = &fds_mapping; |
| 398 } | 396 } |
| 399 #endif | 397 #endif |
| 400 | 398 |
| 401 bool was_timeout = false; | 399 bool was_timeout = false; |
| 402 int exit_code = LaunchChildTestProcessWithOptions( | 400 int exit_code = LaunchChildTestProcessWithOptions( |
| 403 command_line, options, flags, timeout, &was_timeout); | 401 command_line, options, flags, timeout, &was_timeout); |
| 404 | 402 |
| 405 if (redirect_stdio) { | 403 if (redirect_stdio) { |
| 406 #if defined(OS_WIN) | 404 #if defined(OS_WIN) |
| 407 FlushFileBuffers(handle.Get()); | 405 FlushFileBuffers(handle.Get()); |
| 408 handle.Close(); | 406 handle.Close(); |
| 409 #elif defined(OS_POSIX) | 407 #elif defined(OS_POSIX) |
| 410 output_file_fd.reset(); | 408 output_file_fd.reset(); |
| 411 #endif | 409 #endif |
| 412 } | 410 } |
| 413 | 411 |
| 414 std::string output_file_contents; | 412 std::string output_file_contents; |
| 415 CHECK(base::ReadFileToString(output_file, &output_file_contents)); | 413 CHECK(ReadFileToString(output_file, &output_file_contents)); |
| 416 | 414 |
| 417 if (!base::DeleteFile(output_file, false)) { | 415 if (!DeleteFile(output_file, false)) { |
| 418 // This needs to be non-fatal at least for Windows. | 416 // This needs to be non-fatal at least for Windows. |
| 419 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); | 417 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); |
| 420 } | 418 } |
| 421 | 419 |
| 422 // Run target callback on the thread it was originating from, not on | 420 // Run target callback on the thread it was originating from, not on |
| 423 // a worker pool thread. | 421 // a worker pool thread. |
| 424 message_loop_proxy->PostTask( | 422 message_loop_proxy->PostTask( |
| 425 FROM_HERE, | 423 FROM_HERE, |
| 426 Bind(&RunCallback, | 424 Bind(&RunCallback, |
| 427 callback, | 425 callback, |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 results_tracker_.PrintSummaryOfAllIterations(); | 510 results_tracker_.PrintSummaryOfAllIterations(); |
| 513 | 511 |
| 514 MaybeSaveSummaryAsJSON(); | 512 MaybeSaveSummaryAsJSON(); |
| 515 | 513 |
| 516 return run_result_; | 514 return run_result_; |
| 517 } | 515 } |
| 518 | 516 |
| 519 void TestLauncher::LaunchChildGTestProcess( | 517 void TestLauncher::LaunchChildGTestProcess( |
| 520 const CommandLine& command_line, | 518 const CommandLine& command_line, |
| 521 const std::string& wrapper, | 519 const std::string& wrapper, |
| 522 base::TimeDelta timeout, | 520 TimeDelta timeout, |
| 523 int flags, | 521 int flags, |
| 524 const LaunchChildGTestProcessCallback& callback) { | 522 const LaunchChildGTestProcessCallback& callback) { |
| 525 DCHECK(thread_checker_.CalledOnValidThread()); | 523 DCHECK(thread_checker_.CalledOnValidThread()); |
| 526 | 524 |
| 527 // Record the exact command line used to launch the child. | 525 // Record the exact command line used to launch the child. |
| 528 CommandLine new_command_line( | 526 CommandLine new_command_line( |
| 529 PrepareCommandLineForGTest(command_line, wrapper)); | 527 PrepareCommandLineForGTest(command_line, wrapper)); |
| 530 | 528 |
| 531 // When running in parallel mode we need to redirect stdio to avoid mixed-up | 529 // When running in parallel mode we need to redirect stdio to avoid mixed-up |
| 532 // output. We also always redirect on the bots to get the test output into | 530 // output. We also always redirect on the bots to get the test output into |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 bool excluded = false; | 936 bool excluded = false; |
| 939 for (size_t k = 0; k < negative_test_filter_.size(); ++k) { | 937 for (size_t k = 0; k < negative_test_filter_.size(); ++k) { |
| 940 if (MatchPattern(test_name, negative_test_filter_[k])) { | 938 if (MatchPattern(test_name, negative_test_filter_[k])) { |
| 941 excluded = true; | 939 excluded = true; |
| 942 break; | 940 break; |
| 943 } | 941 } |
| 944 } | 942 } |
| 945 if (excluded) | 943 if (excluded) |
| 946 continue; | 944 continue; |
| 947 | 945 |
| 948 if (base::Hash(test_name) % total_shards_ != | 946 if (Hash(test_name) % total_shards_ != static_cast<uint32>(shard_index_)) |
| 949 static_cast<uint32>(shard_index_)) { | |
| 950 continue; | 947 continue; |
| 951 } | |
| 952 | 948 |
| 953 test_names.push_back(test_name); | 949 test_names.push_back(test_name); |
| 954 } | 950 } |
| 955 | 951 |
| 956 test_started_count_ = launcher_delegate_->RunTests(this, test_names); | 952 test_started_count_ = launcher_delegate_->RunTests(this, test_names); |
| 957 | 953 |
| 958 if (test_started_count_ == 0) { | 954 if (test_started_count_ == 0) { |
| 959 fprintf(stdout, "0 tests run\n"); | 955 fprintf(stdout, "0 tests run\n"); |
| 960 fflush(stdout); | 956 fflush(stdout); |
| 961 | 957 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 } | 1080 } |
| 1085 | 1081 |
| 1086 std::string snippet(full_output.substr(run_pos)); | 1082 std::string snippet(full_output.substr(run_pos)); |
| 1087 if (end_pos != std::string::npos) | 1083 if (end_pos != std::string::npos) |
| 1088 snippet = full_output.substr(run_pos, end_pos - run_pos); | 1084 snippet = full_output.substr(run_pos, end_pos - run_pos); |
| 1089 | 1085 |
| 1090 return snippet; | 1086 return snippet; |
| 1091 } | 1087 } |
| 1092 | 1088 |
| 1093 } // namespace base | 1089 } // namespace base |
| OLD | NEW |