| 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 27 matching lines...) Expand all Loading... |
| 38 #include "base/test/test_timeouts.h" | 38 #include "base/test/test_timeouts.h" |
| 39 #include "base/thread_task_runner_handle.h" | 39 #include "base/thread_task_runner_handle.h" |
| 40 #include "base/threading/thread_checker.h" | 40 #include "base/threading/thread_checker.h" |
| 41 #include "base/time/time.h" | 41 #include "base/time/time.h" |
| 42 #include "testing/gtest/include/gtest/gtest.h" | 42 #include "testing/gtest/include/gtest/gtest.h" |
| 43 | 43 |
| 44 #if defined(OS_MACOSX) | 44 #if defined(OS_MACOSX) |
| 45 #include "base/mac/scoped_nsautorelease_pool.h" | 45 #include "base/mac/scoped_nsautorelease_pool.h" |
| 46 #endif | 46 #endif |
| 47 | 47 |
| 48 #if defined(OS_WIN) | |
| 49 #include "base/win/windows_version.h" | |
| 50 #endif | |
| 51 | |
| 52 namespace base { | 48 namespace base { |
| 53 | 49 |
| 54 // 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 . |
| 55 using ::operator<<; | 51 using ::operator<<; |
| 56 | 52 |
| 57 // The environment variable name for the total number of test shards. | 53 // The environment variable name for the total number of test shards. |
| 58 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; | 54 const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; |
| 59 // The environment variable name for the test shard index. | 55 // The environment variable name for the test shard index. |
| 60 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; | 56 const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; |
| 61 | 57 |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 | 219 |
| 224 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | 220 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); |
| 225 iter != switches.end(); ++iter) { | 221 iter != switches.end(); ++iter) { |
| 226 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); | 222 new_command_line.AppendSwitchNative((*iter).first, (*iter).second); |
| 227 } | 223 } |
| 228 | 224 |
| 229 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine | 225 // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine |
| 230 // does not really support removing switches well, and trying to do that | 226 // does not really support removing switches well, and trying to do that |
| 231 // on a CommandLine with a wrapper is known to break. | 227 // on a CommandLine with a wrapper is known to break. |
| 232 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. | 228 // TODO(phajdan.jr): Give it a try to support CommandLine removing switches. |
| 233 #if defined(OS_WIN) | 229 #if defined(OS_POSIX) |
| 234 new_command_line.PrependWrapper(ASCIIToUTF16(wrapper)); | |
| 235 #elif defined(OS_POSIX) | |
| 236 new_command_line.PrependWrapper(wrapper); | 230 new_command_line.PrependWrapper(wrapper); |
| 237 #endif | 231 #endif |
| 238 | 232 |
| 239 return new_command_line; | 233 return new_command_line; |
| 240 } | 234 } |
| 241 | 235 |
| 242 // Launches a child process using |command_line|. If the child process is still | 236 // Launches a child process using |command_line|. If the child process is still |
| 243 // running after |timeout|, it is terminated and |*was_timeout| is set to true. | 237 // running after |timeout|, it is terminated and |*was_timeout| is set to true. |
| 244 // Returns exit code of the process. | 238 // Returns exit code of the process. |
| 245 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, | 239 int LaunchChildTestProcessWithOptions(const CommandLine& command_line, |
| 246 const LaunchOptions& options, | 240 const LaunchOptions& options, |
| 247 int flags, | 241 int flags, |
| 248 TimeDelta timeout, | 242 TimeDelta timeout, |
| 249 bool* was_timeout) { | 243 bool* was_timeout) { |
| 250 #if defined(OS_POSIX) | 244 #if defined(OS_POSIX) |
| 251 // Make sure an option we rely on is present - see LaunchChildGTestProcess. | 245 // Make sure an option we rely on is present - see LaunchChildGTestProcess. |
| 252 DCHECK(options.new_process_group); | 246 DCHECK(options.new_process_group); |
| 253 #endif | 247 #endif |
| 254 | 248 |
| 255 LaunchOptions new_options(options); | 249 LaunchOptions new_options(options); |
| 256 | 250 |
| 257 #if defined(OS_WIN) | |
| 258 DCHECK(!new_options.job_handle); | |
| 259 | |
| 260 win::ScopedHandle job_handle; | |
| 261 if (flags & TestLauncher::USE_JOB_OBJECTS) { | |
| 262 job_handle.Set(CreateJobObject(NULL, NULL)); | |
| 263 if (!job_handle.IsValid()) { | |
| 264 LOG(ERROR) << "Could not create JobObject."; | |
| 265 return -1; | |
| 266 } | |
| 267 | |
| 268 DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | |
| 269 | |
| 270 // Allow break-away from job since sandbox and few other places rely on it | |
| 271 // on Windows versions prior to Windows 8 (which supports nested jobs). | |
| 272 if (win::GetVersion() < win::VERSION_WIN8 && | |
| 273 flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) { | |
| 274 job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; | |
| 275 } | |
| 276 | |
| 277 if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) { | |
| 278 LOG(ERROR) << "Could not SetJobObjectLimitFlags."; | |
| 279 return -1; | |
| 280 } | |
| 281 | |
| 282 new_options.job_handle = job_handle.Get(); | |
| 283 } | |
| 284 #endif // defined(OS_WIN) | |
| 285 | 251 |
| 286 #if defined(OS_LINUX) | 252 #if defined(OS_LINUX) |
| 287 // To prevent accidental privilege sharing to an untrusted child, processes | 253 // To prevent accidental privilege sharing to an untrusted child, processes |
| 288 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this | 254 // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this |
| 289 // new child will be privileged and trusted. | 255 // new child will be privileged and trusted. |
| 290 new_options.allow_new_privs = true; | 256 new_options.allow_new_privs = true; |
| 291 #endif | 257 #endif |
| 292 | 258 |
| 293 Process process; | 259 Process process; |
| 294 | 260 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 bool redirect_stdio, | 320 bool redirect_stdio, |
| 355 SingleThreadTaskRunner* task_runner, | 321 SingleThreadTaskRunner* task_runner, |
| 356 const TestLauncher::LaunchChildGTestProcessCallback& callback) { | 322 const TestLauncher::LaunchChildGTestProcessCallback& callback) { |
| 357 TimeTicks start_time = TimeTicks::Now(); | 323 TimeTicks start_time = TimeTicks::Now(); |
| 358 | 324 |
| 359 // Redirect child process output to a file. | 325 // Redirect child process output to a file. |
| 360 FilePath output_file; | 326 FilePath output_file; |
| 361 CHECK(CreateTemporaryFile(&output_file)); | 327 CHECK(CreateTemporaryFile(&output_file)); |
| 362 | 328 |
| 363 LaunchOptions options; | 329 LaunchOptions options; |
| 364 #if defined(OS_WIN) | 330 #if defined(OS_POSIX) |
| 365 win::ScopedHandle handle; | |
| 366 | |
| 367 if (redirect_stdio) { | |
| 368 // Make the file handle inheritable by the child. | |
| 369 SECURITY_ATTRIBUTES sa_attr; | |
| 370 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
| 371 sa_attr.lpSecurityDescriptor = NULL; | |
| 372 sa_attr.bInheritHandle = TRUE; | |
| 373 | |
| 374 handle.Set(CreateFile(output_file.value().c_str(), | |
| 375 GENERIC_WRITE, | |
| 376 FILE_SHARE_READ | FILE_SHARE_DELETE, | |
| 377 &sa_attr, | |
| 378 OPEN_EXISTING, | |
| 379 FILE_ATTRIBUTE_TEMPORARY, | |
| 380 NULL)); | |
| 381 CHECK(handle.IsValid()); | |
| 382 options.inherit_handles = true; | |
| 383 options.stdin_handle = INVALID_HANDLE_VALUE; | |
| 384 options.stdout_handle = handle.Get(); | |
| 385 options.stderr_handle = handle.Get(); | |
| 386 } | |
| 387 #elif defined(OS_POSIX) | |
| 388 options.new_process_group = true; | 331 options.new_process_group = true; |
| 389 #if defined(OS_LINUX) | 332 #if defined(OS_LINUX) |
| 390 options.kill_on_parent_death = true; | 333 options.kill_on_parent_death = true; |
| 391 #endif // defined(OS_LINUX) | 334 #endif // defined(OS_LINUX) |
| 392 | 335 |
| 393 FileHandleMappingVector fds_mapping; | 336 FileHandleMappingVector fds_mapping; |
| 394 ScopedFD output_file_fd; | 337 ScopedFD output_file_fd; |
| 395 | 338 |
| 396 if (redirect_stdio) { | 339 if (redirect_stdio) { |
| 397 output_file_fd.reset(open(output_file.value().c_str(), O_RDWR)); | 340 output_file_fd.reset(open(output_file.value().c_str(), O_RDWR)); |
| 398 CHECK(output_file_fd.is_valid()); | 341 CHECK(output_file_fd.is_valid()); |
| 399 | 342 |
| 400 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); | 343 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO)); |
| 401 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); | 344 fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO)); |
| 402 options.fds_to_remap = &fds_mapping; | 345 options.fds_to_remap = &fds_mapping; |
| 403 } | 346 } |
| 404 #endif | 347 #endif |
| 405 | 348 |
| 406 bool was_timeout = false; | 349 bool was_timeout = false; |
| 407 int exit_code = LaunchChildTestProcessWithOptions( | 350 int exit_code = LaunchChildTestProcessWithOptions( |
| 408 command_line, options, flags, timeout, &was_timeout); | 351 command_line, options, flags, timeout, &was_timeout); |
| 409 | 352 |
| 410 if (redirect_stdio) { | 353 if (redirect_stdio) { |
| 411 #if defined(OS_WIN) | 354 #if defined(OS_POSIX) |
| 412 FlushFileBuffers(handle.Get()); | |
| 413 handle.Close(); | |
| 414 #elif defined(OS_POSIX) | |
| 415 output_file_fd.reset(); | 355 output_file_fd.reset(); |
| 416 #endif | 356 #endif |
| 417 } | 357 } |
| 418 | 358 |
| 419 std::string output_file_contents; | 359 std::string output_file_contents; |
| 420 CHECK(ReadFileToString(output_file, &output_file_contents)); | 360 CHECK(ReadFileToString(output_file, &output_file_contents)); |
| 421 | 361 |
| 422 if (!DeleteFile(output_file, false)) { | 362 if (!DeleteFile(output_file, false)) { |
| 423 // This needs to be non-fatal at least for Windows. | 363 // This needs to be non-fatal at least for Windows. |
| 424 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); | 364 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe(); |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 #endif | 809 #endif |
| 870 | 810 |
| 871 #if defined(OS_POSIX) | 811 #if defined(OS_POSIX) |
| 872 results_tracker_.AddGlobalTag("OS_POSIX"); | 812 results_tracker_.AddGlobalTag("OS_POSIX"); |
| 873 #endif | 813 #endif |
| 874 | 814 |
| 875 #if defined(OS_SOLARIS) | 815 #if defined(OS_SOLARIS) |
| 876 results_tracker_.AddGlobalTag("OS_SOLARIS"); | 816 results_tracker_.AddGlobalTag("OS_SOLARIS"); |
| 877 #endif | 817 #endif |
| 878 | 818 |
| 879 #if defined(OS_WIN) | |
| 880 results_tracker_.AddGlobalTag("OS_WIN"); | |
| 881 #endif | |
| 882 | |
| 883 // CPU-related tags. | 819 // CPU-related tags. |
| 884 #if defined(ARCH_CPU_32_BITS) | 820 #if defined(ARCH_CPU_32_BITS) |
| 885 results_tracker_.AddGlobalTag("CPU_32_BITS"); | 821 results_tracker_.AddGlobalTag("CPU_32_BITS"); |
| 886 #endif | 822 #endif |
| 887 | 823 |
| 888 #if defined(ARCH_CPU_64_BITS) | 824 #if defined(ARCH_CPU_64_BITS) |
| 889 results_tracker_.AddGlobalTag("CPU_64_BITS"); | 825 results_tracker_.AddGlobalTag("CPU_64_BITS"); |
| 890 #endif | 826 #endif |
| 891 | 827 |
| 892 return true; | 828 return true; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 DCHECK(thread_checker_.CalledOnValidThread()); | 961 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1026 | 962 |
| 1027 AutoLock lock(g_live_processes_lock.Get()); | 963 AutoLock lock(g_live_processes_lock.Get()); |
| 1028 | 964 |
| 1029 fprintf(stdout, "Still waiting for the following processes to finish:\n"); | 965 fprintf(stdout, "Still waiting for the following processes to finish:\n"); |
| 1030 | 966 |
| 1031 for (std::map<ProcessHandle, CommandLine>::iterator i = | 967 for (std::map<ProcessHandle, CommandLine>::iterator i = |
| 1032 g_live_processes.Get().begin(); | 968 g_live_processes.Get().begin(); |
| 1033 i != g_live_processes.Get().end(); | 969 i != g_live_processes.Get().end(); |
| 1034 ++i) { | 970 ++i) { |
| 1035 #if defined(OS_WIN) | |
| 1036 fwprintf(stdout, L"\t%s\n", i->second.GetCommandLineString().c_str()); | |
| 1037 #else | |
| 1038 fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str()); | 971 fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str()); |
| 1039 #endif | |
| 1040 } | 972 } |
| 1041 | 973 |
| 1042 fflush(stdout); | 974 fflush(stdout); |
| 1043 | 975 |
| 1044 // Arm the timer again - otherwise it would fire only once. | 976 // Arm the timer again - otherwise it would fire only once. |
| 1045 watchdog_timer_.Reset(); | 977 watchdog_timer_.Reset(); |
| 1046 } | 978 } |
| 1047 | 979 |
| 1048 std::string GetTestOutputSnippet(const TestResult& result, | 980 std::string GetTestOutputSnippet(const TestResult& result, |
| 1049 const std::string& full_output) { | 981 const std::string& full_output) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1070 } | 1002 } |
| 1071 | 1003 |
| 1072 std::string snippet(full_output.substr(run_pos)); | 1004 std::string snippet(full_output.substr(run_pos)); |
| 1073 if (end_pos != std::string::npos) | 1005 if (end_pos != std::string::npos) |
| 1074 snippet = full_output.substr(run_pos, end_pos - run_pos); | 1006 snippet = full_output.substr(run_pos, end_pos - run_pos); |
| 1075 | 1007 |
| 1076 return snippet; | 1008 return snippet; |
| 1077 } | 1009 } |
| 1078 | 1010 |
| 1079 } // namespace base | 1011 } // namespace base |
| OLD | NEW |