test_launcher.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 <string> 8#include <vector> 9 10#include "base/command_line.h" 11#include "base/containers/hash_tables.h" 12#include "base/environment.h" 13#include "base/file_util.h" 14#include "base/files/scoped_temp_dir.h" 15#include "base/logging.h" 16#include "base/memory/linked_ptr.h" 17#include "base/memory/scoped_ptr.h" 18#include "base/process_util.h" 19#include "base/strings/string_number_conversions.h" 20#include "base/strings/string_util.h" 21#include "base/strings/utf_string_conversions.h" 22#include "base/test/test_launcher.h" 23#include "base/test/test_suite.h" 24#include "base/test/test_timeouts.h" 25#include "base/time/time.h" 26#include "content/public/app/content_main.h" 27#include "content/public/app/content_main_delegate.h" 28#include "content/public/app/startup_helper_win.h" 29#include "content/public/common/content_switches.h" 30#include "content/public/common/sandbox_init.h" 31#include "content/public/test/browser_test.h" 32#include "net/base/escape.h" 33#include "testing/gtest/include/gtest/gtest.h" 34 35#if defined(OS_WIN) 36#include "base/base_switches.h" 37#include "content/common/sandbox_win.h" 38#include "sandbox/win/src/sandbox_factory.h" 39#include "sandbox/win/src/sandbox_types.h" 40#elif defined(OS_MACOSX) 41#include "base/mac/scoped_nsautorelease_pool.h" 42#endif 43 44namespace content { 45 46namespace { 47 48// Tests with this prefix run before the same test without it, and use the same 49// profile. i.e. Foo.PRE_Test runs and then Foo.Test. This allows writing tests 50// that span browser restarts. 51const char kPreTestPrefix[] = "PRE_"; 52 53// Manual tests only run when --run-manual is specified. This allows writing 54// tests that don't run automatically but are still in the same test binary. 55// This is useful so that a team that wants to run a few tests doesn't have to 56// add a new binary that must be compiled on all builds. 57const char kManualTestPrefix[] = "MANUAL_"; 58 59TestLauncherDelegate* g_launcher_delegate; 60} 61 62namespace { 63 64int DoRunTestInternal(const testing::TestCase* test_case, 65 const std::string& test_name, 66 const CommandLine& command_line, 67 base::TimeDelta default_timeout, 68 bool* was_timeout) { 69 if (test_case) { 70 std::string pre_test_name = test_name; 71 std::string replace_string = std::string(".") + kPreTestPrefix; 72 ReplaceFirstSubstringAfterOffset(&pre_test_name, 0, ".", replace_string); 73 for (int i = 0; i < test_case->total_test_count(); ++i) { 74 const testing::TestInfo* test_info = test_case->GetTestInfo(i); 75 std::string cur_test_name = test_info->test_case_name(); 76 cur_test_name.append("."); 77 cur_test_name.append(test_info->name()); 78 if (cur_test_name == pre_test_name) { 79 int exit_code = DoRunTestInternal(test_case, 80 pre_test_name, 81 command_line, 82 default_timeout, 83 was_timeout); 84 if (exit_code != 0) 85 return exit_code; 86 } 87 } 88 } 89 90 CommandLine new_cmd_line(command_line); 91 92 // Always enable disabled tests. This method is not called with disabled 93 // tests unless this flag was specified to the browser test executable. 94 new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests"); 95 new_cmd_line.AppendSwitchASCII("gtest_filter", test_name); 96 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag); 97 98 char* browser_wrapper = getenv("BROWSER_WRAPPER"); 99 int exit_code = base::LaunchChildGTestProcess( 100 new_cmd_line, 101 browser_wrapper ? browser_wrapper : std::string(), 102 default_timeout, 103 was_timeout); 104 if (*was_timeout) { 105 LOG(ERROR) << "Test timeout (" << default_timeout.InMilliseconds() 106 << " ms) exceeded for " << test_name; 107 } 108 109 return exit_code; 110} 111 112// Runs test specified by |test_name| in a child process, 113// and returns the exit code. 114int DoRunTest(TestLauncherDelegate* launcher_delegate, 115 const testing::TestCase* test_case, 116 const std::string& test_name, 117 base::TimeDelta default_timeout, 118 bool* was_timeout) { 119 if (was_timeout) 120 *was_timeout = false; 121 122#if defined(OS_MACOSX) 123 // Some of the below method calls will leak objects if there is no 124 // autorelease pool in place. 125 base::mac::ScopedNSAutoreleasePool pool; 126#endif 127 128 base::ScopedTempDir temp_dir; 129 // Create a new data dir and pass it to the child. 130 if (!temp_dir.CreateUniqueTempDir() || !temp_dir.IsValid()) { 131 LOG(ERROR) << "Error creating temp data directory"; 132 return -1; 133 } 134 135 CommandLine new_cmd_line(*CommandLine::ForCurrentProcess()); 136 if (!launcher_delegate->AdjustChildProcessCommandLine(&new_cmd_line, 137 temp_dir.path())) { 138 return -1; 139 } 140 141 return DoRunTestInternal( 142 test_case, test_name, new_cmd_line, default_timeout, was_timeout); 143} 144 145void PrintUsage() { 146 fprintf(stdout, 147 "Runs tests using the gtest framework, each test being run in its own\n" 148 "process. Any gtest flags can be specified.\n" 149 " --single_process\n" 150 " Runs the tests and the launcher in the same process. Useful for \n" 151 " debugging a specific test in a debugger.\n" 152 " --single-process\n" 153 " Same as above, and also runs Chrome in single-process mode.\n" 154 " --help\n" 155 " Shows this message.\n" 156 " --gtest_help\n" 157 " Shows the gtest help message.\n"); 158} 159 160// Implementation of base::TestLauncherDelegate. This is also a test launcher, 161// wrapping a lower-level test launcher with content-specific code. 162class WrapperTestLauncherDelegate : public base::TestLauncherDelegate { 163 public: 164 explicit WrapperTestLauncherDelegate( 165 content::TestLauncherDelegate* launcher_delegate) 166 : launcher_delegate_(launcher_delegate), 167 timeout_count_(0), 168 printed_timeout_message_(false) { 169 } 170 171 // base::TestLauncherDelegate: 172 virtual bool ShouldRunTest(const testing::TestCase* test_case, 173 const testing::TestInfo* test_info) OVERRIDE; 174 virtual void RunTest( 175 const testing::TestCase* test_case, 176 const testing::TestInfo* test_info, 177 const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE; 178 virtual void RunRemainingTests() OVERRIDE; 179 180 private: 181 content::TestLauncherDelegate* launcher_delegate_; 182 183 // Number of times a test timeout occurred. 184 size_t timeout_count_; 185 186 // True after a message about too many timeouts has been printed, 187 // to avoid doing it more than once. 188 bool printed_timeout_message_; 189 190 DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate); 191}; 192 193bool WrapperTestLauncherDelegate::ShouldRunTest( 194 const testing::TestCase* test_case, 195 const testing::TestInfo* test_info) { 196 std::string test_name = 197 std::string(test_case->name()) + "." + test_info->name(); 198 199 if (StartsWithASCII(test_info->name(), kPreTestPrefix, true)) 200 return false; 201 202 if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) && 203 !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) { 204 return false; 205 } 206 207 // Stop test execution after too many timeouts. 208 if (timeout_count_ > 5) { 209 if (!printed_timeout_message_) { 210 printed_timeout_message_ = true; 211 printf("Too many timeouts, aborting test\n"); 212 } 213 return false; 214 } 215 216 return true; 217} 218 219void WrapperTestLauncherDelegate::RunTest( 220 const testing::TestCase* test_case, 221 const testing::TestInfo* test_info, 222 const base::TestLauncherDelegate::TestResultCallback& callback) { 223 base::TimeTicks start_time = base::TimeTicks::Now(); 224 bool was_timeout = false; 225 std::string test_name = 226 std::string(test_case->name()) + "." + test_info->name(); 227 int exit_code = DoRunTest(launcher_delegate_, 228 test_case, 229 test_name, 230 TestTimeouts::action_max_timeout(), 231 &was_timeout); 232 if (was_timeout) 233 timeout_count_++; 234 235 base::TestResult result; 236 result.test_case_name = test_case->name(); 237 result.test_name = test_info->name(); 238 result.success = (exit_code == 0); 239 result.elapsed_time = (base::TimeTicks::Now() - start_time); 240 241 callback.Run(result); 242} 243 244void WrapperTestLauncherDelegate::RunRemainingTests() { 245 // No need to do anything here, we launch tests synchronously. 246} 247 248} // namespace 249 250// The following is kept for historical reasons (so people that are used to 251// using it don't get surprised). 252const char kChildProcessFlag[] = "child"; 253 254const char kGTestHelpFlag[] = "gtest_help"; 255 256const char kHelpFlag[] = "help"; 257 258const char kLaunchAsBrowser[] = "as-browser"; 259 260// See kManualTestPrefix above. 261const char kRunManualTestsFlag[] = "run-manual"; 262 263const char kSingleProcessTestsFlag[] = "single_process"; 264 265 266TestLauncherDelegate::~TestLauncherDelegate() { 267} 268 269bool ShouldRunContentMain() { 270#if defined(OS_WIN) || defined(OS_LINUX) 271 CommandLine* command_line = CommandLine::ForCurrentProcess(); 272 return command_line->HasSwitch(switches::kProcessType) || 273 command_line->HasSwitch(kLaunchAsBrowser); 274#else 275 return false; 276#endif // defined(OS_WIN) || defined(OS_LINUX) 277} 278 279int RunContentMain(int argc, char** argv, 280 TestLauncherDelegate* launcher_delegate) { 281#if defined(OS_WIN) 282 sandbox::SandboxInterfaceInfo sandbox_info = {0}; 283 InitializeSandboxInfo(&sandbox_info); 284 scoped_ptr<ContentMainDelegate> chrome_main_delegate( 285 launcher_delegate->CreateContentMainDelegate()); 286 return ContentMain(GetModuleHandle(NULL), 287 &sandbox_info, 288 chrome_main_delegate.get()); 289#elif defined(OS_LINUX) 290 scoped_ptr<ContentMainDelegate> chrome_main_delegate( 291 launcher_delegate->CreateContentMainDelegate()); 292 return ContentMain(argc, const_cast<const char**>(argv), 293 chrome_main_delegate.get()); 294#endif // defined(OS_WIN) 295 NOTREACHED(); 296 return 0; 297} 298 299int LaunchTests(TestLauncherDelegate* launcher_delegate, 300 int argc, 301 char** argv) { 302 DCHECK(!g_launcher_delegate); 303 g_launcher_delegate = launcher_delegate; 304 305 CommandLine::Init(argc, argv); 306 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 307 308 if (command_line->HasSwitch(kHelpFlag)) { 309 PrintUsage(); 310 return 0; 311 } 312 313 if (command_line->HasSwitch(kSingleProcessTestsFlag) || 314 (command_line->HasSwitch(switches::kSingleProcess) && 315 command_line->HasSwitch(base::kGTestFilterFlag)) || 316 command_line->HasSwitch(base::kGTestListTestsFlag) || 317 command_line->HasSwitch(kGTestHelpFlag)) { 318#if defined(OS_WIN) 319 if (command_line->HasSwitch(kSingleProcessTestsFlag)) { 320 sandbox::SandboxInterfaceInfo sandbox_info; 321 InitializeSandboxInfo(&sandbox_info); 322 InitializeSandbox(&sandbox_info); 323 } 324#endif 325 return launcher_delegate->RunTestSuite(argc, argv); 326 } 327 328 if (ShouldRunContentMain()) 329 return RunContentMain(argc, argv, launcher_delegate); 330 331 fprintf(stdout, 332 "Starting tests...\n" 333 "IMPORTANT DEBUGGING NOTE: each test is run inside its own process.\n" 334 "For debugging a test inside a debugger, use the\n" 335 "--gtest_filter=<your_test_name> flag along with either\n" 336 "--single_process (to run the test in one launcher/browser process) or\n" 337 "--single-process (to do the above, and also run Chrome in single-" 338 "process mode).\n"); 339 340 base::AtExitManager at_exit; 341 testing::InitGoogleTest(&argc, argv); 342 TestTimeouts::Initialize(); 343 344 WrapperTestLauncherDelegate delegate(launcher_delegate); 345 return base::LaunchTests(&delegate, argc, argv); 346} 347 348TestLauncherDelegate* GetCurrentTestLauncherDelegate() { 349 return g_launcher_delegate; 350} 351 352} // namespace content 353