Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / base / test / launcher / test_launcher.cc
index 889244d..9150e63 100644 (file)
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/environment.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/format_macros.h"
+#include "base/hash.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #endif
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace base {
 
+// Launches a child process using |command_line|. If the child process is still
+// running after |timeout|, it is terminated and |*was_timeout| is set to true.
+// Returns exit code of the process.
+int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
+                                      const LaunchOptions& options,
+                                      int flags,
+                                      base::TimeDelta timeout,
+                                      bool* was_timeout);
+
 // See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/uT3FaE_sgkAJ .
 using ::operator<<;
 
@@ -66,6 +80,11 @@ const char kUnreliableResultsTag[] = "UNRELIABLE_RESULTS";
 // debugging in case the process hangs anyway.
 const int kOutputTimeoutSeconds = 15;
 
+// Limit of output snippet lines when printing to stdout.
+// Avoids flooding the logs with amount of output that gums up
+// the infrastructure.
+const size_t kOutputSnippetLinesLimit = 5000;
+
 // Set of live launch test processes with corresponding lock (it is allowed
 // for callers to launch processes on different threads).
 LazyInstance<std::map<ProcessHandle, CommandLine> > g_live_processes
@@ -208,6 +227,7 @@ void RunCallback(
 void DoLaunchChildTestProcess(
     const CommandLine& command_line,
     base::TimeDelta timeout,
+    int flags,
     bool redirect_stdio,
     scoped_refptr<MessageLoopProxy> message_loop_proxy,
     const TestLauncher::LaunchChildGTestProcessCallback& callback) {
@@ -259,7 +279,7 @@ void DoLaunchChildTestProcess(
 
   bool was_timeout = false;
   int exit_code = LaunchChildTestProcessWithOptions(
-      command_line, options, timeout, &was_timeout);
+      command_line, options, flags, timeout, &was_timeout);
 
   if (redirect_stdio) {
 #if defined(OS_WIN)
@@ -320,20 +340,6 @@ TestLauncher::TestLauncher(TestLauncherDelegate* launcher_delegate,
                       this,
                       &TestLauncher::OnOutputTimeout),
       parallel_jobs_(parallel_jobs) {
-  if (BotModeEnabled()) {
-    fprintf(stdout,
-            "Enabling defaults optimized for continuous integration bots.\n");
-    fflush(stdout);
-
-    // Enable test retries by default for bots. This can be still overridden
-    // from command line using --test-launcher-retry-limit flag.
-    retry_limit_ = 3;
-  } else {
-    // Default to serial test execution if not running on a bot. This makes it
-    // possible to disable stdio redirection and can still be overridden with
-    // --test-launcher-jobs flag.
-    parallel_jobs_ = 1;
-  }
 }
 
 TestLauncher::~TestLauncher() {
@@ -341,7 +347,7 @@ TestLauncher::~TestLauncher() {
     worker_pool_owner_->pool()->Shutdown();
 }
 
-bool TestLauncher::Run(int argc, char** argv) {
+bool TestLauncher::Run() {
   if (!Init())
     return false;
 
@@ -393,6 +399,7 @@ void TestLauncher::LaunchChildGTestProcess(
     const CommandLine& command_line,
     const std::string& wrapper,
     base::TimeDelta timeout,
+    int flags,
     const LaunchChildGTestProcessCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -410,6 +417,7 @@ void TestLauncher::LaunchChildGTestProcess(
       Bind(&DoLaunchChildTestProcess,
            new_command_line,
            timeout,
+           flags,
            redirect_stdio,
            MessageLoopProxy::current(),
            Bind(&TestLauncher::OnLaunchTestProcessFinished,
@@ -438,7 +446,16 @@ void TestLauncher::OnTestFinished(const TestResult& result) {
                  << ": " << print_test_stdio;
   }
   if (print_snippet) {
-    fprintf(stdout, "%s", result.output_snippet.c_str());
+    std::vector<std::string> snippet_lines;
+    SplitString(result.output_snippet, '\n', &snippet_lines);
+    if (snippet_lines.size() > kOutputSnippetLinesLimit) {
+      size_t truncated_size = snippet_lines.size() - kOutputSnippetLinesLimit;
+      snippet_lines.erase(
+          snippet_lines.begin(),
+          snippet_lines.begin() + truncated_size);
+      snippet_lines.insert(snippet_lines.begin(), "<truncated>");
+    }
+    fprintf(stdout, "%s", JoinString(snippet_lines, "\n").c_str());
     fflush(stdout);
   }
 
@@ -448,9 +465,6 @@ void TestLauncher::OnTestFinished(const TestResult& result) {
     tests_to_retry_.insert(result.full_name);
   }
 
-  if (result.status == TestResult::TEST_UNKNOWN)
-    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
-
   results_tracker_.AddTestResult(result);
 
   // TODO(phajdan.jr): Align counter (padding).
@@ -488,7 +502,7 @@ void TestLauncher::OnTestFinished(const TestResult& result) {
     test_broken_count_++;
   }
   size_t broken_threshold =
-      std::max(static_cast<size_t>(10), test_started_count_ / 10);
+      std::max(static_cast<size_t>(20), test_started_count_ / 10);
   if (test_broken_count_ >= broken_threshold) {
     fprintf(stdout, "Too many badly broken tests (%" PRIuS "), exiting now.\n",
             test_broken_count_);
@@ -552,6 +566,12 @@ void TestLauncher::OnTestFinished(const TestResult& result) {
   test_started_count_ += retry_started_count;
 }
 
+// static
+std::string TestLauncher::FormatFullTestName(const std::string& test_case_name,
+                                             const std::string& test_name) {
+  return test_case_name + "." + test_name;
+}
+
 bool TestLauncher::Init() {
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
 
@@ -620,6 +640,9 @@ bool TestLauncher::Init() {
     }
 
     retry_limit_ = retry_limit;
+  } else if (!CommandLine::ForCurrentProcess()->HasSwitch(kGTestFilterFlag)) {
+    // Retry failures 3 times by default if we are running all of the tests.
+    retry_limit_ = 3;
   }
 
   if (CommandLine::ForCurrentProcess()->HasSwitch(
@@ -633,7 +656,12 @@ bool TestLauncher::Init() {
     }
 
     parallel_jobs_ = jobs;
+  } else if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestFilterFlag)) {
+    // Do not run jobs in parallel by default if we are running a subset of
+    // the tests.
+    parallel_jobs_ = 1;
   }
+
   fprintf(stdout, "Using %" PRIuS " parallel jobs.\n", parallel_jobs_);
   fflush(stdout);
   worker_pool_owner_.reset(
@@ -755,17 +783,14 @@ bool TestLauncher::Init() {
 void TestLauncher::RunTests() {
   testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
 
-  int num_runnable_tests = 0;
-
   std::vector<std::string> test_names;
 
   for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
     const testing::TestCase* test_case = unit_test->GetTestCase(i);
     for (int j = 0; j < test_case->total_test_count(); ++j) {
       const testing::TestInfo* test_info = test_case->GetTestInfo(j);
-      std::string test_name = test_info->test_case_name();
-      test_name.append(".");
-      test_name.append(test_info->name());
+      std::string test_name = FormatFullTestName(
+          test_info->test_case_name(), test_info->name());
 
       results_tracker_.AddTest(test_name);
 
@@ -778,6 +803,9 @@ void TestLauncher::RunTests() {
           continue;
       }
 
+      if (!launcher_delegate_->ShouldRunTest(test_case, test_info))
+        continue;
+
       // Skip the test that doesn't match the filter (if given).
       if (!positive_test_filter_.empty()) {
         bool found = false;
@@ -801,11 +829,10 @@ void TestLauncher::RunTests() {
       if (excluded)
         continue;
 
-      if (!launcher_delegate_->ShouldRunTest(test_case, test_info))
-        continue;
-
-      if (num_runnable_tests++ % total_shards_ != shard_index_)
+      if (base::Hash(test_name) % total_shards_ !=
+          static_cast<uint32>(shard_index_)) {
         continue;
+      }
 
       test_names.push_back(test_name);
     }
@@ -868,6 +895,11 @@ void TestLauncher::OnLaunchTestProcessFinished(
 }
 
 void TestLauncher::OnTestIterationFinished() {
+  TestResultsTracker::TestStatusMap tests_by_status(
+      results_tracker_.GetTestStatusMapForCurrentIteration());
+  if (!tests_by_status[TestResult::TEST_UNKNOWN].empty())
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+
   // When we retry tests, success is determined by having nothing more
   // to retry (everything eventually passed), as opposed to having
   // no failures at all.
@@ -943,27 +975,6 @@ std::string GetTestOutputSnippet(const TestResult& result,
   return snippet;
 }
 
-int LaunchChildGTestProcess(const CommandLine& command_line,
-                            const std::string& wrapper,
-                            base::TimeDelta timeout,
-                            bool* was_timeout) {
-  LaunchOptions options;
-
-#if defined(OS_POSIX)
-  // On POSIX, we launch the test in a new process group with pgid equal to
-  // its pid. Any child processes that the test may create will inherit the
-  // same pgid. This way, if the test is abruptly terminated, we can clean up
-  // any orphaned child processes it may have left behind.
-  options.new_process_group = true;
-#endif
-
-  return LaunchChildTestProcessWithOptions(
-      PrepareCommandLineForGTest(command_line, wrapper),
-      options,
-      timeout,
-      was_timeout);
-}
-
 CommandLine PrepareCommandLineForGTest(const CommandLine& command_line,
                                        const std::string& wrapper) {
   CommandLine new_command_line(command_line.GetProgram());
@@ -993,8 +1004,10 @@ CommandLine PrepareCommandLineForGTest(const CommandLine& command_line,
   return new_command_line;
 }
 
+// TODO(phajdan.jr): Move to anonymous namespace.
 int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
                                       const LaunchOptions& options,
+                                      int flags,
                                       base::TimeDelta timeout,
                                       bool* was_timeout) {
 #if defined(OS_POSIX)
@@ -1007,25 +1020,39 @@ int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
 #if defined(OS_WIN)
   DCHECK(!new_options.job_handle);
 
-  win::ScopedHandle job_handle(CreateJobObject(NULL, NULL));
-  if (!job_handle.IsValid()) {
-    LOG(ERROR) << "Could not create JobObject.";
-    return -1;
-  }
+  win::ScopedHandle job_handle;
+  if (flags & TestLauncher::USE_JOB_OBJECTS) {
+    job_handle.Set(CreateJobObject(NULL, NULL));
+    if (!job_handle.IsValid()) {
+      LOG(ERROR) << "Could not create JobObject.";
+      return -1;
+    }
 
-  // Allow break-away from job since sandbox and few other places rely on it
-  // on Windows versions prior to Windows 8 (which supports nested jobs).
-  // TODO(phajdan.jr): Do not allow break-away on Windows 8.
-  if (!SetJobObjectLimitFlags(job_handle.Get(),
-                              JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
-                              JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
-    LOG(ERROR) << "Could not SetJobObjectLimitFlags.";
-    return -1;
-  }
+    DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
 
-  new_options.job_handle = job_handle.Get();
+    // Allow break-away from job since sandbox and few other places rely on it
+    // on Windows versions prior to Windows 8 (which supports nested jobs).
+    if (win::GetVersion() < win::VERSION_WIN8 &&
+        flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) {
+      job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+    }
+
+    if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) {
+      LOG(ERROR) << "Could not SetJobObjectLimitFlags.";
+      return -1;
+    }
+
+    new_options.job_handle = job_handle.Get();
+  }
 #endif  // defined(OS_WIN)
 
+#if defined(OS_LINUX)
+  // To prevent accidental privilege sharing to an untrusted child, processes
+  // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
+  // new child will be privileged and trusted.
+  new_options.allow_new_privs = true;
+#endif
+
   base::ProcessHandle process_handle;
 
   {