This source file includes following definitions.
- RemoveAnyPrePrefixes
 
- PrintUsage
 
- ShouldRunTest
 
- GetPreTestName
 
- RunTests
 
- RetryTests
 
- DoRunTest
 
- RunDependentTest
 
- GTestCallback
 
- LaunchTests
 
- GetCurrentTestLauncherDelegate
 
- GetContentMainParams
 
#include "content/public/test/test_launcher.h"
#include <map>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/launcher/test_launcher.h"
#include "base/test/test_suite.h"
#include "base/test/test_switches.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "content/public/app/content_main.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/app/startup_helper_win.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/sandbox_init.h"
#include "content/public/test/browser_test.h"
#include "net/base/escape.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
#include "base/base_switches.h"
#include "content/common/sandbox_win.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/sandbox_types.h"
#elif defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
#endif
namespace content {
namespace {
const char kPreTestPrefix[] = "PRE_";
const char kManualTestPrefix[] = "MANUAL_";
TestLauncherDelegate* g_launcher_delegate;
ContentMainParams* g_params;
std::string RemoveAnyPrePrefixes(const std::string& test_name) {
  std::string result(test_name);
  ReplaceSubstringsAfterOffset(&result, 0, kPreTestPrefix, std::string());
  return result;
}
void PrintUsage() {
  fprintf(stdout,
          "Runs tests using the gtest framework, each batch of tests being\n"
          "run in their own process. Supported command-line flags:\n"
          "\n"
          " Common flags:\n"
          "  --gtest_filter=...\n"
          "    Runs a subset of tests (see --gtest_help for more info).\n"
          "\n"
          "  --help\n"
          "    Shows this message.\n"
          "\n"
          "  --gtest_help\n"
          "    Shows the gtest help message.\n"
          "\n"
          "  --test-launcher-jobs=N\n"
          "    Sets the number of parallel test jobs to N.\n"
          "\n"
          "  --single_process\n"
          "    Runs the tests and the launcher in the same process. Useful\n"
          "    for debugging a specific test in a debugger.\n"
          "\n"
          " Other flags:\n"
          "  --test-launcher-retry-limit=N\n"
          "    Sets the limit of test retries on failures to N.\n"
          "\n"
          "  --test-launcher-summary-output=PATH\n"
          "    Saves a JSON machine-readable summary of the run.\n"
          "\n"
          "  --test-launcher-print-test-stdio=auto|always|never\n"
          "    Controls when full test output is printed.\n"
          "    auto means to print it when the test failed.\n"
          "\n"
          "  --test-launcher-total-shards=N\n"
          "    Sets the total number of shards to N.\n"
          "\n"
          "  --test-launcher-shard-index=N\n"
          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
}
class WrapperTestLauncherDelegate : public base::TestLauncherDelegate {
 public:
  explicit WrapperTestLauncherDelegate(
      content::TestLauncherDelegate* launcher_delegate)
      : launcher_delegate_(launcher_delegate) {
    CHECK(temp_dir_.CreateUniqueTempDir());
  }
  
  virtual bool ShouldRunTest(const testing::TestCase* test_case,
                             const testing::TestInfo* test_info) OVERRIDE;
  virtual size_t RunTests(base::TestLauncher* test_launcher,
                          const std::vector<std::string>& test_names) OVERRIDE;
  virtual size_t RetryTests(
      base::TestLauncher* test_launcher,
      const std::vector<std::string>& test_names) OVERRIDE;
 private:
  void DoRunTest(base::TestLauncher* test_launcher,
                 const std::string& test_name);
  
  
  void RunDependentTest(base::TestLauncher* test_launcher,
                        const std::string test_name,
                        const base::TestResult& pre_test_result);
  
  void GTestCallback(
      base::TestLauncher* test_launcher,
      const std::string& test_name,
      int exit_code,
      const base::TimeDelta& elapsed_time,
      bool was_timeout,
      const std::string& output);
  content::TestLauncherDelegate* launcher_delegate_;
  
  typedef std::map<std::string, std::string> DependentTestMap;
  DependentTestMap dependent_test_map_;
  DependentTestMap reverse_dependent_test_map_;
  
  
  
  
  
  
  typedef std::map<std::string, base::FilePath> UserDataDirMap;
  UserDataDirMap user_data_dir_map_;
  
  std::set<std::string> all_test_names_;
  
  base::ScopedTempDir temp_dir_;
  DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate);
};
bool WrapperTestLauncherDelegate::ShouldRunTest(
    const testing::TestCase* test_case,
    const testing::TestInfo* test_info) {
  all_test_names_.insert(
      std::string(test_case->name()) + "." + test_info->name());
  if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) &&
      !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) {
    return false;
  }
  if (StartsWithASCII(test_info->name(), kPreTestPrefix, true)) {
    
    
    return false;
  }
  return true;
}
std::string GetPreTestName(const std::string& full_name) {
  size_t dot_pos = full_name.find('.');
  CHECK_NE(dot_pos, std::string::npos);
  std::string test_case_name = full_name.substr(0, dot_pos);
  std::string test_name = full_name.substr(dot_pos + 1);
  return test_case_name + "." + kPreTestPrefix + test_name;
}
size_t WrapperTestLauncherDelegate::RunTests(
    base::TestLauncher* test_launcher,
    const std::vector<std::string>& test_names) {
  dependent_test_map_.clear();
  reverse_dependent_test_map_.clear();
  user_data_dir_map_.clear();
  
  size_t additional_tests_to_run_count = 0;
  
  for (size_t i = 0; i < test_names.size(); i++) {
    std::string full_name(test_names[i]);
    std::string pre_test_name(GetPreTestName(full_name));
    while (ContainsKey(all_test_names_, pre_test_name)) {
      additional_tests_to_run_count++;
      DCHECK(!ContainsKey(dependent_test_map_, pre_test_name));
      dependent_test_map_[pre_test_name] = full_name;
      DCHECK(!ContainsKey(reverse_dependent_test_map_, full_name));
      reverse_dependent_test_map_[full_name] = pre_test_name;
      full_name = pre_test_name;
      pre_test_name = GetPreTestName(pre_test_name);
    }
  }
  for (size_t i = 0; i < test_names.size(); i++) {
    std::string full_name(test_names[i]);
    
    DCHECK_EQ(full_name, RemoveAnyPrePrefixes(full_name));
    if (!ContainsKey(user_data_dir_map_, full_name)) {
      base::FilePath temp_dir;
      CHECK(base::CreateTemporaryDirInDir(temp_dir_.path(),
                                          FILE_PATH_LITERAL("d"), &temp_dir));
      user_data_dir_map_[full_name] = temp_dir;
    }
    
    while (ContainsKey(reverse_dependent_test_map_, full_name))
      full_name = GetPreTestName(full_name);
    DoRunTest(test_launcher, full_name);
  }
  return test_names.size() + additional_tests_to_run_count;
}
size_t WrapperTestLauncherDelegate::RetryTests(
    base::TestLauncher* test_launcher,
    const std::vector<std::string>& test_names) {
  
  std::vector<std::string> tests_to_run_now;
  
  std::set<std::string> test_names_set(test_names.begin(), test_names.end());
  
  
  for (size_t i = 0; i < test_names.size(); i++) {
    std::string test_name(test_names[i]);
    while (ContainsKey(reverse_dependent_test_map_, test_name)) {
      test_name = reverse_dependent_test_map_[test_name];
      test_names_set.insert(test_name);
    }
  }
  
  
  for (UserDataDirMap::const_iterator i = user_data_dir_map_.begin();
       i != user_data_dir_map_.end();
       ++i) {
    
    if (!base::DeleteFile(i->second, true)) {
      LOG(WARNING) << "Failed to delete " << i->second.value();
    }
  }
  user_data_dir_map_.clear();
  for (std::set<std::string>::const_iterator i = test_names_set.begin();
       i != test_names_set.end();
       ++i) {
    std::string full_name(*i);
    
    
    std::string test_name_no_pre(RemoveAnyPrePrefixes(full_name));
    if (!ContainsKey(user_data_dir_map_, test_name_no_pre)) {
      base::FilePath temp_dir;
      CHECK(base::CreateTemporaryDirInDir(temp_dir_.path(),
                                          FILE_PATH_LITERAL("d"), &temp_dir));
      user_data_dir_map_[test_name_no_pre] = temp_dir;
    }
    size_t dot_pos = full_name.find('.');
    CHECK_NE(dot_pos, std::string::npos);
    std::string test_case_name = full_name.substr(0, dot_pos);
    std::string test_name = full_name.substr(dot_pos + 1);
    std::string pre_test_name(
        test_case_name + "." + kPreTestPrefix + test_name);
    if (!ContainsKey(test_names_set, pre_test_name))
      tests_to_run_now.push_back(full_name);
  }
  for (size_t i = 0; i < tests_to_run_now.size(); i++)
    DoRunTest(test_launcher, tests_to_run_now[i]);
  return test_names_set.size();
}
void WrapperTestLauncherDelegate::DoRunTest(base::TestLauncher* test_launcher,
                                            const std::string& test_name) {
  std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
  CommandLine cmd_line(*CommandLine::ForCurrentProcess());
  CHECK(launcher_delegate_->AdjustChildProcessCommandLine(
            &cmd_line, user_data_dir_map_[test_name_no_pre]));
  CommandLine new_cmd_line(cmd_line.GetProgram());
  CommandLine::SwitchMap switches = cmd_line.GetSwitches();
  
  
  switches.erase(base::kGTestOutputFlag);
  for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
       iter != switches.end(); ++iter) {
    new_cmd_line.AppendSwitchNative(iter->first, iter->second);
  }
  
  
  new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests");
  new_cmd_line.AppendSwitchASCII("gtest_filter", test_name);
  new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
  char* browser_wrapper = getenv("BROWSER_WRAPPER");
  test_launcher->LaunchChildGTestProcess(
      new_cmd_line,
      browser_wrapper ? browser_wrapper : std::string(),
      TestTimeouts::action_max_timeout(),
      base::Bind(&WrapperTestLauncherDelegate::GTestCallback,
                 base::Unretained(this),
                 test_launcher,
                 test_name));
}
void WrapperTestLauncherDelegate::RunDependentTest(
    base::TestLauncher* test_launcher,
    const std::string test_name,
    const base::TestResult& pre_test_result) {
  if (pre_test_result.status == base::TestResult::TEST_SUCCESS) {
    
    DoRunTest(test_launcher, test_name);
  } else {
    
    base::TestResult test_result;
    test_result.full_name = test_name;
    test_result.status = base::TestResult::TEST_SKIPPED;
    test_launcher->OnTestFinished(test_result);
    if (ContainsKey(dependent_test_map_, test_name)) {
      RunDependentTest(test_launcher,
                       dependent_test_map_[test_name],
                       test_result);
    }
  }
}
void WrapperTestLauncherDelegate::GTestCallback(
    base::TestLauncher* test_launcher,
    const std::string& test_name,
    int exit_code,
    const base::TimeDelta& elapsed_time,
    bool was_timeout,
    const std::string& output) {
  base::TestResult result;
  result.full_name = test_name;
  
  if (exit_code == 0)
    result.status = base::TestResult::TEST_SUCCESS;
  else if (was_timeout)
    result.status = base::TestResult::TEST_TIMEOUT;
  else
    result.status = base::TestResult::TEST_FAILURE;
  result.elapsed_time = elapsed_time;
  result.output_snippet = GetTestOutputSnippet(result, output);
  if (ContainsKey(dependent_test_map_, test_name)) {
    RunDependentTest(test_launcher, dependent_test_map_[test_name], result);
  } else {
    
    
    std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
    if (ContainsKey(user_data_dir_map_, test_name_no_pre)) {
      if (!base::DeleteFile(user_data_dir_map_[test_name_no_pre], true)) {
        LOG(WARNING) << "Failed to delete "
                     << user_data_dir_map_[test_name_no_pre].value();
      }
      user_data_dir_map_.erase(test_name_no_pre);
    }
  }
  test_launcher->OnTestFinished(result);
}
}  
const char kHelpFlag[]   = "help";
const char kLaunchAsBrowser[] = "as-browser";
const char kRunManualTestsFlag[] = "run-manual";
const char kSingleProcessTestsFlag[]   = "single_process";
TestLauncherDelegate::~TestLauncherDelegate() {
}
int LaunchTests(TestLauncherDelegate* launcher_delegate,
                int default_jobs,
                int argc,
                char** argv) {
  DCHECK(!g_launcher_delegate);
  g_launcher_delegate = launcher_delegate;
  CommandLine::Init(argc, argv);
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(kHelpFlag)) {
    PrintUsage();
    return 0;
  }
  scoped_ptr<ContentMainDelegate> chrome_main_delegate(
      launcher_delegate->CreateContentMainDelegate());
  ContentMainParams params(chrome_main_delegate.get());
