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