Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/public/test/test_launcher.h"
      6 
      7 #include <map>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/command_line.h"
     12 #include "base/containers/hash_tables.h"
     13 #include "base/environment.h"
     14 #include "base/files/file_util.h"
     15 #include "base/files/scoped_temp_dir.h"
     16 #include "base/logging.h"
     17 #include "base/memory/linked_ptr.h"
     18 #include "base/memory/scoped_ptr.h"
     19 #include "base/message_loop/message_loop.h"
     20 #include "base/stl_util.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/strings/string_util.h"
     23 #include "base/strings/utf_string_conversions.h"
     24 #include "base/test/launcher/test_launcher.h"
     25 #include "base/test/test_suite.h"
     26 #include "base/test/test_switches.h"
     27 #include "base/test/test_timeouts.h"
     28 #include "base/time/time.h"
     29 #include "content/public/app/content_main.h"
     30 #include "content/public/app/content_main_delegate.h"
     31 #include "content/public/app/startup_helper_win.h"
     32 #include "content/public/common/content_switches.h"
     33 #include "content/public/common/sandbox_init.h"
     34 #include "content/public/test/browser_test.h"
     35 #include "net/base/escape.h"
     36 #include "testing/gtest/include/gtest/gtest.h"
     37 
     38 #if defined(OS_WIN)
     39 #include "base/base_switches.h"
     40 #include "content/common/sandbox_win.h"
     41 #include "sandbox/win/src/sandbox_factory.h"
     42 #include "sandbox/win/src/sandbox_types.h"
     43 #elif defined(OS_MACOSX)
     44 #include "base/mac/scoped_nsautorelease_pool.h"
     45 #endif
     46 
     47 namespace content {
     48 
     49 namespace {
     50 
     51 // Tests with this prefix run before the same test without it, and use the same
     52 // profile. i.e. Foo.PRE_Test runs and then Foo.Test. This allows writing tests
     53 // that span browser restarts.
     54 const char kPreTestPrefix[] = "PRE_";
     55 
     56 // Manual tests only run when --run-manual is specified. This allows writing
     57 // tests that don't run automatically but are still in the same test binary.
     58 // This is useful so that a team that wants to run a few tests doesn't have to
     59 // add a new binary that must be compiled on all builds.
     60 const char kManualTestPrefix[] = "MANUAL_";
     61 
     62 TestLauncherDelegate* g_launcher_delegate;
     63 ContentMainParams* g_params;
     64 
     65 std::string RemoveAnyPrePrefixes(const std::string& test_name) {
     66   std::string result(test_name);
     67   ReplaceSubstringsAfterOffset(&result, 0, kPreTestPrefix, std::string());
     68   return result;
     69 }
     70 
     71 void PrintUsage() {
     72   fprintf(stdout,
     73           "Runs tests using the gtest framework, each batch of tests being\n"
     74           "run in their own process. Supported command-line flags:\n"
     75           "\n"
     76           " Common flags:\n"
     77           "  --gtest_filter=...\n"
     78           "    Runs a subset of tests (see --gtest_help for more info).\n"
     79           "\n"
     80           "  --help\n"
     81           "    Shows this message.\n"
     82           "\n"
     83           "  --gtest_help\n"
     84           "    Shows the gtest help message.\n"
     85           "\n"
     86           "  --test-launcher-jobs=N\n"
     87           "    Sets the number of parallel test jobs to N.\n"
     88           "\n"
     89           "  --single_process\n"
     90           "    Runs the tests and the launcher in the same process. Useful\n"
     91           "    for debugging a specific test in a debugger.\n"
     92           "\n"
     93           " Other flags:\n"
     94           "  --test-launcher-retry-limit=N\n"
     95           "    Sets the limit of test retries on failures to N.\n"
     96           "\n"
     97           "  --test-launcher-summary-output=PATH\n"
     98           "    Saves a JSON machine-readable summary of the run.\n"
     99           "\n"
    100           "  --test-launcher-print-test-stdio=auto|always|never\n"
    101           "    Controls when full test output is printed.\n"
    102           "    auto means to print it when the test failed.\n"
    103           "\n"
    104           "  --test-launcher-total-shards=N\n"
    105           "    Sets the total number of shards to N.\n"
    106           "\n"
    107           "  --test-launcher-shard-index=N\n"
    108           "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
    109 }
    110 
    111 // Implementation of base::TestLauncherDelegate. This is also a test launcher,
    112 // wrapping a lower-level test launcher with content-specific code.
    113 class WrapperTestLauncherDelegate : public base::TestLauncherDelegate {
    114  public:
    115   explicit WrapperTestLauncherDelegate(
    116       content::TestLauncherDelegate* launcher_delegate)
    117       : launcher_delegate_(launcher_delegate) {
    118     CHECK(temp_dir_.CreateUniqueTempDir());
    119   }
    120 
    121   // base::TestLauncherDelegate:
    122   virtual bool ShouldRunTest(const testing::TestCase* test_case,
    123                              const testing::TestInfo* test_info) OVERRIDE;
    124   virtual size_t RunTests(base::TestLauncher* test_launcher,
    125                           const std::vector<std::string>& test_names) OVERRIDE;
    126   virtual size_t RetryTests(
    127       base::TestLauncher* test_launcher,
    128       const std::vector<std::string>& test_names) OVERRIDE;
    129 
    130  private:
    131   void DoRunTest(base::TestLauncher* test_launcher,
    132                  const std::string& test_name);
    133 
    134   // Launches test named |test_name| using parallel launcher,
    135   // given result of PRE_ test |pre_test_result|.
    136   void RunDependentTest(base::TestLauncher* test_launcher,
    137                         const std::string test_name,
    138                         const base::TestResult& pre_test_result);
    139 
    140   // Callback to receive result of a test.
    141   void GTestCallback(
    142       base::TestLauncher* test_launcher,
    143       const std::string& test_name,
    144       int exit_code,
    145       const base::TimeDelta& elapsed_time,
    146       bool was_timeout,
    147       const std::string& output);
    148 
    149   content::TestLauncherDelegate* launcher_delegate_;
    150 
    151   // Store dependent test name (map is indexed by full test name).
    152   typedef std::map<std::string, std::string> DependentTestMap;
    153   DependentTestMap dependent_test_map_;
    154   DependentTestMap reverse_dependent_test_map_;
    155 
    156   // Store unique data directory prefix for test names (without PRE_ prefixes).
    157   // PRE_ tests and tests that depend on them must share the same
    158   // data directory. Using test name as directory name leads to too long
    159   // names (exceeding UNIX_PATH_MAX, which creates a problem with
    160   // process_singleton_linux). Create a randomly-named temporary directory
    161   // and keep track of the names so that PRE_ tests can still re-use them.
    162   typedef std::map<std::string, base::FilePath> UserDataDirMap;
    163   UserDataDirMap user_data_dir_map_;
    164 
    165   // Store names of all seen tests to properly handle PRE_ tests.
    166   std::set<std::string> all_test_names_;
    167 
    168   // Temporary directory for user data directories.
    169   base::ScopedTempDir temp_dir_;
    170 
    171   DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate);
    172 };
    173 
    174 bool WrapperTestLauncherDelegate::ShouldRunTest(
    175     const testing::TestCase* test_case,
    176     const testing::TestInfo* test_info) {
    177   all_test_names_.insert(
    178       std::string(test_case->name()) + "." + test_info->name());
    179 
    180   if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) &&
    181       !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) {
    182     return false;
    183   }
    184 
    185   if (StartsWithASCII(test_info->name(), kPreTestPrefix, true)) {
    186     // We will actually run PRE_ tests, but to ensure they run on the same shard
    187     // as dependent tests, handle all these details internally.
    188     return false;
    189   }
    190 
    191   return true;
    192 }
    193 
    194 std::string GetPreTestName(const std::string& full_name) {
    195   size_t dot_pos = full_name.find('.');
    196   CHECK_NE(dot_pos, std::string::npos);
    197   std::string test_case_name = full_name.substr(0, dot_pos);
    198   std::string test_name = full_name.substr(dot_pos + 1);
    199   return test_case_name + "." + kPreTestPrefix + test_name;
    200 }
    201 
    202 size_t WrapperTestLauncherDelegate::RunTests(
    203     base::TestLauncher* test_launcher,
    204     const std::vector<std::string>& test_names) {
    205   dependent_test_map_.clear();
    206   reverse_dependent_test_map_.clear();
    207   user_data_dir_map_.clear();
    208 
    209   // Number of additional tests to run because of dependencies.
    210   size_t additional_tests_to_run_count = 0;
    211 
    212   // Compute dependencies of tests to be run.
    213   for (size_t i = 0; i < test_names.size(); i++) {
    214     std::string full_name(test_names[i]);
    215     std::string pre_test_name(GetPreTestName(full_name));
    216 
    217     while (ContainsKey(all_test_names_, pre_test_name)) {
    218       additional_tests_to_run_count++;
    219 
    220       DCHECK(!ContainsKey(dependent_test_map_, pre_test_name));
    221       dependent_test_map_[pre_test_name] = full_name;
    222 
    223       DCHECK(!ContainsKey(reverse_dependent_test_map_, full_name));
    224       reverse_dependent_test_map_[full_name] = pre_test_name;
    225 
    226       full_name = pre_test_name;
    227       pre_test_name = GetPreTestName(pre_test_name);
    228     }
    229   }
    230 
    231   for (size_t i = 0; i < test_names.size(); i++) {
    232     std::string full_name(test_names[i]);
    233 
    234     // Make sure no PRE_ tests were requested explicitly.
    235     DCHECK_EQ(full_name, RemoveAnyPrePrefixes(full_name));
    236 
    237     if (!ContainsKey(user_data_dir_map_, full_name)) {
    238       base::FilePath temp_dir;
    239       CHECK(base::CreateTemporaryDirInDir(temp_dir_.path(),
    240                                           FILE_PATH_LITERAL("d"), &temp_dir));
    241       user_data_dir_map_[full_name] = temp_dir;
    242     }
    243 
    244     // If the test has any dependencies, get to the root and start with that.
    245     while (ContainsKey(reverse_dependent_test_map_, full_name))
    246       full_name = GetPreTestName(full_name);
    247 
    248     DoRunTest(test_launcher, full_name);
    249   }
    250 
    251   return test_names.size() + additional_tests_to_run_count;
    252 }
    253 
    254 size_t WrapperTestLauncherDelegate::RetryTests(
    255     base::TestLauncher* test_launcher,
    256     const std::vector<std::string>& test_names) {
    257   // List of tests we can kick off right now, depending on no other tests.
    258   std::vector<std::string> tests_to_run_now;
    259 
    260   // We retry at least the tests requested to retry.
    261   std::set<std::string> test_names_set(test_names.begin(), test_names.end());
    262 
    263   // In the face of PRE_ tests, we need to retry the entire chain of tests,
    264   // from the very first one.
    265   for (size_t i = 0; i < test_names.size(); i++) {
    266     std::string test_name(test_names[i]);
    267     while (ContainsKey(reverse_dependent_test_map_, test_name)) {
    268       test_name = reverse_dependent_test_map_[test_name];
    269       test_names_set.insert(test_name);
    270     }
    271   }
    272 
    273   // Discard user data directories from any previous runs. Start with
    274   // fresh state.
    275   for (UserDataDirMap::const_iterator i = user_data_dir_map_.begin();
    276        i != user_data_dir_map_.end();
    277        ++i) {
    278     // Delete temporary directories now to avoid using too much space in /tmp.
    279     if (!base::DeleteFile(i->second, true)) {
    280       LOG(WARNING) << "Failed to delete " << i->second.value();
    281     }
    282   }
    283   user_data_dir_map_.clear();
    284 
    285   for (std::set<std::string>::const_iterator i = test_names_set.begin();
    286        i != test_names_set.end();
    287        ++i) {
    288     std::string full_name(*i);
    289 
    290     // Make sure PRE_ tests and tests that depend on them share the same
    291     // data directory - based it on the test name without prefixes.
    292     std::string test_name_no_pre(RemoveAnyPrePrefixes(full_name));
    293     if (!ContainsKey(user_data_dir_map_, test_name_no_pre)) {
    294       base::FilePath temp_dir;
    295       CHECK(base::CreateTemporaryDirInDir(temp_dir_.path(),
    296                                           FILE_PATH_LITERAL("d"), &temp_dir));
    297       user_data_dir_map_[test_name_no_pre] = temp_dir;
    298     }
    299 
    300     size_t dot_pos = full_name.find('.');
    301     CHECK_NE(dot_pos, std::string::npos);
    302     std::string test_case_name = full_name.substr(0, dot_pos);
    303     std::string test_name = full_name.substr(dot_pos + 1);
    304     std::string pre_test_name(
    305         test_case_name + "." + kPreTestPrefix + test_name);
    306     if (!ContainsKey(test_names_set, pre_test_name))
    307       tests_to_run_now.push_back(full_name);
    308   }
    309 
    310   for (size_t i = 0; i < tests_to_run_now.size(); i++)
    311     DoRunTest(test_launcher, tests_to_run_now[i]);
    312 
    313   return test_names_set.size();
    314 }
    315 
    316 void WrapperTestLauncherDelegate::DoRunTest(base::TestLauncher* test_launcher,
    317                                             const std::string& test_name) {
    318   std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
    319 
    320   CommandLine cmd_line(*CommandLine::ForCurrentProcess());
    321   CHECK(launcher_delegate_->AdjustChildProcessCommandLine(
    322             &cmd_line, user_data_dir_map_[test_name_no_pre]));
    323 
    324   CommandLine new_cmd_line(cmd_line.GetProgram());
    325   CommandLine::SwitchMap switches = cmd_line.GetSwitches();
    326 
    327   // Strip out gtest_output flag because otherwise we would overwrite results
    328   // of the other tests.
    329   switches.erase(base::kGTestOutputFlag);
    330 
    331   for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
    332        iter != switches.end(); ++iter) {
    333     new_cmd_line.AppendSwitchNative(iter->first, iter->second);
    334   }
    335 
    336   // Always enable disabled tests.  This method is not called with disabled
    337   // tests unless this flag was specified to the browser test executable.
    338   new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests");
    339   new_cmd_line.AppendSwitchASCII("gtest_filter", test_name);
    340   new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
    341 
    342   char* browser_wrapper = getenv("BROWSER_WRAPPER");
    343 
    344   test_launcher->LaunchChildGTestProcess(
    345       new_cmd_line,
    346       browser_wrapper ? browser_wrapper : std::string(),
    347       TestTimeouts::action_max_timeout(),
    348       base::TestLauncher::USE_JOB_OBJECTS |
    349           base::TestLauncher::ALLOW_BREAKAWAY_FROM_JOB,
    350       base::Bind(&WrapperTestLauncherDelegate::GTestCallback,
    351                  base::Unretained(this),
    352                  test_launcher,
    353                  test_name));
    354 }
    355 
    356 void WrapperTestLauncherDelegate::RunDependentTest(
    357     base::TestLauncher* test_launcher,
    358     const std::string test_name,
    359     const base::TestResult& pre_test_result) {
    360   if (pre_test_result.status == base::TestResult::TEST_SUCCESS) {
    361     // Only run the dependent test if PRE_ test succeeded.
    362     DoRunTest(test_launcher, test_name);
    363   } else {
    364     // Otherwise skip the test.
    365     base::TestResult test_result;
    366     test_result.full_name = test_name;
    367     test_result.status = base::TestResult::TEST_SKIPPED;
    368     test_launcher->OnTestFinished(test_result);
    369 
    370     if (ContainsKey(dependent_test_map_, test_name)) {
    371       RunDependentTest(test_launcher,
    372                        dependent_test_map_[test_name],
    373                        test_result);
    374     }
    375   }
    376 }
    377 
    378 void WrapperTestLauncherDelegate::GTestCallback(
    379     base::TestLauncher* test_launcher,
    380     const std::string& test_name,
    381     int exit_code,
    382     const base::TimeDelta& elapsed_time,
    383     bool was_timeout,
    384     const std::string& output) {
    385   base::TestResult result;
    386   result.full_name = test_name;
    387 
    388   // TODO(phajdan.jr): Recognize crashes.
    389   if (exit_code == 0)
    390     result.status = base::TestResult::TEST_SUCCESS;
    391   else if (was_timeout)
    392     result.status = base::TestResult::TEST_TIMEOUT;
    393   else
    394     result.status = base::TestResult::TEST_FAILURE;
    395 
    396   result.elapsed_time = elapsed_time;
    397 
    398   result.output_snippet = GetTestOutputSnippet(result, output);
    399 
    400   if (ContainsKey(dependent_test_map_, test_name)) {
    401     RunDependentTest(test_launcher, dependent_test_map_[test_name], result);
    402   } else {
    403     // No other tests depend on this, we can delete the temporary directory now.
    404     // Do so to avoid too many temporary files using lots of disk space.
    405     std::string test_name_no_pre(RemoveAnyPrePrefixes(test_name));
    406     if (ContainsKey(user_data_dir_map_, test_name_no_pre)) {
    407       if (!base::DeleteFile(user_data_dir_map_[test_name_no_pre], true)) {
    408         LOG(WARNING) << "Failed to delete "
    409                      << user_data_dir_map_[test_name_no_pre].value();
    410       }
    411       user_data_dir_map_.erase(test_name_no_pre);
    412     }
    413   }
    414 
    415   test_launcher->OnTestFinished(result);
    416 }
    417 
    418 }  // namespace
    419 
    420 const char kHelpFlag[]   = "help";
    421 
    422 const char kLaunchAsBrowser[] = "as-browser";
    423 
    424 // See kManualTestPrefix above.
    425 const char kRunManualTestsFlag[] = "run-manual";
    426 
    427 const char kSingleProcessTestsFlag[]   = "single_process";
    428 
    429 
    430 TestLauncherDelegate::~TestLauncherDelegate() {
    431 }
    432 
    433 int LaunchTests(TestLauncherDelegate* launcher_delegate,
    434                 int default_jobs,
    435                 int argc,
    436                 char** argv) {
    437   DCHECK(!g_launcher_delegate);
    438   g_launcher_delegate = launcher_delegate;
    439 
    440   CommandLine::Init(argc, argv);
    441   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    442 
    443   if (command_line->HasSwitch(kHelpFlag)) {
    444     PrintUsage();
    445     return 0;
    446   }
    447 
    448   scoped_ptr<ContentMainDelegate> chrome_main_delegate(
    449       launcher_delegate->CreateContentMainDelegate());
    450   ContentMainParams params(chrome_main_delegate.get());
    451 
    452 #if defined(OS_WIN)
    453   sandbox::SandboxInterfaceInfo sandbox_info = {0};
    454   InitializeSandboxInfo(&sandbox_info);
    455 
    456   params.instance = GetModuleHandle(NULL);
    457   params.sandbox_info = &sandbox_info;
    458 #elif !defined(OS_ANDROID)
    459   params.argc = argc;
    460   params.argv = const_cast<const char**>(argv);
    461 #endif  // defined(OS_WIN)
    462 
    463   if (command_line->HasSwitch(kSingleProcessTestsFlag) ||
    464       (command_line->HasSwitch(switches::kSingleProcess) &&
    465        command_line->HasSwitch(base::kGTestFilterFlag)) ||
    466       command_line->HasSwitch(base::kGTestListTestsFlag) ||
    467       command_line->HasSwitch(base::kGTestHelpFlag)) {
    468     g_params = &params;
    469     return launcher_delegate->RunTestSuite(argc, argv);
    470   }
    471 
    472 #if !defined(OS_ANDROID)
    473   if (command_line->HasSwitch(switches::kProcessType) ||
    474       command_line->HasSwitch(kLaunchAsBrowser)) {
    475     return ContentMain(params);
    476   }
    477 #endif
    478 
    479   base::AtExitManager at_exit;
    480   testing::InitGoogleTest(&argc, argv);
    481   TestTimeouts::Initialize();
    482 
    483   fprintf(stdout,
    484       "IMPORTANT DEBUGGING NOTE: each test is run inside its own process.\n"
    485       "For debugging a test inside a debugger, use the\n"
    486       "--gtest_filter=<your_test_name> flag along with either\n"
    487       "--single_process (to run the test in one launcher/browser process) or\n"
    488       "--single-process (to do the above, and also run Chrome in single-"
    489           "process mode).\n");
    490 
    491   base::MessageLoopForIO message_loop;
    492 
    493   // Allow the |launcher_delegate| to modify |default_jobs|.
    494   launcher_delegate->AdjustDefaultParallelJobs(&default_jobs);
    495 
    496   WrapperTestLauncherDelegate delegate(launcher_delegate);
    497   base::TestLauncher launcher(&delegate, default_jobs);
    498   return (launcher.Run() ? 0 : 1);
    499 }
    500 
    501 TestLauncherDelegate* GetCurrentTestLauncherDelegate() {
    502   return g_launcher_delegate;
    503 }
    504 
    505 ContentMainParams* GetContentMainParams() {
    506   return g_params;
    507 }
    508 
    509 }  // namespace content
    510