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