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 25 matching lines...) Expand all Loading... |
36 #include "base/threading/thread_checker.h" | 36 #include "base/threading/thread_checker.h" |
37 #include "base/time/time.h" | 37 #include "base/time/time.h" |
38 #include "testing/gtest/include/gtest/gtest.h" | 38 #include "testing/gtest/include/gtest/gtest.h" |
39 | 39 |
40 #if defined(OS_MACOSX) | 40 #if defined(OS_MACOSX) |
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 |
| 47 // running after |timeout|, it is terminated and |*was_timeout| is set to true. |
| 48 // Returns exit code of the process. |
| 49 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 50 const LaunchOptions& options, |
| 51 bool use_job_objects, |
| 52 base::TimeDelta timeout, |
| 53 bool* was_timeout); |
| 54 |
46 // 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 . |
47 using ::operator<<; | 56 using ::operator<<; |
48 | 57 |
49 // The environment variable name for the total number of test shards. | 58 // The environment variable name for the total number of test shards. |
50 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; | 59 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; |
51 // The environment variable name for the test shard index. | 60 // The environment variable name for the test shard index. |
52 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; | 61 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; |
53 | 62 |
54 namespace { | 63 namespace { |
55 | 64 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 int exit_code, | 211 int exit_code, |
203 const TimeDelta& elapsed_time, | 212 const TimeDelta& elapsed_time, |
204 bool was_timeout, | 213 bool was_timeout, |
205 const std::string& output) { | 214 const std::string& output) { |
206 callback.Run(exit_code, elapsed_time, was_timeout, output); | 215 callback.Run(exit_code, elapsed_time, was_timeout, output); |
207 } | 216 } |
208 | 217 |
209 void DoLaunchChildTestProcess( | 218 void DoLaunchChildTestProcess( |
210 const CommandLine& command_line, | 219 const CommandLine& command_line, |
211 base::TimeDelta timeout, | 220 base::TimeDelta timeout, |
| 221 bool use_job_objects, |
212 bool redirect_stdio, | 222 bool redirect_stdio, |
213 scoped_refptr<MessageLoopProxy> message_loop_proxy, | 223 scoped_refptr<MessageLoopProxy> message_loop_proxy, |
214 const TestLauncher::LaunchChildGTestProcessCallback& callback) { | 224 const TestLauncher::LaunchChildGTestProcessCallback& callback) { |
215 TimeTicks start_time = TimeTicks::Now(); | 225 TimeTicks start_time = TimeTicks::Now(); |
216 | 226 |
217 // Redirect child process output to a file. | 227 // Redirect child process output to a file. |
218 base::FilePath output_file; | 228 base::FilePath output_file; |
219 CHECK(base::CreateTemporaryFile(&output_file)); | 229 CHECK(base::CreateTemporaryFile(&output_file)); |
220 | 230 |
221 LaunchOptions options; | 231 LaunchOptions options; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 CHECK(output_file_fd.is_valid()); | 263 CHECK(output_file_fd.is_valid()); |
254 | 264 |
255 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); | 265 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); |
256 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); | 266 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); |
257 options.fds_to_remap = &fds_mapping; | 267 options.fds_to_remap = &fds_mapping; |
258 } | 268 } |
259 #endif | 269 #endif |
260 | 270 |
261 bool was_timeout = false; | 271 bool was_timeout = false; |
262 int exit_code = LaunchChildTestProcessWithOptions( | 272 int exit_code = LaunchChildTestProcessWithOptions( |
263 command_line, options, timeout, &was_timeout); | 273 command_line, options, use_job_objects, timeout, &was_timeout); |
264 | 274 |
265 if (redirect_stdio) { | 275 if (redirect_stdio) { |
266 #if defined(OS_WIN) | 276 #if defined(OS_WIN) |
267 FlushFileBuffers(handle.Get()); | 277 FlushFileBuffers(handle.Get()); |
268 handle.Close(); | 278 handle.Close(); |
269 #elif defined(OS_POSIX) | 279 #elif defined(OS_POSIX) |
270 output_file_fd.reset(); | 280 output_file_fd.reset(); |
271 #endif | 281 #endif |
272 } | 282 } |
273 | 283 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 // --test-launcher-jobs flag. | 345 // --test-launcher-jobs flag. |
336 parallel_jobs_ = 1; | 346 parallel_jobs_ = 1; |
337 } | 347 } |
338 } | 348 } |
339 | 349 |
340 TestLauncher::~TestLauncher() { | 350 TestLauncher::~TestLauncher() { |
341 if (worker_pool_owner_) | 351 if (worker_pool_owner_) |
342 worker_pool_owner_->pool()->Shutdown(); | 352 worker_pool_owner_->pool()->Shutdown(); |
343 } | 353 } |
344 | 354 |
345 bool TestLauncher::Run(int argc, char** argv) { | 355 bool TestLauncher::Run() { |
346 if (!Init()) | 356 if (!Init()) |
347 return false; | 357 return false; |
348 | 358 |
349 // Value of |cycles_| changes after each iteration. Keep track of the | 359 // Value of |cycles_| changes after each iteration. Keep track of the |
350 // original value. | 360 // original value. |
351 int requested_cycles = cycles_; | 361 int requested_cycles = cycles_; |
352 | 362 |
353 #if defined(OS_POSIX) | 363 #if defined(OS_POSIX) |
354 CHECK_EQ(0, pipe(g_shutdown_pipe)); | 364 CHECK_EQ(0, pipe(g_shutdown_pipe)); |
355 | 365 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 | 397 |
388 MaybeSaveSummaryAsJSON(); | 398 MaybeSaveSummaryAsJSON(); |
389 | 399 |
390 return run_result_; | 400 return run_result_; |
391 } | 401 } |
392 | 402 |
393 void TestLauncher::LaunchChildGTestProcess( | 403 void TestLauncher::LaunchChildGTestProcess( |
394 const CommandLine& command_line, | 404 const CommandLine& command_line, |
395 const std::string& wrapper, | 405 const std::string& wrapper, |
396 base::TimeDelta timeout, | 406 base::TimeDelta timeout, |
| 407 bool use_job_objects, |
397 const LaunchChildGTestProcessCallback& callback) { | 408 const LaunchChildGTestProcessCallback& callback) { |
398 DCHECK(thread_checker_.CalledOnValidThread()); | 409 DCHECK(thread_checker_.CalledOnValidThread()); |
399 | 410 |
400 // Record the exact command line used to launch the child. | 411 // Record the exact command line used to launch the child. |
401 CommandLine new_command_line( | 412 CommandLine new_command_line( |
402 PrepareCommandLineForGTest(command_line, wrapper)); | 413 PrepareCommandLineForGTest(command_line, wrapper)); |
403 | 414 |
404 // When running in parallel mode we need to redirect stdio to avoid mixed-up | 415 // When running in parallel mode we need to redirect stdio to avoid mixed-up |
405 // output. We also always redirect on the bots to get the test output into | 416 // output. We also always redirect on the bots to get the test output into |
406 // JSON summary. | 417 // JSON summary. |
407 bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled(); | 418 bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled(); |
408 | 419 |
409 worker_pool_owner_->pool()->PostWorkerTask( | 420 worker_pool_owner_->pool()->PostWorkerTask( |
410 FROM_HERE, | 421 FROM_HERE, |
411 Bind(&DoLaunchChildTestProcess, | 422 Bind(&DoLaunchChildTestProcess, |
412 new_command_line, | 423 new_command_line, |
413 timeout, | 424 timeout, |
| 425 use_job_objects, |
414 redirect_stdio, | 426 redirect_stdio, |
415 MessageLoopProxy::current(), | 427 MessageLoopProxy::current(), |
416 Bind(&TestLauncher::OnLaunchTestProcessFinished, | 428 Bind(&TestLauncher::OnLaunchTestProcessFinished, |
417 Unretained(this), | 429 Unretained(this), |
418 callback))); | 430 callback))); |
419 } | 431 } |
420 | 432 |
421 void TestLauncher::OnTestFinished(const TestResult& result) { | 433 void TestLauncher::OnTestFinished(const TestResult& result) { |
422 ++test_finished_count_; | 434 ++test_finished_count_; |
423 | 435 |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
937 end_pos = newline_pos + 1; | 949 end_pos = newline_pos + 1; |
938 } | 950 } |
939 | 951 |
940 std::string snippet(full_output.substr(run_pos)); | 952 std::string snippet(full_output.substr(run_pos)); |
941 if (end_pos != std::string::npos) | 953 if (end_pos != std::string::npos) |
942 snippet = full_output.substr(run_pos, end_pos - run_pos); | 954 snippet = full_output.substr(run_pos, end_pos - run_pos); |
943 | 955 |
944 return snippet; | 956 return snippet; |
945 } | 957 } |
946 | 958 |
947 int LaunchChildGTestProcess(const CommandLine& command_line, | |
948 const std::string& wrapper, | |
949 base::TimeDelta timeout, | |
950 bool* was_timeout) { | |
951 LaunchOptions options; | |
952 | |
953 #if defined(OS_POSIX) | |
954 // On POSIX, we launch the test in a new process group with pgid equal to | |
955 // its pid. Any child processes that the test may create will inherit the | |
956 // same pgid. This way, if the test is abruptly terminated, we can clean up | |
957 // any orphaned child processes it may have left behind. | |
958 options.new_process_group = true; | |
959 #endif | |
960 | |
961 return LaunchChildTestProcessWithOptions( | |
962 PrepareCommandLineForGTest(command_line, wrapper), | |
963 options, | |
964 timeout, | |
965 was_timeout); | |
966 } | |
967 | |
968 CommandLine PrepareCommandLineForGTest(const CommandLine& command_line, | 959 CommandLine PrepareCommandLineForGTest(const CommandLine& command_line, |
969 const std::string& wrapper) { | 960 const std::string& wrapper) { |
970 CommandLine new_command_line(command_line.GetProgram()); | 961 CommandLine new_command_line(command_line.GetProgram()); |
971 CommandLine::SwitchMap switches = command_line.GetSwitches(); | 962 CommandLine::SwitchMap switches = command_line.GetSwitches(); |
972 | 963 |
973 // Strip out gtest_repeat flag - this is handled by the launcher process. | 964 // Strip out gtest_repeat flag - this is handled by the launcher process. |
974 switches.erase(kGTestRepeatFlag); | 965 switches.erase(kGTestRepeatFlag); |
975 | 966 |
976 // Don't try to write the final XML report in child processes. | 967 // Don't try to write the final XML report in child processes. |
977 switches.erase(kGTestOutputFlag); | 968 switches.erase(kGTestOutputFlag); |
978 | 969 |
979 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | 970 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); |
980 iter != switches.end(); ++iter) { | 971 iter != switches.end(); ++iter) { |
981 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); | 972 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); |
982 } | 973 } |
983 | 974 |
984 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine | 975 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine |
985 // does not really support removing switches well, and trying to do that | 976 // does not really support removing switches well, and trying to do that |
986 // on a CommandLine with a wrapper is known to break. | 977 // on a CommandLine with a wrapper is known to break. |
987 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. | 978 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. |
988 #if defined(OS_WIN) | 979 #if defined(OS_WIN) |
989 new_command_line.PrependWrapper(ASCIIToWide(wrapper)); | 980 new_command_line.PrependWrapper(ASCIIToWide(wrapper)); |
990 #elif defined(OS_POSIX) | 981 #elif defined(OS_POSIX) |
991 new_command_line.PrependWrapper(wrapper); | 982 new_command_line.PrependWrapper(wrapper); |
992 #endif | 983 #endif |
993 | 984 |
994 return new_command_line; | 985 return new_command_line; |
995 } | 986 } |
996 | 987 |
| 988 // TODO(phajdan.jr): Move to anonymous namespace. |
997 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | 989 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
998 const LaunchOptions& options, | 990 const LaunchOptions& options, |
| 991 bool use_job_objects, |
999 base::TimeDelta timeout, | 992 base::TimeDelta timeout, |
1000 bool* was_timeout) { | 993 bool* was_timeout) { |
1001 #if defined(OS_POSIX) | 994 #if defined(OS_POSIX) |
1002 // Make sure an option we rely on is present - see LaunchChildGTestProcess. | 995 // Make sure an option we rely on is present - see LaunchChildGTestProcess. |
1003 DCHECK(options.new_process_group); | 996 DCHECK(options.new_process_group); |
1004 #endif | 997 #endif |
1005 | 998 |
1006 LaunchOptions new_options(options); | 999 LaunchOptions new_options(options); |
1007 | 1000 |
1008 #if defined(OS_WIN) | 1001 #if defined(OS_WIN) |
1009 DCHECK(!new_options.job_handle); | 1002 DCHECK(!new_options.job_handle); |
1010 | 1003 |
1011 win::ScopedHandle job_handle(CreateJobObject(NULL, NULL)); | 1004 win::ScopedHandle job_handle; |
1012 if (!job_handle.IsValid()) { | 1005 if (use_job_objects) { |
1013 LOG(ERROR) << "Could not create JobObject."; | 1006 job_handle.Set(CreateJobObject(NULL, NULL)); |
1014 return -1; | 1007 if (!job_handle.IsValid()) { |
| 1008 LOG(ERROR) << "Could not create JobObject."; |
| 1009 return -1; |
| 1010 } |
| 1011 |
| 1012 // Allow break-away from job since sandbox and few other places rely on it |
| 1013 // on Windows versions prior to Windows 8 (which supports nested jobs). |
| 1014 // TODO(phajdan.jr): Do not allow break-away on Windows 8. |
| 1015 if (!SetJobObjectLimitFlags(job_handle.Get(), |
| 1016 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | |
| 1017 JOB_OBJECT_LIMIT_BREAKAWAY_OK)) { |
| 1018 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; |
| 1019 return -1; |
| 1020 } |
| 1021 |
| 1022 new_options.job_handle = job_handle.Get(); |
1015 } | 1023 } |
1016 | |
1017 // Allow break-away from job since sandbox and few other places rely on it | |
1018 // on Windows versions prior to Windows 8 (which supports nested jobs). | |
1019 // TODO(phajdan.jr): Do not allow break-away on Windows 8. | |
1020 if (!SetJobObjectLimitFlags(job_handle.Get(), | |
1021 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | | |
1022 JOB_OBJECT_LIMIT_BREAKAWAY_OK)) { | |
1023 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; | |
1024 return -1; | |
1025 } | |
1026 | |
1027 new_options.job_handle = job_handle.Get(); | |
1028 #endif // defined(OS_WIN) | 1024 #endif // defined(OS_WIN) |
1029 | 1025 |
1030 #if defined(OS_LINUX) | 1026 #if defined(OS_LINUX) |
1031 // To prevent accidental privilege sharing to an untrusted child, processes | 1027 // To prevent accidental privilege sharing to an untrusted child, processes |
1032 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this | 1028 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this |
1033 // new child will be privileged and trusted. | 1029 // new child will be privileged and trusted. |
1034 new_options.allow_new_privs = true; | 1030 new_options.allow_new_privs = true; |
1035 #endif | 1031 #endif |
1036 | 1032 |
1037 base::ProcessHandle process_handle; | 1033 base::ProcessHandle process_handle; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 | 1073 |
1078 g_live_processes.Get().erase(process_handle); | 1074 g_live_processes.Get().erase(process_handle); |
1079 } | 1075 } |
1080 | 1076 |
1081 base::CloseProcessHandle(process_handle); | 1077 base::CloseProcessHandle(process_handle); |
1082 | 1078 |
1083 return exit_code; | 1079 return exit_code; |
1084 } | 1080 } |
1085 | 1081 |
1086 } // namespace base | 1082 } // namespace base |
OLD | NEW |