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 |