browser_test_base.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright (c) 2011 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/browser_test_base.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/debug/stack_trace.h"
10#include "base/message_loop/message_loop.h"
11#include "content/browser/renderer_host/render_process_host_impl.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/common/content_switches.h"
14#include "content/public/common/main_function_params.h"
15#include "content/public/test/test_utils.h"
16#include "net/base/net_errors.h"
17#include "net/dns/mock_host_resolver.h"
18#include "net/test/embedded_test_server/embedded_test_server.h"
19#include "ui/compositor/compositor_switches.h"
20#include "ui/gl/gl_implementation.h"
21#include "ui/gl/gl_switches.h"
22
23#if defined(OS_POSIX)
24#include "base/process/process_handle.h"
25#endif
26
27#if defined(OS_MACOSX)
28#include "base/mac/mac_util.h"
29#include "base/power_monitor/power_monitor_device_source.h"
30#endif
31
32#if defined(OS_ANDROID)
33#include "base/threading/thread_restrictions.h"
34#include "content/public/browser/browser_main_runner.h"
35#include "content/public/browser/browser_thread.h"
36#endif
37
38#if defined(OS_CHROMEOS)
39#include "base/chromeos/chromeos_version.h"
40#endif
41
42namespace content {
43namespace {
44
45#if defined(OS_POSIX)
46// On SIGTERM (sent by the runner on timeouts), dump a stack trace (to make
47// debugging easier) and also exit with a known error code (so that the test
48// framework considers this a failure -- http://crbug.com/57578).
49// Note: We only want to do this in the browser process, and not forked
50// processes. That might lead to hangs because of locks inside tcmalloc or the
51// OS. See http://crbug.com/141302.
52static int g_browser_process_pid;
53static void DumpStackTraceSignalHandler(int signal) {
54  if (g_browser_process_pid == base::GetCurrentProcId()) {
55    logging::RawLog(logging::LOG_ERROR,
56                    "BrowserTestBase signal handler received SIGTERM. "
57                    "Backtrace:\n");
58    base::debug::StackTrace().Print();
59  }
60  _exit(128 + signal);
61}
62#endif  // defined(OS_POSIX)
63
64void RunTaskOnRendererThread(const base::Closure& task,
65                             const base::Closure& quit_task) {
66  task.Run();
67  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
68}
69
70// In many cases it may be not obvious that a test makes a real DNS lookup.
71// We generally don't want to rely on external DNS servers for our tests,
72// so this host resolver procedure catches external queries and returns a failed
73// lookup result.
74class LocalHostResolverProc : public net::HostResolverProc {
75 public:
76  LocalHostResolverProc() : HostResolverProc(NULL) {}
77
78  virtual int Resolve(const std::string& host,
79                      net::AddressFamily address_family,
80                      net::HostResolverFlags host_resolver_flags,
81                      net::AddressList* addrlist,
82                      int* os_error) OVERRIDE {
83    const char* kLocalHostNames[] = {"localhost", "127.0.0.1", "::1"};
84    bool local = false;
85
86    if (host == net::GetHostName()) {
87      local = true;
88    } else {
89      for (size_t i = 0; i < arraysize(kLocalHostNames); i++)
90        if (host == kLocalHostNames[i]) {
91          local = true;
92          break;
93        }
94    }
95
96    // To avoid depending on external resources and to reduce (if not preclude)
97    // network interactions from tests, we simulate failure for non-local DNS
98    // queries, rather than perform them.
99    // If you really need to make an external DNS query, use
100    // net::RuleBasedHostResolverProc and its AllowDirectLookup method.
101    if (!local) {
102      DVLOG(1) << "To avoid external dependencies, simulating failure for "
103          "external DNS lookup of " << host;
104      return net::ERR_NOT_IMPLEMENTED;
105    }
106
107    return ResolveUsingPrevious(host, address_family, host_resolver_flags,
108                                addrlist, os_error);
109  }
110
111 private:
112  virtual ~LocalHostResolverProc() {}
113};
114
115}  // namespace
116
117extern int BrowserMain(const MainFunctionParams&);
118
119BrowserTestBase::BrowserTestBase()
120    : embedded_test_server_io_thread_("EmbeddedTestServer io thread"),
121      allow_test_contexts_(true),
122      allow_osmesa_(true) {
123#if defined(OS_MACOSX)
124  base::mac::SetOverrideAmIBundled(true);
125  base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
126#endif
127
128#if defined(OS_POSIX)
129  handle_sigterm_ = true;
130#endif
131
132  // Create a separate thread for the test server to run on. It's tempting to
133  // use actual browser threads, but that doesn't work for cases where the test
134  // server needs to be started before the browser, for example when the server
135  // URL should be passed in command-line parameters.
136  base::Thread::Options thread_options;
137  thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
138  CHECK(embedded_test_server_io_thread_.StartWithOptions(thread_options));
139  embedded_test_server_.reset(new net::test_server::EmbeddedTestServer(
140      embedded_test_server_io_thread_.message_loop_proxy()));
141}
142
143BrowserTestBase::~BrowserTestBase() {
144#if defined(OS_ANDROID)
145  // RemoteTestServer can cause wait on the UI thread.
146  base::ThreadRestrictions::ScopedAllowWait allow_wait;
147  test_server_.reset(NULL);
148#endif
149}
150
151void BrowserTestBase::SetUp() {
152  CommandLine* command_line = CommandLine::ForCurrentProcess();
153
154  // The tests assume that file:// URIs can freely access other file:// URIs.
155  command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
156
157  command_line->AppendSwitch(switches::kDomAutomationController);
158
159  command_line->AppendSwitch(switches::kSkipGpuDataLoading);
160
161#if defined(USE_AURA)
162  // Use test contexts for browser tests unless they override and force us to
163  // use a real context.
164  if (allow_test_contexts_)
165    command_line->AppendSwitch(switches::kTestCompositor);
166#endif
167
168  // When using real GL contexts, we usually use OSMesa as this works on all
169  // bots. The command line can override this behaviour to use a real GPU.
170  if (command_line->HasSwitch(switches::kUseGpuInTests))
171    allow_osmesa_ = false;
172
173  // Some bots pass this flag when they want to use a real GPU.
174  if (command_line->HasSwitch("enable-gpu"))
175    allow_osmesa_ = false;
176
177#if defined(OS_MACOSX)
178  // On Mac we always use a real GPU.
179  allow_osmesa_ = false;
180#endif
181
182#if defined(OS_ANDROID)
183  // On Android we always use a real GPU.
184  allow_osmesa_ = false;
185#endif
186
187#if defined(OS_CHROMEOS)
188  // If the test is running on the chromeos envrionment (such as
189  // device or vm bots), the compositor will use real GL contexts, and
190  // we should use real GL bindings with it.
191  if (base::chromeos::IsRunningOnChromeOS())
192    allow_osmesa_ = false;
193#endif
194
195  if (command_line->HasSwitch(switches::kUseGL)) {
196    NOTREACHED() <<
197        "kUseGL should not be used with tests. Try kUseGpuInTests instead.";
198  }
199
200  if (allow_osmesa_) {
201    command_line->AppendSwitchASCII(
202        switches::kUseGL, gfx::kGLImplementationOSMesaName);
203  }
204
205  scoped_refptr<net::HostResolverProc> local_resolver =
206      new LocalHostResolverProc();
207  rule_based_resolver_ =
208      new net::RuleBasedHostResolverProc(local_resolver.get());
209  rule_based_resolver_->AddSimulatedFailure("wpad");
210  net::ScopedDefaultHostResolverProc scoped_local_host_resolver_proc(
211      rule_based_resolver_.get());
212
213  SetUpInProcessBrowserTestFixture();
214
215  MainFunctionParams params(*command_line);
216  params.ui_task =
217      new base::Closure(
218          base::Bind(&BrowserTestBase::ProxyRunTestOnMainThreadLoop, this));
219
220#if defined(OS_ANDROID)
221  BrowserMainRunner::Create()->Initialize(params);
222  // We are done running the test by now. During teardown we
223  // need to be able to perform IO.
224  base::ThreadRestrictions::SetIOAllowed(true);
225  BrowserThread::PostTask(
226      BrowserThread::IO, FROM_HERE,
227      base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
228                 true));
229#else
230  BrowserMain(params);
231#endif
232  TearDownInProcessBrowserTestFixture();
233}
234
235void BrowserTestBase::TearDown() {
236}
237
238void BrowserTestBase::ProxyRunTestOnMainThreadLoop() {
239#if defined(OS_POSIX)
240  if (handle_sigterm_) {
241    g_browser_process_pid = base::GetCurrentProcId();
242    signal(SIGTERM, DumpStackTraceSignalHandler);
243  }
244#endif  // defined(OS_POSIX)
245  RunTestOnMainThreadLoop();
246}
247
248void BrowserTestBase::CreateTestServer(const base::FilePath& test_server_base) {
249  CHECK(!test_server_.get());
250  test_server_.reset(new net::SpawnedTestServer(
251      net::SpawnedTestServer::TYPE_HTTP,
252      net::SpawnedTestServer::kLocalhost,
253      test_server_base));
254}
255
256void BrowserTestBase::PostTaskToInProcessRendererAndWait(
257    const base::Closure& task) {
258  CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess));
259
260  scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
261
262  base::MessageLoop* renderer_loop =
263      RenderProcessHostImpl::GetInProcessRendererThreadForTesting();
264  CHECK(renderer_loop);
265
266  renderer_loop->PostTask(
267      FROM_HERE,
268      base::Bind(&RunTaskOnRendererThread, task, runner->QuitClosure()));
269  runner->Run();
270}
271
272}  // namespace content
273