| 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 |