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