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