Make audio thread hang checker less chatty.
[chromium-blink-merge.git] / chrome / test / base / in_process_browser_test.cc
blobcb63fb1464cc312a393a082090aa012a62868974
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.
5 #include "chrome/test/base/in_process_browser_test.h"
7 #include "base/auto_reset.h"
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/lazy_instance.h"
14 #include "base/location.h"
15 #include "base/path_service.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/test/test_file_util.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/threading/non_thread_safe.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/net/net_error_tab_helper.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_finder.h"
28 #include "chrome/browser/ui/browser_list.h"
29 #include "chrome/browser/ui/browser_list_observer.h"
30 #include "chrome/browser/ui/browser_navigator.h"
31 #include "chrome/browser/ui/browser_tabstrip.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "chrome/browser/ui/host_desktop.h"
34 #include "chrome/browser/ui/tabs/tab_strip_model.h"
35 #include "chrome/common/chrome_constants.h"
36 #include "chrome/common/chrome_paths.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/logging_chrome.h"
39 #include "chrome/common/url_constants.h"
40 #include "chrome/renderer/chrome_content_renderer_client.h"
41 #include "chrome/test/base/chrome_test_suite.h"
42 #include "chrome/test/base/test_launcher_utils.h"
43 #include "chrome/test/base/test_switches.h"
44 #include "chrome/test/base/testing_browser_process.h"
45 #include "components/google/core/browser/google_util.h"
46 #include "components/os_crypt/os_crypt.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/notification_types.h"
49 #include "content/public/test/browser_test_utils.h"
50 #include "content/public/test/test_launcher.h"
51 #include "content/public/test/test_navigation_observer.h"
52 #include "net/test/embedded_test_server/embedded_test_server.h"
53 #include "net/test/spawned_test_server/spawned_test_server.h"
55 #if defined(OS_MACOSX)
56 #include "base/mac/scoped_nsautorelease_pool.h"
57 #endif
59 #if defined(OS_WIN)
60 #include "base/win/scoped_com_initializer.h"
61 #include "base/win/windows_version.h"
62 #include "ui/base/win/atl_module.h"
63 #include "win8/test/metro_registration_helper.h"
64 #include "win8/test/test_registrar_constants.h"
65 #endif
67 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
68 #include "chrome/browser/captive_portal/captive_portal_service.h"
69 #endif
71 #if !defined(OS_ANDROID) && !defined(OS_IOS)
72 #include "components/storage_monitor/test_storage_monitor.h"
73 #endif
75 #if defined(OS_CHROMEOS)
76 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
77 #endif
79 namespace {
81 // Passed as value of kTestType.
82 const char kBrowserTestType[] = "browser";
84 // A BrowserListObserver that makes sure that all browsers created are on the
85 // |allowed_desktop_|.
86 class SingleDesktopTestObserver : public chrome::BrowserListObserver,
87 public base::NonThreadSafe {
88 public:
89 explicit SingleDesktopTestObserver(chrome::HostDesktopType allowed_desktop);
90 ~SingleDesktopTestObserver() override;
92 // chrome::BrowserListObserver:
93 void OnBrowserAdded(Browser* browser) override;
95 private:
96 chrome::HostDesktopType allowed_desktop_;
98 DISALLOW_COPY_AND_ASSIGN(SingleDesktopTestObserver);
101 SingleDesktopTestObserver::SingleDesktopTestObserver(
102 chrome::HostDesktopType allowed_desktop)
103 : allowed_desktop_(allowed_desktop) {
104 BrowserList::AddObserver(this);
107 SingleDesktopTestObserver::~SingleDesktopTestObserver() {
108 BrowserList::RemoveObserver(this);
111 void SingleDesktopTestObserver::OnBrowserAdded(Browser* browser) {
112 CHECK(CalledOnValidThread());
113 CHECK_EQ(browser->host_desktop_type(), allowed_desktop_);
116 } // namespace
118 // Library used for testing accessibility.
119 const base::FilePath::CharType kAXSTesting[] =
120 FILE_PATH_LITERAL("third_party/accessibility-audit/axs_testing.js");
121 // JavaScript snippet to configure and run the accessibility audit.
122 const char kAccessibilityTestString[] =
123 "var config = new axs.AuditConfiguration();"
124 "/* Disable warning about rules that cannot be checked. */"
125 "config.showUnsupportedRulesWarning = false;"
126 "config.auditRulesToIgnore = ["
127 " /*"
128 " * The 'elements with meaningful background image' accessibility"
129 " * audit (AX_IMAGE_01) does not apply, since Chrome doesn't"
130 " * disable background images in high-contrast mode like some"
131 " * browsers do."
132 " */"
133 " 'elementsWithMeaningfulBackgroundImage',"
134 " /*"
135 " * Most WebUI pages are inside an IFrame, so the 'web page should"
136 " * have a title that describes topic or purpose' test (AX_TITLE_01)"
137 " * generally does not apply."
138 " */"
139 " 'pageWithoutTitle',"
140 " /*"
141 " * Enable when crbug.com/267035 is fixed."
142 " * Until then it's just noise."
143 " */"
144 " 'lowContrastElements'"
145 "];"
146 "var result = axs.Audit.run(config);"
147 "var error = '';"
148 "for (var i = 0; i < result.length; ++i) {"
149 " if (result[i].result == axs.constants.AuditResult.FAIL) {"
150 " error = axs.Audit.createReport(result);"
151 " break;"
152 " }"
154 "domAutomationController.send(error);";
156 InProcessBrowserTest::InProcessBrowserTest()
157 : browser_(NULL),
158 exit_when_last_browser_closes_(true),
159 open_about_blank_on_browser_launch_(true),
160 multi_desktop_test_(false),
161 run_accessibility_checks_for_test_case_(false)
162 #if defined(OS_MACOSX)
163 , autorelease_pool_(NULL)
164 #endif // OS_MACOSX
166 #if defined(OS_MACOSX)
167 // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this.
168 // Before we run the browser, we have to hack the path to the exe to match
169 // what it would be if Chrome was running, because it is used to fork renderer
170 // processes, on Linux at least (failure to do so will cause a browser_test to
171 // be run instead of a renderer).
172 base::FilePath chrome_path;
173 CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
174 chrome_path = chrome_path.DirName();
175 chrome_path = chrome_path.Append(chrome::kBrowserProcessExecutablePath);
176 CHECK(PathService::Override(base::FILE_EXE, chrome_path));
177 #endif // defined(OS_MACOSX)
179 CreateTestServer(base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
180 base::FilePath src_dir;
181 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
182 base::FilePath test_data_dir = src_dir.AppendASCII("chrome/test/data");
183 embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
185 // chrome::DIR_TEST_DATA isn't going to be setup until after we call
186 // ContentMain. However that is after tests' constructors or SetUp methods,
187 // which sometimes need it. So just override it.
188 CHECK(PathService::Override(chrome::DIR_TEST_DATA, test_data_dir));
191 InProcessBrowserTest::~InProcessBrowserTest() {
194 void InProcessBrowserTest::SetUp() {
195 // Browser tests will create their own g_browser_process later.
196 DCHECK(!g_browser_process);
198 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
200 // Auto-reload breaks many browser tests, which assume error pages won't be
201 // reloaded out from under them. Tests that expect or desire this behavior can
202 // append switches::kEnableOfflineAutoReload, which will override the disable
203 // here.
204 command_line->AppendSwitch(switches::kDisableOfflineAutoReload);
206 // Allow subclasses to change the command line before running any tests.
207 SetUpCommandLine(command_line);
208 // Add command line arguments that are used by all InProcessBrowserTests.
209 PrepareTestCommandLine(command_line);
211 // Create a temporary user data directory if required.
212 ASSERT_TRUE(CreateUserDataDirectory())
213 << "Could not create user data directory.";
215 // Allow subclasses the opportunity to make changes to the default user data
216 // dir before running any tests.
217 ASSERT_TRUE(SetUpUserDataDirectory())
218 << "Could not set up user data directory.";
220 #if defined(OS_CHROMEOS)
221 // Make sure that the log directory exists.
222 base::FilePath log_dir = logging::GetSessionLogFile(*command_line).DirName();
223 base::CreateDirectory(log_dir);
224 // Disable IME extension loading to avoid many browser tests failures.
225 chromeos::input_method::DisableExtensionLoading();
226 #endif // defined(OS_CHROMEOS)
228 #if defined(OS_MACOSX)
229 // Always use the MockKeychain if OS encription is used (which is when
230 // anything sensitive gets stored, including Cookies). Without this,
231 // many tests will hang waiting for a user to approve KeyChain access.
232 OSCrypt::UseMockKeychain(true);
233 #endif
235 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
236 CaptivePortalService::set_state_for_testing(
237 CaptivePortalService::DISABLED_FOR_TESTING);
238 #endif
240 chrome_browser_net::NetErrorTabHelper::set_state_for_testing(
241 chrome_browser_net::NetErrorTabHelper::TESTING_FORCE_DISABLED);
243 google_util::SetMockLinkDoctorBaseURLForTesting();
245 #if defined(OS_WIN)
246 base::win::Version version = base::win::GetVersion();
247 // Although Ash officially is only supported for users on Win7+, we still run
248 // ash_unittests on Vista builders, so we still need to initialize COM.
249 if (version >= base::win::VERSION_VISTA &&
250 base::CommandLine::ForCurrentProcess()->HasSwitch(
251 switches::kAshBrowserTests)) {
252 com_initializer_.reset(new base::win::ScopedCOMInitializer());
253 ui::win::CreateATLModuleIfNeeded();
254 if (version >= base::win::VERSION_WIN8)
255 ASSERT_TRUE(win8::MakeTestDefaultBrowserSynchronously());
257 #endif
259 BrowserTestBase::SetUp();
262 void InProcessBrowserTest::PrepareTestCommandLine(
263 base::CommandLine* command_line) {
264 // Propagate commandline settings from test_launcher_utils.
265 test_launcher_utils::PrepareBrowserCommandLineForTests(command_line);
267 // This is a Browser test.
268 command_line->AppendSwitchASCII(switches::kTestType, kBrowserTestType);
270 #if defined(OS_WIN)
271 if (command_line->HasSwitch(switches::kAshBrowserTests)) {
272 command_line->AppendSwitchNative(switches::kViewerLaunchViaAppId,
273 win8::test::kDefaultTestAppUserModelId);
274 // Ash already launches with a single browser opened, add kSilentLaunch to
275 // make sure StartupBrowserCreator doesn't attempt to launch a browser on
276 // the native desktop on startup.
277 command_line->AppendSwitch(switches::kSilentLaunch);
279 #endif
281 #if defined(OS_MACOSX)
282 // Explicitly set the path of the binary used for child processes, otherwise
283 // they'll try to use browser_tests which doesn't contain ChromeMain.
284 base::FilePath subprocess_path;
285 PathService::Get(base::FILE_EXE, &subprocess_path);
286 // Recreate the real environment, run the helper within the app bundle.
287 subprocess_path = subprocess_path.DirName().DirName();
288 DCHECK_EQ(subprocess_path.BaseName().value(), "Contents");
289 subprocess_path =
290 subprocess_path.Append("Versions").Append(chrome::kChromeVersion);
291 subprocess_path =
292 subprocess_path.Append(chrome::kHelperProcessExecutablePath);
293 command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
294 subprocess_path);
295 #endif
297 // TODO(pkotwicz): Investigate if we can remove this switch.
298 if (exit_when_last_browser_closes_)
299 command_line->AppendSwitch(switches::kDisableZeroBrowsersOpenForTests);
301 if (open_about_blank_on_browser_launch_ && command_line->GetArgs().empty())
302 command_line->AppendArg(url::kAboutBlankURL);
305 bool InProcessBrowserTest::RunAccessibilityChecks(std::string* error_message) {
306 if (!browser()) {
307 *error_message = "browser is NULL";
308 return false;
310 auto tab_strip = browser()->tab_strip_model();
311 if (!tab_strip) {
312 *error_message = "tab_strip is NULL";
313 return false;
315 auto web_contents = tab_strip->GetActiveWebContents();
316 if (!web_contents) {
317 *error_message = "web_contents is NULL";
318 return false;
320 auto focused_frame = web_contents->GetFocusedFrame();
321 if (!focused_frame) {
322 *error_message = "focused_frame is NULL";
323 return false;
326 // Load accessibility library.
327 base::FilePath src_dir;
328 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) {
329 *error_message = "PathService::Get failed";
330 return false;
332 base::FilePath script_path = src_dir.Append(kAXSTesting);
333 std::string script;
334 if (!base::ReadFileToString(script_path, &script)) {
335 *error_message = "Could not read accessibility library";
336 return false;
338 if (!content::ExecuteScript(web_contents, script)) {
339 *error_message = "Failed to load accessibility library";
340 return false;
343 // Run accessibility audit.
344 if (!content::ExecuteScriptAndExtractString(focused_frame,
345 kAccessibilityTestString,
346 error_message)) {
347 *error_message = "Failed to run accessibility audit";
348 return false;
351 // Test result should be empty if there are no errors.
352 return error_message->empty();
355 bool InProcessBrowserTest::CreateUserDataDirectory() {
356 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
357 base::FilePath user_data_dir =
358 command_line->GetSwitchValuePath(switches::kUserDataDir);
359 if (user_data_dir.empty()) {
360 if (temp_user_data_dir_.CreateUniqueTempDir() &&
361 temp_user_data_dir_.IsValid()) {
362 user_data_dir = temp_user_data_dir_.path();
363 } else {
364 LOG(ERROR) << "Could not create temporary user data directory \""
365 << temp_user_data_dir_.path().value() << "\".";
366 return false;
369 return test_launcher_utils::OverrideUserDataDir(user_data_dir);
372 void InProcessBrowserTest::TearDown() {
373 DCHECK(!g_browser_process);
374 #if defined(OS_WIN)
375 com_initializer_.reset();
376 #endif
377 BrowserTestBase::TearDown();
380 // TODO(alexmos): This function should expose success of the underlying
381 // navigation to tests, which should make sure navigations succeed when
382 // appropriate. See https://crbug.com/425335
383 void InProcessBrowserTest::AddTabAtIndexToBrowser(
384 Browser* browser,
385 int index,
386 const GURL& url,
387 ui::PageTransition transition,
388 bool check_navigation_success) {
389 chrome::NavigateParams params(browser, url, transition);
390 params.tabstrip_index = index;
391 params.disposition = NEW_FOREGROUND_TAB;
392 chrome::Navigate(&params);
394 if (check_navigation_success)
395 content::WaitForLoadStop(params.target_contents);
396 else
397 content::WaitForLoadStopWithoutSuccessCheck(params.target_contents);
400 void InProcessBrowserTest::AddTabAtIndex(
401 int index,
402 const GURL& url,
403 ui::PageTransition transition) {
404 AddTabAtIndexToBrowser(browser(), index, url, transition, true);
407 bool InProcessBrowserTest::SetUpUserDataDirectory() {
408 return true;
411 // Creates a browser with a single tab (about:blank), waits for the tab to
412 // finish loading and shows the browser.
413 Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
414 Browser* browser = new Browser(
415 Browser::CreateParams(profile, chrome::GetActiveDesktop()));
416 AddBlankTabAndShow(browser);
417 return browser;
420 Browser* InProcessBrowserTest::CreateIncognitoBrowser() {
421 // Create a new browser with using the incognito profile.
422 Browser* incognito = new Browser(
423 Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile(),
424 chrome::GetActiveDesktop()));
425 AddBlankTabAndShow(incognito);
426 return incognito;
429 Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
430 Browser* browser =
431 new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile,
432 chrome::GetActiveDesktop()));
433 AddBlankTabAndShow(browser);
434 return browser;
437 Browser* InProcessBrowserTest::CreateBrowserForApp(
438 const std::string& app_name,
439 Profile* profile) {
440 Browser* browser = new Browser(
441 Browser::CreateParams::CreateForApp(
442 app_name, false /* trusted_source */, gfx::Rect(), profile,
443 chrome::GetActiveDesktop()));
444 AddBlankTabAndShow(browser);
445 return browser;
448 void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) {
449 content::WindowedNotificationObserver observer(
450 content::NOTIFICATION_LOAD_STOP,
451 content::NotificationService::AllSources());
452 chrome::AddSelectedTabWithURL(browser,
453 GURL(url::kAboutBlankURL),
454 ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
455 observer.Wait();
457 browser->window()->Show();
460 #if !defined(OS_MACOSX)
461 base::CommandLine InProcessBrowserTest::GetCommandLineForRelaunch() {
462 base::CommandLine new_command_line(
463 base::CommandLine::ForCurrentProcess()->GetProgram());
464 base::CommandLine::SwitchMap switches =
465 base::CommandLine::ForCurrentProcess()->GetSwitches();
466 switches.erase(switches::kUserDataDir);
467 switches.erase(content::kSingleProcessTestsFlag);
468 switches.erase(switches::kSingleProcess);
469 new_command_line.AppendSwitch(content::kLaunchAsBrowser);
471 base::FilePath user_data_dir;
472 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
473 new_command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
475 for (base::CommandLine::SwitchMap::const_iterator iter = switches.begin();
476 iter != switches.end(); ++iter) {
477 new_command_line.AppendSwitchNative((*iter).first, (*iter).second);
479 return new_command_line;
481 #endif
483 void InProcessBrowserTest::RunTestOnMainThreadLoop() {
484 // Pump startup related events.
485 content::RunAllPendingInMessageLoop();
487 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
488 // Self-adds/removes itself from the BrowserList observers.
489 scoped_ptr<SingleDesktopTestObserver> single_desktop_test_observer;
490 if (!multi_desktop_test_) {
491 single_desktop_test_observer.reset(
492 new SingleDesktopTestObserver(active_desktop));
495 const BrowserList* active_browser_list =
496 BrowserList::GetInstance(active_desktop);
497 if (!active_browser_list->empty()) {
498 browser_ = active_browser_list->get(0);
499 #if defined(USE_ASH)
500 // There are cases where windows get created maximized by default.
501 if (browser_->window()->IsMaximized())
502 browser_->window()->Restore();
503 #endif
504 content::WaitForLoadStop(
505 browser_->tab_strip_model()->GetActiveWebContents());
508 #if !defined(OS_ANDROID) && !defined(OS_IOS)
509 // Do not use the real StorageMonitor for tests, which introduces another
510 // source of variability and potential slowness.
511 ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateForBrowserTests());
512 #endif
514 #if defined(OS_MACOSX)
515 // On Mac, without the following autorelease pool, code which is directly
516 // executed (as opposed to executed inside a message loop) would autorelease
517 // objects into a higher-level pool. This pool is not recycled in-sync with
518 // the message loops' pools and causes problems with code relying on
519 // deallocation via an autorelease pool (such as browser window closure and
520 // browser shutdown). To avoid this, the following pool is recycled after each
521 // time code is directly executed.
522 autorelease_pool_ = new base::mac::ScopedNSAutoreleasePool;
523 #endif
525 // Pump any pending events that were created as a result of creating a
526 // browser.
527 content::RunAllPendingInMessageLoop();
529 // run_accessibility_checks_for_test_case_ must be set before calling
530 // SetUpOnMainThread or RunTestOnMainThread so that one or all tests can
531 // enable/disable the accessibility audit.
532 run_accessibility_checks_for_test_case_ = false;
534 SetUpOnMainThread();
535 #if defined(OS_MACOSX)
536 autorelease_pool_->Recycle();
537 #endif
539 if (!HasFatalFailure())
540 RunTestOnMainThread();
541 #if defined(OS_MACOSX)
542 autorelease_pool_->Recycle();
543 #endif
545 if (run_accessibility_checks_for_test_case_) {
546 std::string error_message;
547 EXPECT_TRUE(RunAccessibilityChecks(&error_message));
548 EXPECT_EQ("", error_message);
551 // Invoke cleanup and quit even if there are failures. This is similar to
552 // gtest in that it invokes TearDown even if Setup fails.
553 TearDownOnMainThread();
554 #if defined(OS_MACOSX)
555 autorelease_pool_->Recycle();
556 #endif
558 // Sometimes tests leave Quit tasks in the MessageLoop (for shame), so let's
559 // run all pending messages here to avoid preempting the QuitBrowsers tasks.
560 // TODO(jbates) Once crbug.com/134753 is fixed, this can be removed because it
561 // will not be possible to post Quit tasks.
562 content::RunAllPendingInMessageLoop();
564 QuitBrowsers();
565 // All BrowserLists should be empty at this point.
566 for (chrome::HostDesktopType t = chrome::HOST_DESKTOP_TYPE_FIRST;
567 t < chrome::HOST_DESKTOP_TYPE_COUNT;
568 t = static_cast<chrome::HostDesktopType>(t + 1)) {
569 CHECK(BrowserList::GetInstance(t)->empty()) << t;
573 void InProcessBrowserTest::QuitBrowsers() {
574 if (chrome::GetTotalBrowserCount() == 0) {
575 chrome::NotifyAppTerminating();
576 return;
579 // Invoke AttemptExit on a running message loop.
580 // AttemptExit exits the message loop after everything has been
581 // shut down properly.
582 base::ThreadTaskRunnerHandle::Get()->PostTask(
583 FROM_HERE, base::Bind(&chrome::AttemptExit));
584 content::RunMessageLoop();
586 #if defined(OS_MACOSX)
587 // chrome::AttemptExit() will attempt to close all browsers by deleting
588 // their tab contents. The last tab contents being removed triggers closing of
589 // the browser window.
591 // On the Mac, this eventually reaches
592 // -[BrowserWindowController windowWillClose:], which will post a deferred
593 // -autorelease on itself to ultimately destroy the Browser object. The line
594 // below is necessary to pump these pending messages to ensure all Browsers
595 // get deleted.
596 content::RunAllPendingInMessageLoop();
597 delete autorelease_pool_;
598 autorelease_pool_ = NULL;
599 #endif