#if defined(OS_WIN)
  sandbox::SandboxInterfaceInfo sandbox_info = {0};
  InitializeSandboxInfo(&sandbox_info);
  params.instance = GetModuleHandle(NULL);
  params.sandbox_info = &sandbox_info;
#elif !defined(OS_ANDROID)
  params.argc = argc;
  params.argv = const_cast<const char**>(argv);
#endif  
  if (command_line->HasSwitch(kSingleProcessTestsFlag) ||
      (command_line->HasSwitch(switches::kSingleProcess) &&
       command_line->HasSwitch(base::kGTestFilterFlag)) ||
      command_line->HasSwitch(base::kGTestListTestsFlag) ||
      command_line->HasSwitch(base::kGTestHelpFlag)) {
    g_params = ¶ms;
    return launcher_delegate->RunTestSuite(argc, argv);
  }
#if !defined(OS_ANDROID)
  if (command_line->HasSwitch(switches::kProcessType) ||
      command_line->HasSwitch(kLaunchAsBrowser)) {
    return ContentMain(params);
  }
#endif
  base::AtExitManager at_exit;
  testing::InitGoogleTest(&argc, argv);
  TestTimeouts::Initialize();
  fprintf(stdout,
      "IMPORTANT DEBUGGING NOTE: each test is run inside its own process.\n"
      "For debugging a test inside a debugger, use the\n"
      "--gtest_filter=<your_test_name> flag along with either\n"
      "--single_process (to run the test in one launcher/browser process) or\n"
      "--single-process (to do the above, and also run Chrome in single-"
          "process mode).\n");
  base::MessageLoopForIO message_loop;
  
  launcher_delegate->AdjustDefaultParallelJobs(&default_jobs);
  WrapperTestLauncherDelegate delegate(launcher_delegate);
  base::TestLauncher launcher(&delegate, default_jobs);
  bool success = launcher.Run(argc, argv);
  return (success ? 0 : 1);
}
TestLauncherDelegate* GetCurrentTestLauncherDelegate() {
  return g_launcher_delegate;
}
ContentMainParams* GetContentMainParams() {
  return g_params;
}
}