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