| 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 30 matching lines...) Expand all Loading... |
| 41 #include "base/mac/scoped_nsautorelease_pool.h" | 41 #include "base/mac/scoped_nsautorelease_pool.h" |
| 42 #endif | 42 #endif |
| 43 | 43 |
| 44 namespace base { | 44 namespace base { |
| 45 | 45 |
| 46 // Launches a child process using |command_line|. If the child process is still | 46 // Launches a child process using |command_line|. If the child process is still |
| 47 // running after |timeout|, it is terminated and |*was_timeout| is set to true. | 47 // running after |timeout|, it is terminated and |*was_timeout| is set to true. |
| 48 // Returns exit code of the process. | 48 // Returns exit code of the process. |
| 49 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | 49 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 50 const LaunchOptions& options, | 50 const LaunchOptions& options, |
| 51 bool use_job_objects, | 51 int flags, |
| 52 base::TimeDelta timeout, | 52 base::TimeDelta timeout, |
| 53 bool* was_timeout); | 53 bool* was_timeout); |
| 54 | 54 |
| 55 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . | 55 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . |
| 56 using ::operator<<; | 56 using ::operator<<; |
| 57 | 57 |
| 58 // The environment variable name for the total number of test shards. | 58 // The environment variable name for the total number of test shards. |
| 59 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; | 59 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; |
| 60 // The environment variable name for the test shard index. | 60 // The environment variable name for the test shard index. |
| 61 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; | 61 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 int exit_code, | 216 int exit_code, |
| 217 const TimeDelta& elapsed_time, | 217 const TimeDelta& elapsed_time, |
| 218 bool was_timeout, | 218 bool was_timeout, |
| 219 const std::string& output) { | 219 const std::string& output) { |
| 220 callback.Run(exit_code, elapsed_time, was_timeout, output); | 220 callback.Run(exit_code, elapsed_time, was_timeout, output); |
| 221 } | 221 } |
| 222 | 222 |
| 223 void DoLaunchChildTestProcess( | 223 void DoLaunchChildTestProcess( |
| 224 const CommandLine& command_line, | 224 const CommandLine& command_line, |
| 225 base::TimeDelta timeout, | 225 base::TimeDelta timeout, |
| 226 bool use_job_objects, | 226 int flags, |
| 227 bool redirect_stdio, | 227 bool redirect_stdio, |
| 228 scoped_refptr<MessageLoopProxy> message_loop_proxy, | 228 scoped_refptr<MessageLoopProxy> message_loop_proxy, |
| 229 const TestLauncher::LaunchChildGTestProcessCallback& callback) { | 229 const TestLauncher::LaunchChildGTestProcessCallback& callback) { |
| 230 TimeTicks start_time = TimeTicks::Now(); | 230 TimeTicks start_time = TimeTicks::Now(); |
| 231 | 231 |
| 232 // Redirect child process output to a file. | 232 // Redirect child process output to a file. |
| 233 base::FilePath output_file; | 233 base::FilePath output_file; |
| 234 CHECK(base::CreateTemporaryFile(&output_file)); | 234 CHECK(base::CreateTemporaryFile(&output_file)); |
| 235 | 235 |
| 236 LaunchOptions options; | 236 LaunchOptions options; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 CHECK(output_file_fd.is_valid()); | 268 CHECK(output_file_fd.is_valid()); |
| 269 | 269 |
| 270 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); | 270 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); |
| 271 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); | 271 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); |
| 272 options.fds_to_remap = &fds_mapping; | 272 options.fds_to_remap = &fds_mapping; |
| 273 } | 273 } |
| 274 #endif | 274 #endif |
| 275 | 275 |
| 276 bool was_timeout = false; | 276 bool was_timeout = false; |
| 277 int exit_code = LaunchChildTestProcessWithOptions( | 277 int exit_code = LaunchChildTestProcessWithOptions( |
| 278 command_line, options, use_job_objects, timeout, &was_timeout); | 278 command_line, options, flags, timeout, &was_timeout); |
| 279 | 279 |
| 280 if (redirect_stdio) { | 280 if (redirect_stdio) { |
| 281 #if defined(OS_WIN) | 281 #if defined(OS_WIN) |
| 282 FlushFileBuffers(handle.Get()); | 282 FlushFileBuffers(handle.Get()); |
| 283 handle.Close(); | 283 handle.Close(); |
| 284 #elif defined(OS_POSIX) | 284 #elif defined(OS_POSIX) |
| 285 output_file_fd.reset(); | 285 output_file_fd.reset(); |
| 286 #endif | 286 #endif |
| 287 } | 287 } |
| 288 | 288 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 | 402 |
| 403 MaybeSaveSummaryAsJSON(); | 403 MaybeSaveSummaryAsJSON(); |
| 404 | 404 |
| 405 return run_result_; | 405 return run_result_; |
| 406 } | 406 } |
| 407 | 407 |
| 408 void TestLauncher::LaunchChildGTestProcess( | 408 void TestLauncher::LaunchChildGTestProcess( |
| 409 const CommandLine& command_line, | 409 const CommandLine& command_line, |
| 410 const std::string& wrapper, | 410 const std::string& wrapper, |
| 411 base::TimeDelta timeout, | 411 base::TimeDelta timeout, |
| 412 bool use_job_objects, | 412 int flags, |
| 413 const LaunchChildGTestProcessCallback& callback) { | 413 const LaunchChildGTestProcessCallback& callback) { |
| 414 DCHECK(thread_checker_.CalledOnValidThread()); | 414 DCHECK(thread_checker_.CalledOnValidThread()); |
| 415 | 415 |
| 416 // Record the exact command line used to launch the child. | 416 // Record the exact command line used to launch the child. |
| 417 CommandLine new_command_line( | 417 CommandLine new_command_line( |
| 418 PrepareCommandLineForGTest(command_line, wrapper)); | 418 PrepareCommandLineForGTest(command_line, wrapper)); |
| 419 | 419 |
| 420 // When running in parallel mode we need to redirect stdio to avoid mixed-up | 420 // When running in parallel mode we need to redirect stdio to avoid mixed-up |
| 421 // output. We also always redirect on the bots to get the test output into | 421 // output. We also always redirect on the bots to get the test output into |
| 422 // JSON summary. | 422 // JSON summary. |
| 423 bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled(); | 423 bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled(); |
| 424 | 424 |
| 425 worker_pool_owner_->pool()->PostWorkerTask( | 425 worker_pool_owner_->pool()->PostWorkerTask( |
| 426 FROM_HERE, | 426 FROM_HERE, |
| 427 Bind(&DoLaunchChildTestProcess, | 427 Bind(&DoLaunchChildTestProcess, |
| 428 new_command_line, | 428 new_command_line, |
| 429 timeout, | 429 timeout, |
| 430 use_job_objects, | 430 flags, |
| 431 redirect_stdio, | 431 redirect_stdio, |
| 432 MessageLoopProxy::current(), | 432 MessageLoopProxy::current(), |
| 433 Bind(&TestLauncher::OnLaunchTestProcessFinished, | 433 Bind(&TestLauncher::OnLaunchTestProcessFinished, |
| 434 Unretained(this), | 434 Unretained(this), |
| 435 callback))); | 435 callback))); |
| 436 } | 436 } |
| 437 | 437 |
| 438 void TestLauncher::OnTestFinished(const TestResult& result) { | 438 void TestLauncher::OnTestFinished(const TestResult& result) { |
| 439 ++test_finished_count_; | 439 ++test_finished_count_; |
| 440 | 440 |
| (...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 #elif defined(OS_POSIX) | 1002 #elif defined(OS_POSIX) |
| 1003 new_command_line.PrependWrapper(wrapper); | 1003 new_command_line.PrependWrapper(wrapper); |
| 1004 #endif | 1004 #endif |
| 1005 | 1005 |
| 1006 return new_command_line; | 1006 return new_command_line; |
| 1007 } | 1007 } |
| 1008 | 1008 |
| 1009 // TODO(phajdan.jr): Move to anonymous namespace. | 1009 // TODO(phajdan.jr): Move to anonymous namespace. |
| 1010 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | 1010 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 1011 const LaunchOptions& options, | 1011 const LaunchOptions& options, |
| 1012 bool use_job_objects, | 1012 int flags, |
| 1013 base::TimeDelta timeout, | 1013 base::TimeDelta timeout, |
| 1014 bool* was_timeout) { | 1014 bool* was_timeout) { |
| 1015 #if defined(OS_POSIX) | 1015 #if defined(OS_POSIX) |
| 1016 // Make sure an option we rely on is present - see LaunchChildGTestProcess. | 1016 // Make sure an option we rely on is present - see LaunchChildGTestProcess. |
| 1017 DCHECK(options.new_process_group); | 1017 DCHECK(options.new_process_group); |
| 1018 #endif | 1018 #endif |
| 1019 | 1019 |
| 1020 LaunchOptions new_options(options); | 1020 LaunchOptions new_options(options); |
| 1021 | 1021 |
| 1022 #if defined(OS_WIN) | 1022 #if defined(OS_WIN) |
| 1023 DCHECK(!new_options.job_handle); | 1023 DCHECK(!new_options.job_handle); |
| 1024 | 1024 |
| 1025 win::ScopedHandle job_handle; | 1025 win::ScopedHandle job_handle; |
| 1026 if (use_job_objects) { | 1026 if (flags & TestLauncher::USE_JOB_OBJECTS) { |
| 1027 job_handle.Set(CreateJobObject(NULL, NULL)); | 1027 job_handle.Set(CreateJobObject(NULL, NULL)); |
| 1028 if (!job_handle.IsValid()) { | 1028 if (!job_handle.IsValid()) { |
| 1029 LOG(ERROR) << "Could not create JobObject."; | 1029 LOG(ERROR) << "Could not create JobObject."; |
| 1030 return -1; | 1030 return -1; |
| 1031 } | 1031 } |
| 1032 | 1032 |
| 1033 DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; |
| 1034 |
| 1033 // Allow break-away from job since sandbox and few other places rely on it | 1035 // Allow break-away from job since sandbox and few other places rely on it |
| 1034 // on Windows versions prior to Windows 8 (which supports nested jobs). | 1036 // on Windows versions prior to Windows 8 (which supports nested jobs). |
| 1035 // TODO(phajdan.jr): Do not allow break-away on Windows 8. | 1037 // TODO(phajdan.jr): Do not allow break-away on Windows 8. |
| 1036 if (!SetJobObjectLimitFlags(job_handle.Get(), | 1038 if (flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) |
| 1037 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | | 1039 job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; |
| 1038 JOB_OBJECT_LIMIT_BREAKAWAY_OK)) { | 1040 |
| 1041 if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) { |
| 1039 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; | 1042 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; |
| 1040 return -1; | 1043 return -1; |
| 1041 } | 1044 } |
| 1042 | 1045 |
| 1043 new_options.job_handle = job_handle.Get(); | 1046 new_options.job_handle = job_handle.Get(); |
| 1044 } | 1047 } |
| 1045 #endif // defined(OS_WIN) | 1048 #endif // defined(OS_WIN) |
| 1046 | 1049 |
| 1047 #if defined(OS_LINUX) | 1050 #if defined(OS_LINUX) |
| 1048 // To prevent accidental privilege sharing to an untrusted child, processes | 1051 // To prevent accidental privilege sharing to an untrusted child, processes |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 | 1097 |
| 1095 g_live_processes.Get().erase(process_handle); | 1098 g_live_processes.Get().erase(process_handle); |
| 1096 } | 1099 } |
| 1097 | 1100 |
| 1098 base::CloseProcessHandle(process_handle); | 1101 base::CloseProcessHandle(process_handle); |
| 1099 | 1102 |
| 1100 return exit_code; | 1103 return exit_code; |
| 1101 } | 1104 } |
| 1102 | 1105 |
| 1103 } // namespace base | 1106 } // namespace base |
| OLD | NEW |