Home | History | Annotate | Download | only in base
      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 "chrome/test/base/in_process_browser_test.h"
      6 
      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/file_util.h"
     12 #include "base/files/file_path.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/path_service.h"
     15 #include "base/strings/string_number_conversions.h"
     16 #include "base/test/test_file_util.h"
     17 #include "base/threading/non_thread_safe.h"
     18 #include "chrome/browser/browser_process.h"
     19 #include "chrome/browser/lifetime/application_lifetime.h"
     20 #include "chrome/browser/net/net_error_tab_helper.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/profiles/profile_manager.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_finder.h"
     25 #include "chrome/browser/ui/browser_list.h"
     26 #include "chrome/browser/ui/browser_list_observer.h"
     27 #include "chrome/browser/ui/browser_navigator.h"
     28 #include "chrome/browser/ui/browser_tabstrip.h"
     29 #include "chrome/browser/ui/browser_window.h"
     30 #include "chrome/browser/ui/host_desktop.h"
     31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     32 #include "chrome/common/chrome_constants.h"
     33 #include "chrome/common/chrome_paths.h"
     34 #include "chrome/common/chrome_switches.h"
     35 #include "chrome/common/logging_chrome.h"
     36 #include "chrome/common/url_constants.h"
     37 #include "chrome/renderer/chrome_content_renderer_client.h"
     38 #include "chrome/test/base/chrome_test_suite.h"
     39 #include "chrome/test/base/test_launcher_utils.h"
     40 #include "chrome/test/base/test_switches.h"
     41 #include "chrome/test/base/testing_browser_process.h"
     42 #include "chrome/test/base/ui_test_utils.h"
     43 #include "components/google/core/browser/google_util.h"
     44 #include "components/os_crypt/os_crypt.h"
     45 #include "content/public/browser/notification_service.h"
     46 #include "content/public/browser/notification_types.h"
     47 #include "content/public/test/browser_test_utils.h"
     48 #include "content/public/test/test_launcher.h"
     49 #include "content/public/test/test_navigation_observer.h"
     50 #include "net/test/embedded_test_server/embedded_test_server.h"
     51 #include "net/test/spawned_test_server/spawned_test_server.h"
     52 
     53 #if defined(OS_MACOSX)
     54 #include "base/mac/scoped_nsautorelease_pool.h"
     55 #endif
     56 
     57 #if defined(OS_WIN)
     58 #include "base/win/scoped_com_initializer.h"
     59 #include "base/win/windows_version.h"
     60 #include "ui/base/win/atl_module.h"
     61 #include "win8/test/metro_registration_helper.h"
     62 #include "win8/test/test_registrar_constants.h"
     63 #endif
     64 
     65 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
     66 #include "chrome/browser/captive_portal/captive_portal_service.h"
     67 #endif
     68 
     69 #if !defined(OS_ANDROID) && !defined(OS_IOS)
     70 #include "components/storage_monitor/test_storage_monitor.h"
     71 #endif
     72 
     73 namespace {
     74 
     75 // Passed as value of kTestType.
     76 const char kBrowserTestType[] = "browser";
     77 
     78 // A BrowserListObserver that makes sure that all browsers created are on the
     79 // |allowed_desktop_|.
     80 class SingleDesktopTestObserver : public chrome::BrowserListObserver,
     81                                   public base::NonThreadSafe {
     82  public:
     83   explicit SingleDesktopTestObserver(chrome::HostDesktopType allowed_desktop);
     84   virtual ~SingleDesktopTestObserver();
     85 
     86   // chrome::BrowserListObserver:
     87   virtual void OnBrowserAdded(Browser* browser) OVERRIDE;
     88 
     89  private:
     90   chrome::HostDesktopType allowed_desktop_;
     91 
     92   DISALLOW_COPY_AND_ASSIGN(SingleDesktopTestObserver);
     93 };
     94 
     95 SingleDesktopTestObserver::SingleDesktopTestObserver(
     96     chrome::HostDesktopType allowed_desktop)
     97         : allowed_desktop_(allowed_desktop) {
     98   BrowserList::AddObserver(this);
     99 }
    100 
    101 SingleDesktopTestObserver::~SingleDesktopTestObserver() {
    102   BrowserList::RemoveObserver(this);
    103 }
    104 
    105 void SingleDesktopTestObserver::OnBrowserAdded(Browser* browser) {
    106   CHECK(CalledOnValidThread());
    107   CHECK_EQ(browser->host_desktop_type(), allowed_desktop_);
    108 }
    109 
    110 }  // namespace
    111 
    112 InProcessBrowserTest::InProcessBrowserTest()
    113     : browser_(NULL),
    114       exit_when_last_browser_closes_(true),
    115       multi_desktop_test_(false)
    116 #if defined(OS_MACOSX)
    117       , autorelease_pool_(NULL)
    118 #endif  // OS_MACOSX
    119     {
    120 #if defined(OS_MACOSX)
    121   // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this.
    122   // Before we run the browser, we have to hack the path to the exe to match
    123   // what it would be if Chrome was running, because it is used to fork renderer
    124   // processes, on Linux at least (failure to do so will cause a browser_test to
    125   // be run instead of a renderer).
    126   base::FilePath chrome_path;
    127   CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
    128   chrome_path = chrome_path.DirName();
    129   chrome_path = chrome_path.Append(chrome::kBrowserProcessExecutablePath);
    130   CHECK(PathService::Override(base::FILE_EXE, chrome_path));
    131 #endif  // defined(OS_MACOSX)
    132 
    133   CreateTestServer(base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
    134   base::FilePath src_dir;
    135   CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
    136   base::FilePath test_data_dir = src_dir.AppendASCII("chrome/test/data");
    137   embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
    138 
    139   // chrome::DIR_TEST_DATA isn't going to be setup until after we call
    140   // ContentMain. However that is after tests' constructors or SetUp methods,
    141   // which sometimes need it. So just override it.
    142   CHECK(PathService::Override(chrome::DIR_TEST_DATA, test_data_dir));
    143 }
    144 
    145 InProcessBrowserTest::~InProcessBrowserTest() {
    146 }
    147 
    148 void InProcessBrowserTest::SetUp() {
    149   // Browser tests will create their own g_browser_process later.
    150   DCHECK(!g_browser_process);
    151 
    152   CommandLine* command_line = CommandLine::ForCurrentProcess();
    153 
    154   // Auto-reload breaks many browser tests, which assume error pages won't be
    155   // reloaded out from under them. Tests that expect or desire this behavior can
    156   // append switches::kEnableOfflineAutoReload, which will override the disable
    157   // here.
    158   command_line->AppendSwitch(switches::kDisableOfflineAutoReload);
    159 
    160   // Allow subclasses to change the command line before running any tests.
    161   SetUpCommandLine(command_line);
    162   // Add command line arguments that are used by all InProcessBrowserTests.
    163   PrepareTestCommandLine(command_line);
    164 
    165   // Create a temporary user data directory if required.
    166   ASSERT_TRUE(CreateUserDataDirectory())
    167       << "Could not create user data directory.";
    168 
    169   // Allow subclasses the opportunity to make changes to the default user data
    170   // dir before running any tests.
    171   ASSERT_TRUE(SetUpUserDataDirectory())
    172       << "Could not set up user data directory.";
    173 
    174 #if defined(OS_CHROMEOS)
    175   // Make sure that the log directory exists.
    176   base::FilePath log_dir = logging::GetSessionLogFile(*command_line).DirName();
    177   base::CreateDirectory(log_dir);
    178 #endif  // defined(OS_CHROMEOS)
    179 
    180 #if defined(OS_MACOSX)
    181   // Always use the MockKeychain if OS encription is used (which is when
    182   // anything sensitive gets stored, including Cookies).  Without this,
    183   // many tests will hang waiting for a user to approve KeyChain access.
    184   OSCrypt::UseMockKeychain(true);
    185 #endif
    186 
    187 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
    188   CaptivePortalService::set_state_for_testing(
    189       CaptivePortalService::DISABLED_FOR_TESTING);
    190 #endif
    191 
    192   chrome_browser_net::NetErrorTabHelper::set_state_for_testing(
    193       chrome_browser_net::NetErrorTabHelper::TESTING_FORCE_DISABLED);
    194 
    195   google_util::SetMockLinkDoctorBaseURLForTesting();
    196 
    197 #if defined(OS_WIN)
    198   base::win::Version version = base::win::GetVersion();
    199   // Although Ash officially is only supported for users on Win7+, we still run
    200   // ash_unittests on Vista builders, so we still need to initialize COM.
    201   if (version >= base::win::VERSION_VISTA &&
    202       CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) {
    203     com_initializer_.reset(new base::win::ScopedCOMInitializer());
    204     ui::win::CreateATLModuleIfNeeded();
    205     if (version >= base::win::VERSION_WIN8)
    206       ASSERT_TRUE(win8::MakeTestDefaultBrowserSynchronously());
    207   }
    208 #endif
    209 
    210   BrowserTestBase::SetUp();
    211 }
    212 
    213 void InProcessBrowserTest::PrepareTestCommandLine(CommandLine* command_line) {
    214   // Propagate commandline settings from test_launcher_utils.
    215   test_launcher_utils::PrepareBrowserCommandLineForTests(command_line);
    216 
    217   // This is a Browser test.
    218   command_line->AppendSwitchASCII(switches::kTestType, kBrowserTestType);
    219 
    220 #if defined(OS_WIN)
    221   if (command_line->HasSwitch(switches::kAshBrowserTests)) {
    222     command_line->AppendSwitchNative(switches::kViewerLaunchViaAppId,
    223                                      win8::test::kDefaultTestAppUserModelId);
    224     // Ash already launches with a single browser opened, add kSilentLaunch to
    225     // make sure StartupBrowserCreator doesn't attempt to launch a browser on
    226     // the native desktop on startup.
    227     command_line->AppendSwitch(switches::kSilentLaunch);
    228   }
    229 #endif
    230 
    231 #if defined(OS_MACOSX)
    232   // Explicitly set the path of the binary used for child processes, otherwise
    233   // they'll try to use browser_tests which doesn't contain ChromeMain.
    234   base::FilePath subprocess_path;
    235   PathService::Get(base::FILE_EXE, &subprocess_path);
    236   // Recreate the real environment, run the helper within the app bundle.
    237   subprocess_path = subprocess_path.DirName().DirName();
    238   DCHECK_EQ(subprocess_path.BaseName().value(), "Contents");
    239   subprocess_path =
    240       subprocess_path.Append("Versions").Append(chrome::kChromeVersion);
    241   subprocess_path =
    242       subprocess_path.Append(chrome::kHelperProcessExecutablePath);
    243   command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
    244                                  subprocess_path);
    245 #endif
    246 
    247   // TODO(pkotwicz): Investigate if we can remove this switch.
    248   if (exit_when_last_browser_closes_)
    249     command_line->AppendSwitch(switches::kDisableZeroBrowsersOpenForTests);
    250 
    251   if (command_line->GetArgs().empty())
    252     command_line->AppendArg(url::kAboutBlankURL);
    253 }
    254 
    255 bool InProcessBrowserTest::CreateUserDataDirectory() {
    256   CommandLine* command_line = CommandLine::ForCurrentProcess();
    257   base::FilePath user_data_dir =
    258       command_line->GetSwitchValuePath(switches::kUserDataDir);
    259   if (user_data_dir.empty()) {
    260     if (temp_user_data_dir_.CreateUniqueTempDir() &&
    261         temp_user_data_dir_.IsValid()) {
    262       user_data_dir = temp_user_data_dir_.path();
    263     } else {
    264       LOG(ERROR) << "Could not create temporary user data directory \""
    265                  << temp_user_data_dir_.path().value() << "\".";
    266       return false;
    267     }
    268   }
    269   return test_launcher_utils::OverrideUserDataDir(user_data_dir);
    270 }
    271 
    272 void InProcessBrowserTest::TearDown() {
    273   DCHECK(!g_browser_process);
    274 #if defined(OS_WIN)
    275   com_initializer_.reset();
    276 #endif
    277   BrowserTestBase::TearDown();
    278 }
    279 
    280 void InProcessBrowserTest::AddTabAtIndexToBrowser(
    281     Browser* browser,
    282     int index,
    283     const GURL& url,
    284     content::PageTransition transition) {
    285   chrome::NavigateParams params(browser, url, transition);
    286   params.tabstrip_index = index;
    287   params.disposition = NEW_FOREGROUND_TAB;
    288   chrome::Navigate(&params);
    289 
    290   content::WaitForLoadStop(params.target_contents);
    291 }
    292 
    293 void InProcessBrowserTest::AddTabAtIndex(
    294     int index,
    295     const GURL& url,
    296     content::PageTransition transition) {
    297   AddTabAtIndexToBrowser(browser(), index, url, transition);
    298 }
    299 
    300 bool InProcessBrowserTest::SetUpUserDataDirectory() {
    301   return true;
    302 }
    303 
    304 // Creates a browser with a single tab (about:blank), waits for the tab to
    305 // finish loading and shows the browser.
    306 Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
    307   Browser* browser = new Browser(
    308       Browser::CreateParams(profile, chrome::GetActiveDesktop()));
    309   AddBlankTabAndShow(browser);
    310   return browser;
    311 }
    312 
    313 Browser* InProcessBrowserTest::CreateIncognitoBrowser() {
    314   // Create a new browser with using the incognito profile.
    315   Browser* incognito = new Browser(
    316       Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile(),
    317                             chrome::GetActiveDesktop()));
    318   AddBlankTabAndShow(incognito);
    319   return incognito;
    320 }
    321 
    322 Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
    323   Browser* browser =
    324       new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile,
    325                   chrome::GetActiveDesktop()));
    326   AddBlankTabAndShow(browser);
    327   return browser;
    328 }
    329 
    330 Browser* InProcessBrowserTest::CreateBrowserForApp(
    331     const std::string& app_name,
    332     Profile* profile) {
    333   Browser* browser = new Browser(
    334       Browser::CreateParams::CreateForApp(
    335           app_name, false /* trusted_source */, gfx::Rect(), profile,
    336           chrome::GetActiveDesktop()));
    337   AddBlankTabAndShow(browser);
    338   return browser;
    339 }
    340 
    341 void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) {
    342   content::WindowedNotificationObserver observer(
    343       content::NOTIFICATION_LOAD_STOP,
    344       content::NotificationService::AllSources());
    345   chrome::AddSelectedTabWithURL(browser,
    346                                 GURL(url::kAboutBlankURL),
    347                                 content::PAGE_TRANSITION_AUTO_TOPLEVEL);
    348   observer.Wait();
    349 
    350   browser->window()->Show();
    351 }
    352 
    353 #if !defined(OS_MACOSX)
    354 CommandLine InProcessBrowserTest::GetCommandLineForRelaunch() {
    355   CommandLine new_command_line(CommandLine::ForCurrentProcess()->GetProgram());
    356   CommandLine::SwitchMap switches =
    357       CommandLine::ForCurrentProcess()->GetSwitches();
    358   switches.erase(switches::kUserDataDir);
    359   switches.erase(content::kSingleProcessTestsFlag);
    360   switches.erase(switches::kSingleProcess);
    361   new_command_line.AppendSwitch(content::kLaunchAsBrowser);
    362 
    363   base::FilePath user_data_dir;
    364   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    365   new_command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
    366 
    367   for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
    368         iter != switches.end(); ++iter) {
    369     new_command_line.AppendSwitchNative((*iter).first, (*iter).second);
    370   }
    371   return new_command_line;
    372 }
    373 #endif
    374 
    375 void InProcessBrowserTest::RunTestOnMainThreadLoop() {
    376   // Pump startup related events.
    377   content::RunAllPendingInMessageLoop();
    378 
    379   chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
    380   // Self-adds/removes itself from the BrowserList observers.
    381   scoped_ptr<SingleDesktopTestObserver> single_desktop_test_observer;
    382   if (!multi_desktop_test_) {
    383     single_desktop_test_observer.reset(
    384         new SingleDesktopTestObserver(active_desktop));
    385   }
    386 
    387   const BrowserList* active_browser_list =
    388       BrowserList::GetInstance(active_desktop);
    389   if (!active_browser_list->empty()) {
    390     browser_ = active_browser_list->get(0);
    391 #if defined(USE_ASH)
    392     // There are cases where windows get created maximized by default.
    393     if (browser_->window()->IsMaximized())
    394       browser_->window()->Restore();
    395 #endif
    396     content::WaitForLoadStop(
    397         browser_->tab_strip_model()->GetActiveWebContents());
    398   }
    399 
    400 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    401   // Do not use the real StorageMonitor for tests, which introduces another
    402   // source of variability and potential slowness.
    403   ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateForBrowserTests());
    404 #endif
    405 
    406 #if defined(OS_MACOSX)
    407   // On Mac, without the following autorelease pool, code which is directly
    408   // executed (as opposed to executed inside a message loop) would autorelease
    409   // objects into a higher-level pool. This pool is not recycled in-sync with
    410   // the message loops' pools and causes problems with code relying on
    411   // deallocation via an autorelease pool (such as browser window closure and
    412   // browser shutdown). To avoid this, the following pool is recycled after each
    413   // time code is directly executed.
    414   autorelease_pool_ = new base::mac::ScopedNSAutoreleasePool;
    415 #endif
    416 
    417   // Pump any pending events that were created as a result of creating a
    418   // browser.
    419   content::RunAllPendingInMessageLoop();
    420 
    421   SetUpOnMainThread();
    422 #if defined(OS_MACOSX)
    423   autorelease_pool_->Recycle();
    424 #endif
    425 
    426   if (!HasFatalFailure())
    427     RunTestOnMainThread();
    428 #if defined(OS_MACOSX)
    429   autorelease_pool_->Recycle();
    430 #endif
    431 
    432   // Invoke cleanup and quit even if there are failures. This is similar to
    433   // gtest in that it invokes TearDown even if Setup fails.
    434   CleanUpOnMainThread();
    435 #if defined(OS_MACOSX)
    436   autorelease_pool_->Recycle();
    437 #endif
    438 
    439   // Sometimes tests leave Quit tasks in the MessageLoop (for shame), so let's
    440   // run all pending messages here to avoid preempting the QuitBrowsers tasks.
    441   // TODO(jbates) Once crbug.com/134753 is fixed, this can be removed because it
    442   // will not be possible to post Quit tasks.
    443   content::RunAllPendingInMessageLoop();
    444 
    445   QuitBrowsers();
    446   // All BrowserLists should be empty at this point.
    447   for (chrome::HostDesktopType t = chrome::HOST_DESKTOP_TYPE_FIRST;
    448        t < chrome::HOST_DESKTOP_TYPE_COUNT;
    449        t = static_cast<chrome::HostDesktopType>(t + 1)) {
    450     CHECK(BrowserList::GetInstance(t)->empty()) << t;
    451   }
    452 }
    453 
    454 void InProcessBrowserTest::QuitBrowsers() {
    455   if (chrome::GetTotalBrowserCount() == 0) {
    456     chrome::NotifyAppTerminating();
    457     return;
    458   }
    459 
    460   // Invoke AttemptExit on a running message loop.
    461   // AttemptExit exits the message loop after everything has been
    462   // shut down properly.
    463   base::MessageLoopForUI::current()->PostTask(FROM_HERE,
    464                                               base::Bind(&chrome::AttemptExit));
    465   content::RunMessageLoop();
    466 
    467 #if defined(OS_MACOSX)
    468   // chrome::AttemptExit() will attempt to close all browsers by deleting
    469   // their tab contents. The last tab contents being removed triggers closing of
    470   // the browser window.
    471   //
    472   // On the Mac, this eventually reaches
    473   // -[BrowserWindowController windowWillClose:], which will post a deferred
    474   // -autorelease on itself to ultimately destroy the Browser object. The line
    475   // below is necessary to pump these pending messages to ensure all Browsers
    476   // get deleted.
    477   content::RunAllPendingInMessageLoop();
    478   delete autorelease_pool_;
    479   autorelease_pool_ = NULL;
    480 #endif
    481 }
    482