| 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 29 matching lines...) Expand all Loading... |
| 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 #if defined(OS_WIN) | 44 #if defined(OS_WIN) |
| 45 #include "base/win/windows_version.h" | 45 #include "base/win/windows_version.h" |
| 46 #endif | 46 #endif |
| 47 | 47 |
| 48 namespace base { | 48 namespace base { |
| 49 | 49 |
| 50 // Launches a child process using |command_line|. If the child process is still | |
| 51 // running after |timeout|, it is terminated and |*was_timeout| is set to true. | |
| 52 // Returns exit code of the process. | |
| 53 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | |
| 54 const LaunchOptions& options, | |
| 55 int flags, | |
| 56 base::TimeDelta timeout, | |
| 57 bool* was_timeout); | |
| 58 | |
| 59 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . | 50 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/u
T3FaE_sgkAJ . |
| 60 using ::operator<<; | 51 using ::operator<<; |
| 61 | 52 |
| 62 // The environment variable name for the total number of test shards. | 53 // The environment variable name for the total number of test shards. |
| 63 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; | 54 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; |
| 64 // The environment variable name for the test shard index. | 55 // The environment variable name for the test shard index. |
| 65 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; | 56 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; |
| 66 | 57 |
| 67 namespace { | 58 namespace { |
| 68 | 59 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 // Returns true if bot mode has been requested, i.e. defaults optimized | 199 // Returns true if bot mode has been requested, i.e. defaults optimized |
| 209 // for continuous integration bots. This way developers don't have to remember | 200 // for continuous integration bots. This way developers don't have to remember |
| 210 // special command-line flags. | 201 // special command-line flags. |
| 211 bool BotModeEnabled() { | 202 bool BotModeEnabled() { |
| 212 scoped_ptr<Environment> env(Environment::Create()); | 203 scoped_ptr<Environment> env(Environment::Create()); |
| 213 return CommandLine::ForCurrentProcess()->HasSwitch( | 204 return CommandLine::ForCurrentProcess()->HasSwitch( |
| 214 switches::kTestLauncherBotMode) || | 205 switches::kTestLauncherBotMode) || |
| 215 env->HasVar("CHROMIUM_TEST_LAUNCHER_BOT_MODE"); | 206 env->HasVar("CHROMIUM_TEST_LAUNCHER_BOT_MODE"); |
| 216 } | 207 } |
| 217 | 208 |
| 209 // Returns command line command line after gtest-specific processing |
| 210 // and applying |wrapper|. |
| 211 CommandLine PrepareCommandLineForGTest(const CommandLine& command_line, |
| 212 const std::string& wrapper) { |
| 213 CommandLine new_command_line(command_line.GetProgram()); |
| 214 CommandLine::SwitchMap switches = command_line.GetSwitches(); |
| 215 |
| 216 // Strip out gtest_repeat flag - this is handled by the launcher process. |
| 217 switches.erase(kGTestRepeatFlag); |
| 218 |
| 219 // Don't try to write the final XML report in child processes. |
| 220 switches.erase(kGTestOutputFlag); |
| 221 |
| 222 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); |
| 223 iter != switches.end(); ++iter) { |
| 224 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); |
| 225 } |
| 226 |
| 227 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine |
| 228 // does not really support removing switches well, and trying to do that |
| 229 // on a CommandLine with a wrapper is known to break. |
| 230 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. |
| 231 #if defined(OS_WIN) |
| 232 new_command_line.PrependWrapper(ASCIIToWide(wrapper)); |
| 233 #elif defined(OS_POSIX) |
| 234 new_command_line.PrependWrapper(wrapper); |
| 235 #endif |
| 236 |
| 237 return new_command_line; |
| 238 } |
| 239 |
| 240 // Launches a child process using |command_line|. If the child process is still |
| 241 // running after |timeout|, it is terminated and |*was_timeout| is set to true. |
| 242 // Returns exit code of the process. |
| 243 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 244 const LaunchOptions& options, |
| 245 int flags, |
| 246 base::TimeDelta timeout, |
| 247 bool* was_timeout) { |
| 248 #if defined(OS_POSIX) |
| 249 // Make sure an option we rely on is present - see LaunchChildGTestProcess. |
| 250 DCHECK(options.new_process_group); |
| 251 #endif |
| 252 |
| 253 LaunchOptions new_options(options); |
| 254 |
| 255 #if defined(OS_WIN) |
| 256 DCHECK(!new_options.job_handle); |
| 257 |
| 258 win::ScopedHandle job_handle; |
| 259 if (flags & TestLauncher::USE_JOB_OBJECTS) { |
| 260 job_handle.Set(CreateJobObject(NULL, NULL)); |
| 261 if (!job_handle.IsValid()) { |
| 262 LOG(ERROR) << "Could not create JobObject."; |
| 263 return -1; |
| 264 } |
| 265 |
| 266 DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; |
| 267 |
| 268 // Allow break-away from job since sandbox and few other places rely on it |
| 269 // on Windows versions prior to Windows 8 (which supports nested jobs). |
| 270 if (win::GetVersion() < win::VERSION_WIN8 && |
| 271 flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) { |
| 272 job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; |
| 273 } |
| 274 |
| 275 if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) { |
| 276 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; |
| 277 return -1; |
| 278 } |
| 279 |
| 280 new_options.job_handle = job_handle.Get(); |
| 281 } |
| 282 #endif // defined(OS_WIN) |
| 283 |
| 284 #if defined(OS_LINUX) |
| 285 // To prevent accidental privilege sharing to an untrusted child, processes |
| 286 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this |
| 287 // new child will be privileged and trusted. |
| 288 new_options.allow_new_privs = true; |
| 289 #endif |
| 290 |
| 291 base::ProcessHandle process_handle; |
| 292 |
| 293 { |
| 294 // Note how we grab the lock before the process possibly gets created. |
| 295 // This ensures that when the lock is held, ALL the processes are registered |
| 296 // in the set. |
| 297 AutoLock lock(g_live_processes_lock.Get()); |
| 298 |
| 299 if (!base::LaunchProcess(command_line, new_options, &process_handle)) |
| 300 return -1; |
| 301 |
| 302 g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); |
| 303 } |
| 304 |
| 305 int exit_code = 0; |
| 306 if (!base::WaitForExitCodeWithTimeout(process_handle, |
| 307 &exit_code, |
| 308 timeout)) { |
| 309 *was_timeout = true; |
| 310 exit_code = -1; // Set a non-zero exit code to signal a failure. |
| 311 |
| 312 // Ensure that the process terminates. |
| 313 base::KillProcess(process_handle, -1, true); |
| 314 } |
| 315 |
| 316 { |
| 317 // Note how we grab the log before issuing a possibly broad process kill. |
| 318 // Other code parts that grab the log kill processes, so avoid trying |
| 319 // to do that twice and trigger all kinds of log messages. |
| 320 AutoLock lock(g_live_processes_lock.Get()); |
| 321 |
| 322 #if defined(OS_POSIX) |
| 323 if (exit_code != 0) { |
| 324 // On POSIX, in case the test does not exit cleanly, either due to a crash |
| 325 // or due to it timing out, we need to clean up any child processes that |
| 326 // it might have created. On Windows, child processes are automatically |
| 327 // cleaned up using JobObjects. |
| 328 base::KillProcessGroup(process_handle); |
| 329 } |
| 330 #endif |
| 331 |
| 332 g_live_processes.Get().erase(process_handle); |
| 333 } |
| 334 |
| 335 base::CloseProcessHandle(process_handle); |
| 336 |
| 337 return exit_code; |
| 338 } |
| 339 |
| 218 void RunCallback( | 340 void RunCallback( |
| 219 const TestLauncher::LaunchChildGTestProcessCallback& callback, | 341 const TestLauncher::LaunchChildGTestProcessCallback& callback, |
| 220 int exit_code, | 342 int exit_code, |
| 221 const TimeDelta& elapsed_time, | 343 const TimeDelta& elapsed_time, |
| 222 bool was_timeout, | 344 bool was_timeout, |
| 223 const std::string& output) { | 345 const std::string& output) { |
| 224 callback.Run(exit_code, elapsed_time, was_timeout, output); | 346 callback.Run(exit_code, elapsed_time, was_timeout, output); |
| 225 } | 347 } |
| 226 | 348 |
| 227 void DoLaunchChildTestProcess( | 349 void DoLaunchChildTestProcess( |
| (...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 967 end_pos = newline_pos + 1; | 1089 end_pos = newline_pos + 1; |
| 968 } | 1090 } |
| 969 | 1091 |
| 970 std::string snippet(full_output.substr(run_pos)); | 1092 std::string snippet(full_output.substr(run_pos)); |
| 971 if (end_pos != std::string::npos) | 1093 if (end_pos != std::string::npos) |
| 972 snippet = full_output.substr(run_pos, end_pos - run_pos); | 1094 snippet = full_output.substr(run_pos, end_pos - run_pos); |
| 973 | 1095 |
| 974 return snippet; | 1096 return snippet; |
| 975 } | 1097 } |
| 976 | 1098 |
| 977 CommandLine PrepareCommandLineForGTest(const CommandLine& command_line, | |
| 978 const std::string& wrapper) { | |
| 979 CommandLine new_command_line(command_line.GetProgram()); | |
| 980 CommandLine::SwitchMap switches = command_line.GetSwitches(); | |
| 981 | |
| 982 // Strip out gtest_repeat flag - this is handled by the launcher process. | |
| 983 switches.erase(kGTestRepeatFlag); | |
| 984 | |
| 985 // Don't try to write the final XML report in child processes. | |
| 986 switches.erase(kGTestOutputFlag); | |
| 987 | |
| 988 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | |
| 989 iter != switches.end(); ++iter) { | |
| 990 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); | |
| 991 } | |
| 992 | |
| 993 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine | |
| 994 // does not really support removing switches well, and trying to do that | |
| 995 // on a CommandLine with a wrapper is known to break. | |
| 996 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. | |
| 997 #if defined(OS_WIN) | |
| 998 new_command_line.PrependWrapper(ASCIIToWide(wrapper)); | |
| 999 #elif defined(OS_POSIX) | |
| 1000 new_command_line.PrependWrapper(wrapper); | |
| 1001 #endif | |
| 1002 | |
| 1003 return new_command_line; | |
| 1004 } | |
| 1005 | |
| 1006 // TODO(phajdan.jr): Move to anonymous namespace. | |
| 1007 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | |
| 1008 const LaunchOptions& options, | |
| 1009 int flags, | |
| 1010 base::TimeDelta timeout, | |
| 1011 bool* was_timeout) { | |
| 1012 #if defined(OS_POSIX) | |
| 1013 // Make sure an option we rely on is present - see LaunchChildGTestProcess. | |
| 1014 DCHECK(options.new_process_group); | |
| 1015 #endif | |
| 1016 | |
| 1017 LaunchOptions new_options(options); | |
| 1018 | |
| 1019 #if defined(OS_WIN) | |
| 1020 DCHECK(!new_options.job_handle); | |
| 1021 | |
| 1022 win::ScopedHandle job_handle; | |
| 1023 if (flags & TestLauncher::USE_JOB_OBJECTS) { | |
| 1024 job_handle.Set(CreateJobObject(NULL, NULL)); | |
| 1025 if (!job_handle.IsValid()) { | |
| 1026 LOG(ERROR) << "Could not create JobObject."; | |
| 1027 return -1; | |
| 1028 } | |
| 1029 | |
| 1030 DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | |
| 1031 | |
| 1032 // Allow break-away from job since sandbox and few other places rely on it | |
| 1033 // on Windows versions prior to Windows 8 (which supports nested jobs). | |
| 1034 if (win::GetVersion() < win::VERSION_WIN8 && | |
| 1035 flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) { | |
| 1036 job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; | |
| 1037 } | |
| 1038 | |
| 1039 if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) { | |
| 1040 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; | |
| 1041 return -1; | |
| 1042 } | |
| 1043 | |
| 1044 new_options.job_handle = job_handle.Get(); | |
| 1045 } | |
| 1046 #endif // defined(OS_WIN) | |
| 1047 | |
| 1048 #if defined(OS_LINUX) | |
| 1049 // To prevent accidental privilege sharing to an untrusted child, processes | |
| 1050 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this | |
| 1051 // new child will be privileged and trusted. | |
| 1052 new_options.allow_new_privs = true; | |
| 1053 #endif | |
| 1054 | |
| 1055 base::ProcessHandle process_handle; | |
| 1056 | |
| 1057 { | |
| 1058 // Note how we grab the lock before the process possibly gets created. | |
| 1059 // This ensures that when the lock is held, ALL the processes are registered | |
| 1060 // in the set. | |
| 1061 AutoLock lock(g_live_processes_lock.Get()); | |
| 1062 | |
| 1063 if (!base::LaunchProcess(command_line, new_options, &process_handle)) | |
| 1064 return -1; | |
| 1065 | |
| 1066 g_live_processes.Get().insert(std::make_pair(process_handle, command_line)); | |
| 1067 } | |
| 1068 | |
| 1069 int exit_code = 0; | |
| 1070 if (!base::WaitForExitCodeWithTimeout(process_handle, | |
| 1071 &exit_code, | |
| 1072 timeout)) { | |
| 1073 *was_timeout = true; | |
| 1074 exit_code = -1; // Set a non-zero exit code to signal a failure. | |
| 1075 | |
| 1076 // Ensure that the process terminates. | |
| 1077 base::KillProcess(process_handle, -1, true); | |
| 1078 } | |
| 1079 | |
| 1080 { | |
| 1081 // Note how we grab the log before issuing a possibly broad process kill. | |
| 1082 // Other code parts that grab the log kill processes, so avoid trying | |
| 1083 // to do that twice and trigger all kinds of log messages. | |
| 1084 AutoLock lock(g_live_processes_lock.Get()); | |
| 1085 | |
| 1086 #if defined(OS_POSIX) | |
| 1087 if (exit_code != 0) { | |
| 1088 // On POSIX, in case the test does not exit cleanly, either due to a crash | |
| 1089 // or due to it timing out, we need to clean up any child processes that | |
| 1090 // it might have created. On Windows, child processes are automatically | |
| 1091 // cleaned up using JobObjects. | |
| 1092 base::KillProcessGroup(process_handle); | |
| 1093 } | |
| 1094 #endif | |
| 1095 | |
| 1096 g_live_processes.Get().erase(process_handle); | |
| 1097 } | |
| 1098 | |
| 1099 base::CloseProcessHandle(process_handle); | |
| 1100 | |
| 1101 return exit_code; | |
| 1102 } | |
| 1103 | |
| 1104 } // namespace base | 1099 } // namespace base |
| OLD | NEW |