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 |