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/i18n/icu_util.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/sys_info.h" 14 #include "base/test/test_timeouts.h" 15 #include "content/public/app/content_main.h" 16 #include "content/browser/renderer_host/render_process_host_impl.h" 17 #include "content/browser/tracing/tracing_controller_impl.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/common/content_switches.h" 20 #include "content/public/common/main_function_params.h" 21 #include "content/public/test/test_launcher.h" 22 #include "content/public/test/test_utils.h" 23 #include "net/base/net_errors.h" 24 #include "net/dns/mock_host_resolver.h" 25 #include "net/test/embedded_test_server/embedded_test_server.h" 26 #include "ui/compositor/compositor_switches.h" 27 #include "ui/gl/gl_implementation.h" 28 #include "ui/gl/gl_switches.h" 29 30 #if defined(OS_POSIX) 31 #include "base/process/process_handle.h" 32 #endif 33 34 #if defined(OS_MACOSX) 35 #include "base/mac/mac_util.h" 36 #endif 37 38 #if defined(OS_ANDROID) 39 #include "base/threading/thread_restrictions.h" 40 #include "content/public/browser/browser_main_runner.h" 41 #include "content/public/browser/browser_thread.h" 42 #endif 43 44 #if defined(USE_AURA) 45 #include "content/browser/compositor/image_transport_factory.h" 46 #include "ui/aura/test/event_generator_delegate_aura.h" 47 #if defined(USE_X11) 48 #include "ui/aura/window_tree_host_x11.h" 49 #endif 50 #endif 51 52 namespace content { 53 namespace { 54 55 #if defined(OS_POSIX) 56 // On SIGTERM (sent by the runner on timeouts), dump a stack trace (to make 57 // debugging easier) and also exit with a known error code (so that the test 58 // framework considers this a failure -- http://crbug.com/57578). 59 // Note: We only want to do this in the browser process, and not forked 60 // processes. That might lead to hangs because of locks inside tcmalloc or the 61 // OS. See http://crbug.com/141302. 62 static int g_browser_process_pid; 63 static void DumpStackTraceSignalHandler(int signal) { 64 if (g_browser_process_pid == base::GetCurrentProcId()) { 65 logging::RawLog(logging::LOG_ERROR, 66 "BrowserTestBase signal handler received SIGTERM. " 67 "Backtrace:\n"); 68 base::debug::StackTrace().Print(); 69 } 70 _exit(128 + signal); 71 } 72 #endif // defined(OS_POSIX) 73 74 void RunTaskOnRendererThread(const base::Closure& task, 75 const base::Closure& quit_task) { 76 task.Run(); 77 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task); 78 } 79 80 // In many cases it may be not obvious that a test makes a real DNS lookup. 81 // We generally don't want to rely on external DNS servers for our tests, 82 // so this host resolver procedure catches external queries and returns a failed 83 // lookup result. 84 class LocalHostResolverProc : public net::HostResolverProc { 85 public: 86 LocalHostResolverProc() : HostResolverProc(NULL) {} 87 88 virtual int Resolve(const std::string& host, 89 net::AddressFamily address_family, 90 net::HostResolverFlags host_resolver_flags, 91 net::AddressList* addrlist, 92 int* os_error) OVERRIDE { 93 const char* kLocalHostNames[] = {"localhost", "127.0.0.1", "::1"}; 94 bool local = false; 95 96 if (host == net::GetHostName()) { 97 local = true; 98 } else { 99 for (size_t i = 0; i < arraysize(kLocalHostNames); i++) 100 if (host == kLocalHostNames[i]) { 101 local = true; 102 break; 103 } 104 } 105 106 // To avoid depending on external resources and to reduce (if not preclude) 107 // network interactions from tests, we simulate failure for non-local DNS 108 // queries, rather than perform them. 109 // If you really need to make an external DNS query, use 110 // net::RuleBasedHostResolverProc and its AllowDirectLookup method. 111 if (!local) { 112 DVLOG(1) << "To avoid external dependencies, simulating failure for " 113 "external DNS lookup of " << host; 114 return net::ERR_NOT_IMPLEMENTED; 115 } 116 117 return ResolveUsingPrevious(host, address_family, host_resolver_flags, 118 addrlist, os_error); 119 } 120 121 private: 122 virtual ~LocalHostResolverProc() {} 123 }; 124 125 void TraceDisableRecordingComplete(const base::Closure& quit, 126 const base::FilePath& file_path) { 127 LOG(ERROR) << "Tracing written to: " << file_path.value(); 128 quit.Run(); 129 } 130 131 } // namespace 132 133 extern int BrowserMain(const MainFunctionParams&); 134 135 BrowserTestBase::BrowserTestBase() 136 : expected_exit_code_(0), 137 enable_pixel_output_(false), 138 use_software_compositing_(false) { 139 #if defined(OS_MACOSX) 140 base::mac::SetOverrideAmIBundled(true); 141 #endif 142 143 #if defined(USE_AURA) 144 #if defined(USE_X11) 145 aura::test::SetUseOverrideRedirectWindowByDefault(true); 146 #endif 147 aura::test::InitializeAuraEventGeneratorDelegate(); 148 #endif 149 150 #if defined(OS_POSIX) 151 handle_sigterm_ = true; 152 #endif 153 154 // This is called through base::TestSuite initially. It'll also be called 155 // inside BrowserMain, so tell the code to ignore the check that it's being 156 // called more than once 157 base::i18n::AllowMultipleInitializeCallsForTesting(); 158 159 embedded_test_server_.reset(new net::test_server::EmbeddedTestServer); 160 } 161 162 BrowserTestBase::~BrowserTestBase() { 163 #if defined(OS_ANDROID) 164 // RemoteTestServer can cause wait on the UI thread. 165 base::ThreadRestrictions::ScopedAllowWait allow_wait; 166 test_server_.reset(NULL); 167 #endif 168 } 169 170 void BrowserTestBase::SetUp() { 171 CommandLine* command_line = CommandLine::ForCurrentProcess(); 172 173 // Override the child process connection timeout since tests can exceed that 174 // when sharded. 175 command_line->AppendSwitchASCII( 176 switches::kIPCConnectionTimeout, 177 base::IntToString(TestTimeouts::action_max_timeout().InSeconds())); 178 179 // The tests assume that file:// URIs can freely access other file:// URIs. 180 command_line->AppendSwitch(switches::kAllowFileAccessFromFiles); 181 182 command_line->AppendSwitch(switches::kDomAutomationController); 183 184 // It is sometimes useful when looking at browser test failures to know which 185 // GPU blacklisting decisions were made. 186 command_line->AppendSwitch(switches::kLogGpuControlListDecisions); 187 188 if (use_software_compositing_) { 189 command_line->AppendSwitch(switches::kDisableGpu); 190 #if defined(USE_AURA) 191 command_line->AppendSwitch(switches::kUIDisableThreadedCompositing); 192 #endif 193 } 194 195 #if defined(USE_AURA) 196 // Most tests do not need pixel output, so we don't produce any. The command 197 // line can override this behaviour to allow for visual debugging. 198 if (command_line->HasSwitch(switches::kEnablePixelOutputInTests)) 199 enable_pixel_output_ = true; 200 201 if (command_line->HasSwitch(switches::kDisableGLDrawingForTests)) { 202 NOTREACHED() << "kDisableGLDrawingForTests should not be used as it" 203 "is chosen by tests. Use kEnablePixelOutputInTests " 204 "to enable pixel output."; 205 } 206 207 // Don't enable pixel output for browser tests unless they override and force 208 // us to, or it's requested on the command line. 209 if (!enable_pixel_output_ && !use_software_compositing_) 210 command_line->AppendSwitch(switches::kDisableGLDrawingForTests); 211 #endif 212 213 bool use_osmesa = true; 214 215 // We usually use OSMesa as this works on all bots. The command line can 216 // override this behaviour to use hardware GL. 217 if (command_line->HasSwitch(switches::kUseGpuInTests)) 218 use_osmesa = false; 219 220 // Some bots pass this flag when they want to use hardware GL. 221 if (command_line->HasSwitch("enable-gpu")) 222 use_osmesa = false; 223 224 #if defined(OS_MACOSX) 225 // On Mac we always use hardware GL. 226 use_osmesa = false; 227 #endif 228 229 #if defined(OS_ANDROID) 230 // On Android we always use hardware GL. 231 use_osmesa = false; 232 #endif 233 234 #if defined(OS_CHROMEOS) 235 // If the test is running on the chromeos envrionment (such as 236 // device or vm bots), we use hardware GL. 237 if (base::SysInfo::IsRunningOnChromeOS()) 238 use_osmesa = false; 239 #endif 240 241 if (use_osmesa && !use_software_compositing_) 242 command_line->AppendSwitch(switches::kOverrideUseGLWithOSMesaForTests); 243 244 scoped_refptr<net::HostResolverProc> local_resolver = 245 new LocalHostResolverProc(); 246 rule_based_resolver_ = 247 new net::RuleBasedHostResolverProc(local_resolver.get()); 248 rule_based_resolver_->AddSimulatedFailure("wpad"); 249 net::ScopedDefaultHostResolverProc scoped_local_host_resolver_proc( 250 rule_based_resolver_.get()); 251 SetUpInProcessBrowserTestFixture(); 252 253 base::Closure* ui_task = 254 new base::Closure( 255 base::Bind(&BrowserTestBase::ProxyRunTestOnMainThreadLoop, this)); 256 257 #if defined(OS_ANDROID) 258 MainFunctionParams params(*command_line); 259 params.ui_task = ui_task; 260 // TODO(phajdan.jr): Check return code, http://crbug.com/374738 . 261 BrowserMain(params); 262 #else 263 GetContentMainParams()->ui_task = ui_task; 264 EXPECT_EQ(expected_exit_code_, ContentMain(*GetContentMainParams())); 265 #endif 266 TearDownInProcessBrowserTestFixture(); 267 } 268 269 void BrowserTestBase::TearDown() { 270 } 271 272 void BrowserTestBase::ProxyRunTestOnMainThreadLoop() { 273 #if defined(OS_POSIX) 274 if (handle_sigterm_) { 275 g_browser_process_pid = base::GetCurrentProcId(); 276 signal(SIGTERM, DumpStackTraceSignalHandler); 277 } 278 #endif // defined(OS_POSIX) 279 280 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableTracing)) { 281 base::debug::CategoryFilter category_filter( 282 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 283 switches::kEnableTracing)); 284 TracingController::GetInstance()->EnableRecording( 285 category_filter, 286 base::debug::TraceOptions(base::debug::RECORD_CONTINUOUSLY), 287 TracingController::EnableRecordingDoneCallback()); 288 } 289 290 RunTestOnMainThreadLoop(); 291 292 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableTracing)) { 293 base::FilePath trace_file = 294 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 295 switches::kEnableTracingOutput); 296 // If there was no file specified, put a hardcoded one in the current 297 // working directory. 298 if (trace_file.empty()) 299 trace_file = base::FilePath().AppendASCII("trace.json"); 300 301 // Wait for tracing to collect results from the renderers. 302 base::RunLoop run_loop; 303 TracingController::GetInstance()->DisableRecording( 304 TracingControllerImpl::CreateFileSink( 305 trace_file, 306 base::Bind(&TraceDisableRecordingComplete, 307 run_loop.QuitClosure(), 308 trace_file))); 309 run_loop.Run(); 310 } 311 } 312 313 void BrowserTestBase::CreateTestServer(const base::FilePath& test_server_base) { 314 CHECK(!test_server_.get()); 315 test_server_.reset(new net::SpawnedTestServer( 316 net::SpawnedTestServer::TYPE_HTTP, 317 net::SpawnedTestServer::kLocalhost, 318 test_server_base)); 319 } 320 321 void BrowserTestBase::PostTaskToInProcessRendererAndWait( 322 const base::Closure& task) { 323 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)); 324 325 scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner; 326 327 base::MessageLoop* renderer_loop = 328 RenderProcessHostImpl::GetInProcessRendererThreadForTesting(); 329 CHECK(renderer_loop); 330 331 renderer_loop->PostTask( 332 FROM_HERE, 333 base::Bind(&RunTaskOnRendererThread, task, runner->QuitClosure())); 334 runner->Run(); 335 } 336 337 void BrowserTestBase::EnablePixelOutput() { enable_pixel_output_ = true; } 338 339 void BrowserTestBase::UseSoftwareCompositing() { 340 use_software_compositing_ = true; 341 } 342 343 bool BrowserTestBase::UsingOSMesa() const { 344 CommandLine* cmd = CommandLine::ForCurrentProcess(); 345 return cmd->GetSwitchValueASCII(switches::kUseGL) == 346 gfx::kGLImplementationOSMesaName; 347 } 348 349 } // namespace content 350