Home | History | Annotate | Download | only in extensions
      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/browser/extensions/extension_browsertest.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/files/file_path.h"
     11 #include "base/files/file_util.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/path_service.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "chrome/browser/extensions/browsertest_util.h"
     18 #include "chrome/browser/extensions/component_loader.h"
     19 #include "chrome/browser/extensions/crx_installer.h"
     20 #include "chrome/browser/extensions/extension_creator.h"
     21 #include "chrome/browser/extensions/extension_error_reporter.h"
     22 #include "chrome/browser/extensions/extension_install_prompt.h"
     23 #include "chrome/browser/extensions/extension_service.h"
     24 #include "chrome/browser/extensions/extension_util.h"
     25 #include "chrome/browser/extensions/unpacked_installer.h"
     26 #include "chrome/browser/extensions/updater/extension_cache_fake.h"
     27 #include "chrome/browser/profiles/profile.h"
     28 #include "chrome/browser/profiles/profile_manager.h"
     29 #include "chrome/browser/ui/browser.h"
     30 #include "chrome/browser/ui/browser_window.h"
     31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     32 #include "chrome/common/chrome_paths.h"
     33 #include "chrome/common/chrome_switches.h"
     34 #include "chrome/common/chrome_version_info.h"
     35 #include "chrome/test/base/ui_test_utils.h"
     36 #include "content/public/browser/navigation_controller.h"
     37 #include "content/public/browser/navigation_entry.h"
     38 #include "content/public/browser/notification_registrar.h"
     39 #include "content/public/browser/notification_service.h"
     40 #include "content/public/browser/render_view_host.h"
     41 #include "content/public/test/browser_test_utils.h"
     42 #include "extensions/browser/extension_host.h"
     43 #include "extensions/browser/extension_prefs.h"
     44 #include "extensions/browser/extension_system.h"
     45 #include "extensions/browser/notification_types.h"
     46 #include "extensions/browser/uninstall_reason.h"
     47 #include "extensions/common/constants.h"
     48 #include "extensions/common/extension_set.h"
     49 #include "sync/api/string_ordinal.h"
     50 
     51 #if defined(OS_CHROMEOS)
     52 #include "chromeos/chromeos_switches.h"
     53 #endif
     54 
     55 using extensions::Extension;
     56 using extensions::ExtensionCreator;
     57 using extensions::FeatureSwitch;
     58 using extensions::Manifest;
     59 
     60 ExtensionBrowserTest::ExtensionBrowserTest()
     61     : loaded_(false),
     62       installed_(false),
     63 #if defined(OS_CHROMEOS)
     64       set_chromeos_user_(true),
     65 #endif
     66       // Default channel is STABLE but override with UNKNOWN so that unlaunched
     67       // or incomplete APIs can write tests.
     68       current_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN),
     69       override_prompt_for_external_extensions_(
     70           FeatureSwitch::prompt_for_external_extensions(),
     71           false),
     72 #if defined(OS_WIN)
     73       user_desktop_override_(base::DIR_USER_DESKTOP),
     74       common_desktop_override_(base::DIR_COMMON_DESKTOP),
     75       user_quick_launch_override_(base::DIR_USER_QUICK_LAUNCH),
     76       start_menu_override_(base::DIR_START_MENU),
     77       common_start_menu_override_(base::DIR_COMMON_START_MENU),
     78 #endif
     79       profile_(NULL) {
     80   EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     81 }
     82 
     83 ExtensionBrowserTest::~ExtensionBrowserTest() {
     84 }
     85 
     86 Profile* ExtensionBrowserTest::profile() {
     87   if (!profile_) {
     88     if (browser())
     89       profile_ = browser()->profile();
     90     else
     91       profile_ = ProfileManager::GetActiveUserProfile();
     92   }
     93   return profile_;
     94 }
     95 
     96 // static
     97 const Extension* ExtensionBrowserTest::GetExtensionByPath(
     98     const extensions::ExtensionSet* extensions, const base::FilePath& path) {
     99   base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
    100   EXPECT_TRUE(!extension_path.empty());
    101   for (extensions::ExtensionSet::const_iterator iter = extensions->begin();
    102        iter != extensions->end(); ++iter) {
    103     if ((*iter)->path() == extension_path) {
    104       return iter->get();
    105     }
    106   }
    107   return NULL;
    108 }
    109 
    110 void ExtensionBrowserTest::SetUp() {
    111   test_extension_cache_.reset(new extensions::ExtensionCacheFake());
    112   InProcessBrowserTest::SetUp();
    113 }
    114 
    115 void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
    116   PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
    117   test_data_dir_ = test_data_dir_.AppendASCII("extensions");
    118   observer_.reset(new ExtensionTestNotificationObserver(browser()));
    119 
    120 #if defined(OS_CHROMEOS)
    121   if (set_chromeos_user_) {
    122     // This makes sure that we create the Default profile first, with no
    123     // ExtensionService and then the real profile with one, as we do when
    124     // running on chromeos.
    125     command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
    126                                     "TestUser (at) gmail.com");
    127     command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
    128   }
    129 #endif
    130 }
    131 
    132 void ExtensionBrowserTest::SetUpOnMainThread() {
    133   InProcessBrowserTest::SetUpOnMainThread();
    134   observer_.reset(new ExtensionTestNotificationObserver(browser()));
    135 }
    136 
    137 const Extension* ExtensionBrowserTest::LoadExtension(
    138     const base::FilePath& path) {
    139   return LoadExtensionWithFlags(path, kFlagEnableFileAccess);
    140 }
    141 
    142 const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
    143     const base::FilePath& path) {
    144   return LoadExtensionWithFlags(path,
    145                                 kFlagEnableFileAccess | kFlagEnableIncognito);
    146 }
    147 
    148 const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
    149     const base::FilePath& path, int flags) {
    150   return LoadExtensionWithInstallParam(path, flags, std::string());
    151 }
    152 
    153 const extensions::Extension*
    154 ExtensionBrowserTest::LoadExtensionWithInstallParam(
    155     const base::FilePath& path,
    156     int flags,
    157     const std::string& install_param) {
    158   ExtensionService* service = extensions::ExtensionSystem::Get(
    159       profile())->extension_service();
    160   {
    161     observer_->Watch(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    162                      content::NotificationService::AllSources());
    163 
    164     scoped_refptr<extensions::UnpackedInstaller> installer(
    165         extensions::UnpackedInstaller::Create(service));
    166     installer->set_prompt_for_plugins(false);
    167     installer->set_require_modern_manifest_version(
    168         (flags & kFlagAllowOldManifestVersions) == 0);
    169     installer->Load(path);
    170 
    171     observer_->Wait();
    172   }
    173 
    174   // Find the loaded extension by its path. See crbug.com/59531 for why
    175   // we cannot just use last_loaded_extension_id().
    176   const Extension* extension = GetExtensionByPath(service->extensions(), path);
    177   if (!extension)
    178     return NULL;
    179 
    180   if (!(flags & kFlagIgnoreManifestWarnings)) {
    181     const std::vector<extensions::InstallWarning>& install_warnings =
    182         extension->install_warnings();
    183     if (!install_warnings.empty()) {
    184       std::string install_warnings_message = base::StringPrintf(
    185           "Unexpected warnings when loading test extension %s:\n",
    186           path.AsUTF8Unsafe().c_str());
    187 
    188       for (std::vector<extensions::InstallWarning>::const_iterator it =
    189           install_warnings.begin(); it != install_warnings.end(); ++it) {
    190         install_warnings_message += "  " + it->message + "\n";
    191       }
    192 
    193       EXPECT_EQ(0u, extension->install_warnings().size())
    194           << install_warnings_message;
    195       return NULL;
    196     }
    197   }
    198 
    199   const std::string extension_id = extension->id();
    200 
    201   if (!install_param.empty()) {
    202     extensions::ExtensionPrefs::Get(profile())
    203         ->SetInstallParam(extension_id, install_param);
    204     // Re-enable the extension if needed.
    205     if (service->extensions()->Contains(extension_id)) {
    206       content::WindowedNotificationObserver load_signal(
    207           extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    208           content::Source<Profile>(profile()));
    209       // Reload the extension so that the
    210       // NOTIFICATION_EXTENSION_LOADED_DEPRECATED
    211       // observers may access |install_param|.
    212       service->ReloadExtension(extension_id);
    213       load_signal.Wait();
    214       extension = service->GetExtensionById(extension_id, false);
    215       CHECK(extension) << extension_id << " not found after reloading.";
    216     }
    217   }
    218 
    219   // Toggling incognito or file access will reload the extension, so wait for
    220   // the reload and grab the new extension instance. The default state is
    221   // incognito disabled and file access enabled, so we don't wait in those
    222   // cases.
    223   {
    224     content::WindowedNotificationObserver load_signal(
    225         extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    226         content::Source<Profile>(profile()));
    227     CHECK(!extensions::util::IsIncognitoEnabled(extension_id, profile()));
    228 
    229     if (flags & kFlagEnableIncognito) {
    230       extensions::util::SetIsIncognitoEnabled(extension_id, profile(), true);
    231       load_signal.Wait();
    232       extension = service->GetExtensionById(extension_id, false);
    233       CHECK(extension) << extension_id << " not found after reloading.";
    234     }
    235   }
    236 
    237   {
    238     content::WindowedNotificationObserver load_signal(
    239         extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    240         content::Source<Profile>(profile()));
    241     CHECK(extensions::util::AllowFileAccess(extension_id, profile()));
    242     if (!(flags & kFlagEnableFileAccess)) {
    243       extensions::util::SetAllowFileAccess(extension_id, profile(), false);
    244       load_signal.Wait();
    245       extension = service->GetExtensionById(extension_id, false);
    246       CHECK(extension) << extension_id << " not found after reloading.";
    247     }
    248   }
    249 
    250   if (!observer_->WaitForExtensionViewsToLoad())
    251     return NULL;
    252 
    253   return extension;
    254 }
    255 
    256 const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
    257     const base::FilePath& path,
    258     const base::FilePath::CharType* manifest_relative_path) {
    259   ExtensionService* service = extensions::ExtensionSystem::Get(
    260       profile())->extension_service();
    261 
    262   std::string manifest;
    263   if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) {
    264     return NULL;
    265   }
    266 
    267   std::string extension_id = service->component_loader()->Add(manifest, path);
    268   const Extension* extension = service->extensions()->GetByID(extension_id);
    269   if (!extension)
    270     return NULL;
    271   observer_->set_last_loaded_extension_id(extension->id());
    272   return extension;
    273 }
    274 
    275 const Extension* ExtensionBrowserTest::LoadExtensionAsComponent(
    276     const base::FilePath& path) {
    277   return LoadExtensionAsComponentWithManifest(path,
    278                                               extensions::kManifestFilename);
    279 }
    280 
    281 base::FilePath ExtensionBrowserTest::PackExtension(
    282     const base::FilePath& dir_path) {
    283   base::FilePath crx_path = temp_dir_.path().AppendASCII("temp.crx");
    284   if (!base::DeleteFile(crx_path, false)) {
    285     ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
    286     return base::FilePath();
    287   }
    288 
    289   // Look for PEM files with the same name as the directory.
    290   base::FilePath pem_path =
    291       dir_path.ReplaceExtension(FILE_PATH_LITERAL(".pem"));
    292   base::FilePath pem_path_out;
    293 
    294   if (!base::PathExists(pem_path)) {
    295     pem_path = base::FilePath();
    296     pem_path_out = crx_path.DirName().AppendASCII("temp.pem");
    297     if (!base::DeleteFile(pem_path_out, false)) {
    298       ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value();
    299       return base::FilePath();
    300     }
    301   }
    302 
    303   return PackExtensionWithOptions(dir_path, crx_path, pem_path, pem_path_out);
    304 }
    305 
    306 base::FilePath ExtensionBrowserTest::PackExtensionWithOptions(
    307     const base::FilePath& dir_path,
    308     const base::FilePath& crx_path,
    309     const base::FilePath& pem_path,
    310     const base::FilePath& pem_out_path) {
    311   if (!base::PathExists(dir_path)) {
    312     ADD_FAILURE() << "Extension dir not found: " << dir_path.value();
    313     return base::FilePath();
    314   }
    315 
    316   if (!base::PathExists(pem_path) && pem_out_path.empty()) {
    317     ADD_FAILURE() << "Must specify a PEM file or PEM output path";
    318     return base::FilePath();
    319   }
    320 
    321   scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
    322   if (!creator->Run(dir_path,
    323                     crx_path,
    324                     pem_path,
    325                     pem_out_path,
    326                     ExtensionCreator::kOverwriteCRX)) {
    327     ADD_FAILURE() << "ExtensionCreator::Run() failed: "
    328                   << creator->error_message();
    329     return base::FilePath();
    330   }
    331 
    332   if (!base::PathExists(crx_path)) {
    333     ADD_FAILURE() << crx_path.value() << " was not created.";
    334     return base::FilePath();
    335   }
    336   return crx_path;
    337 }
    338 
    339 // This class is used to simulate an installation abort by the user.
    340 class MockAbortExtensionInstallPrompt : public ExtensionInstallPrompt {
    341  public:
    342   MockAbortExtensionInstallPrompt() : ExtensionInstallPrompt(NULL) {
    343   }
    344 
    345   // Simulate a user abort on an extension installation.
    346   virtual void ConfirmInstall(
    347       Delegate* delegate,
    348       const Extension* extension,
    349       const ShowDialogCallback& show_dialog_callback) OVERRIDE {
    350     delegate->InstallUIAbort(true);
    351     base::MessageLoopForUI::current()->Quit();
    352   }
    353 
    354   virtual void OnInstallSuccess(const Extension* extension,
    355                                 SkBitmap* icon) OVERRIDE {}
    356 
    357   virtual void OnInstallFailure(
    358       const extensions::CrxInstallerError& error) OVERRIDE {}
    359 };
    360 
    361 class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt {
    362  public:
    363   explicit MockAutoConfirmExtensionInstallPrompt(
    364       content::WebContents* web_contents)
    365     : ExtensionInstallPrompt(web_contents) {}
    366 
    367   // Proceed without confirmation prompt.
    368   virtual void ConfirmInstall(
    369       Delegate* delegate,
    370       const Extension* extension,
    371       const ShowDialogCallback& show_dialog_callback) OVERRIDE {
    372     delegate->InstallUIProceed();
    373   }
    374 };
    375 
    376 const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
    377     const std::string& id,
    378     const base::FilePath& path,
    379     int expected_change) {
    380   return InstallOrUpdateExtension(id,
    381                                   path,
    382                                   INSTALL_UI_TYPE_NONE,
    383                                   expected_change,
    384                                   Manifest::INTERNAL,
    385                                   browser(),
    386                                   Extension::NO_FLAGS,
    387                                   false,
    388                                   false);
    389 }
    390 
    391 const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore(
    392     const base::FilePath& path,
    393     int expected_change) {
    394   return InstallOrUpdateExtension(std::string(),
    395                                   path,
    396                                   INSTALL_UI_TYPE_NONE,
    397                                   expected_change,
    398                                   Manifest::INTERNAL,
    399                                   browser(),
    400                                   Extension::FROM_WEBSTORE,
    401                                   true,
    402                                   false);
    403 }
    404 
    405 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
    406     const std::string& id,
    407     const base::FilePath& path,
    408     InstallUIType ui_type,
    409     int expected_change) {
    410   return InstallOrUpdateExtension(id,
    411                                   path,
    412                                   ui_type,
    413                                   expected_change,
    414                                   Manifest::INTERNAL,
    415                                   browser(),
    416                                   Extension::NO_FLAGS,
    417                                   true,
    418                                   false);
    419 }
    420 
    421 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
    422     const std::string& id,
    423     const base::FilePath& path,
    424     InstallUIType ui_type,
    425     int expected_change,
    426     Browser* browser,
    427     Extension::InitFromValueFlags creation_flags) {
    428   return InstallOrUpdateExtension(id,
    429                                   path,
    430                                   ui_type,
    431                                   expected_change,
    432                                   Manifest::INTERNAL,
    433                                   browser,
    434                                   creation_flags,
    435                                   true,
    436                                   false);
    437 }
    438 
    439 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
    440     const std::string& id,
    441     const base::FilePath& path,
    442     InstallUIType ui_type,
    443     int expected_change,
    444     Manifest::Location install_source) {
    445   return InstallOrUpdateExtension(id,
    446                                   path,
    447                                   ui_type,
    448                                   expected_change,
    449                                   install_source,
    450                                   browser(),
    451                                   Extension::NO_FLAGS,
    452                                   true,
    453                                   false);
    454 }
    455 
    456 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
    457     const std::string& id,
    458     const base::FilePath& path,
    459     InstallUIType ui_type,
    460     int expected_change,
    461     Manifest::Location install_source,
    462     Browser* browser,
    463     Extension::InitFromValueFlags creation_flags,
    464     bool install_immediately,
    465     bool is_ephemeral) {
    466   ExtensionService* service =
    467       extensions::ExtensionSystem::Get(profile())->extension_service();
    468   service->set_show_extensions_prompts(false);
    469   size_t num_before = service->extensions()->size();
    470 
    471   {
    472     scoped_ptr<ExtensionInstallPrompt> install_ui;
    473     if (ui_type == INSTALL_UI_TYPE_CANCEL) {
    474       install_ui.reset(new MockAbortExtensionInstallPrompt());
    475     } else if (ui_type == INSTALL_UI_TYPE_NORMAL) {
    476       install_ui.reset(new ExtensionInstallPrompt(
    477           browser->tab_strip_model()->GetActiveWebContents()));
    478     } else if (ui_type == INSTALL_UI_TYPE_AUTO_CONFIRM) {
    479       install_ui.reset(new MockAutoConfirmExtensionInstallPrompt(
    480           browser->tab_strip_model()->GetActiveWebContents()));
    481     }
    482 
    483     // TODO(tessamac): Update callers to always pass an unpacked extension
    484     //                 and then always pack the extension here.
    485     base::FilePath crx_path = path;
    486     if (crx_path.Extension() != FILE_PATH_LITERAL(".crx")) {
    487       crx_path = PackExtension(path);
    488     }
    489     if (crx_path.empty())
    490       return NULL;
    491 
    492     scoped_refptr<extensions::CrxInstaller> installer(
    493         extensions::CrxInstaller::Create(service, install_ui.Pass()));
    494     installer->set_expected_id(id);
    495     installer->set_creation_flags(creation_flags);
    496     installer->set_install_source(install_source);
    497     installer->set_install_immediately(install_immediately);
    498     installer->set_is_ephemeral(is_ephemeral);
    499     if (!installer->is_gallery_install()) {
    500       installer->set_off_store_install_allow_reason(
    501           extensions::CrxInstaller::OffStoreInstallAllowedInTest);
    502     }
    503 
    504     observer_->Watch(
    505         extensions::NOTIFICATION_CRX_INSTALLER_DONE,
    506         content::Source<extensions::CrxInstaller>(installer.get()));
    507 
    508     installer->InstallCrx(crx_path);
    509 
    510     observer_->Wait();
    511   }
    512 
    513   size_t num_after = service->extensions()->size();
    514   EXPECT_EQ(num_before + expected_change, num_after);
    515   if (num_before + expected_change != num_after) {
    516     VLOG(1) << "Num extensions before: " << base::IntToString(num_before)
    517             << " num after: " << base::IntToString(num_after)
    518             << " Installed extensions follow:";
    519 
    520     for (extensions::ExtensionSet::const_iterator it =
    521              service->extensions()->begin();
    522          it != service->extensions()->end(); ++it)
    523       VLOG(1) << "  " << (*it)->id();
    524 
    525     VLOG(1) << "Errors follow:";
    526     const std::vector<base::string16>* errors =
    527         ExtensionErrorReporter::GetInstance()->GetErrors();
    528     for (std::vector<base::string16>::const_iterator iter = errors->begin();
    529          iter != errors->end(); ++iter)
    530       VLOG(1) << *iter;
    531 
    532     return NULL;
    533   }
    534 
    535   if (!observer_->WaitForExtensionViewsToLoad())
    536     return NULL;
    537   return service->GetExtensionById(last_loaded_extension_id(), false);
    538 }
    539 
    540 void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) {
    541   observer_->Watch(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    542                    content::NotificationService::AllSources());
    543 
    544   ExtensionService* service =
    545       extensions::ExtensionSystem::Get(profile())->extension_service();
    546   service->ReloadExtension(extension_id);
    547 
    548   observer_->Wait();
    549   observer_->WaitForExtensionViewsToLoad();
    550 }
    551 
    552 void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
    553   ExtensionService* service = extensions::ExtensionSystem::Get(
    554       profile())->extension_service();
    555   service->UnloadExtension(extension_id,
    556                            extensions::UnloadedExtensionInfo::REASON_DISABLE);
    557 }
    558 
    559 void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
    560   ExtensionService* service = extensions::ExtensionSystem::Get(
    561       profile())->extension_service();
    562   service->UninstallExtension(extension_id,
    563                               extensions::UNINSTALL_REASON_FOR_TESTING,
    564                               base::Bind(&base::DoNothing),
    565                               NULL);
    566 }
    567 
    568 void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
    569   ExtensionService* service = extensions::ExtensionSystem::Get(
    570       profile())->extension_service();
    571   service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
    572 }
    573 
    574 void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
    575   ExtensionService* service = extensions::ExtensionSystem::Get(
    576       profile())->extension_service();
    577   service->EnableExtension(extension_id);
    578 }
    579 
    580 void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
    581                                       const GURL& url,
    582                                       bool newtab_process_should_equal_opener,
    583                                       content::WebContents** newtab_result) {
    584   content::WindowedNotificationObserver windowed_observer(
    585       content::NOTIFICATION_LOAD_STOP,
    586       content::NotificationService::AllSources());
    587   ASSERT_TRUE(content::ExecuteScript(contents,
    588                                      "window.open('" + url.spec() + "');"));
    589 
    590   // The above window.open call is not user-initiated, so it will create
    591   // a popup window instead of a new tab in current window.
    592   // The stop notification will come from the new tab.
    593   windowed_observer.Wait();
    594   content::NavigationController* controller =
    595       content::Source<content::NavigationController>(
    596           windowed_observer.source()).ptr();
    597   content::WebContents* newtab = controller->GetWebContents();
    598   ASSERT_TRUE(newtab);
    599   EXPECT_EQ(url, controller->GetLastCommittedEntry()->GetURL());
    600   if (newtab_process_should_equal_opener)
    601     EXPECT_EQ(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
    602   else
    603     EXPECT_NE(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
    604 
    605   if (newtab_result)
    606     *newtab_result = newtab;
    607 }
    608 
    609 void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
    610                                               const GURL& url) {
    611   bool result = false;
    612   content::WindowedNotificationObserver windowed_observer(
    613       content::NOTIFICATION_LOAD_STOP,
    614       content::NotificationService::AllSources());
    615   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
    616       contents,
    617       "window.addEventListener('unload', function() {"
    618       "    window.domAutomationController.send(true);"
    619       "}, false);"
    620       "window.location = '" + url.spec() + "';",
    621       &result));
    622   ASSERT_TRUE(result);
    623   windowed_observer.Wait();
    624   EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
    625 }
    626 
    627 extensions::ExtensionHost* ExtensionBrowserTest::FindHostWithPath(
    628     extensions::ProcessManager* manager,
    629     const std::string& path,
    630     int expected_hosts) {
    631   extensions::ExtensionHost* host = NULL;
    632   int num_hosts = 0;
    633   extensions::ProcessManager::ExtensionHostSet background_hosts =
    634       manager->background_hosts();
    635   for (extensions::ProcessManager::const_iterator iter =
    636            background_hosts.begin();
    637        iter != background_hosts.end();
    638        ++iter) {
    639     if ((*iter)->GetURL().path() == path) {
    640       EXPECT_FALSE(host);
    641       host = *iter;
    642     }
    643     num_hosts++;
    644   }
    645   EXPECT_EQ(expected_hosts, num_hosts);
    646   return host;
    647 }
    648 
    649 std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
    650     const std::string& extension_id,
    651     const std::string& script) {
    652   return extensions::browsertest_util::ExecuteScriptInBackgroundPage(
    653       profile(), extension_id, script);
    654 }
    655 
    656 bool ExtensionBrowserTest::ExecuteScriptInBackgroundPageNoWait(
    657     const std::string& extension_id,
    658     const std::string& script) {
    659   return extensions::browsertest_util::ExecuteScriptInBackgroundPageNoWait(
    660       profile(), extension_id, script);
    661 }
    662