extension_browsertest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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_host.h" 24#include "chrome/browser/extensions/extension_install_prompt.h" 25#include "chrome/browser/extensions/extension_service.h" 26#include "chrome/browser/extensions/extension_system.h" 27#include "chrome/browser/extensions/unpacked_installer.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/omnibox/location_bar.h" 33#include "chrome/browser/ui/tabs/tab_strip_model.h" 34#include "chrome/common/chrome_paths.h" 35#include "chrome/common/chrome_switches.h" 36#include "chrome/common/chrome_version_info.h" 37#include "chrome/common/extensions/extension_set.h" 38#include "chrome/test/base/ui_test_utils.h" 39#include "content/public/browser/navigation_controller.h" 40#include "content/public/browser/navigation_entry.h" 41#include "content/public/browser/notification_registrar.h" 42#include "content/public/browser/notification_service.h" 43#include "content/public/browser/render_view_host.h" 44#include "content/public/test/browser_test_utils.h" 45#include "extensions/common/constants.h" 46#include "sync/api/string_ordinal.h" 47 48#if defined(OS_CHROMEOS) 49#include "chromeos/chromeos_switches.h" 50#endif 51 52using extensions::Extension; 53using extensions::ExtensionCreator; 54using extensions::FeatureSwitch; 55using extensions::Manifest; 56 57namespace { 58 59bool HasExtensionPageActionCountReachedTarget(LocationBarTesting* location_bar, 60 int target_page_action_count) { 61 VLOG(1) << "Number of page actions: " << location_bar->PageActionCount(); 62 return location_bar->PageActionCount() == target_page_action_count; 63} 64 65bool HasExtensionPageActionVisibilityReachedTarget( 66 LocationBarTesting* location_bar, 67 int target_visible_page_action_count) { 68 VLOG(1) << "Number of visible page actions: " 69 << location_bar->PageActionVisibleCount(); 70 return location_bar->PageActionVisibleCount() == 71 target_visible_page_action_count; 72} 73 74} // namespace 75 76ExtensionBrowserTest::ExtensionBrowserTest() 77 : loaded_(false), 78 installed_(false), 79 extension_installs_observed_(0), 80 extension_load_errors_observed_(0), 81 current_channel_(chrome::VersionInfo::CHANNEL_DEV), 82 override_prompt_for_external_extensions_( 83 FeatureSwitch::prompt_for_external_extensions(), false), 84 profile_(NULL) { 85 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); 86} 87 88ExtensionBrowserTest::~ExtensionBrowserTest() {} 89 90Profile* ExtensionBrowserTest::profile() { 91 if (!profile_) { 92 if (browser()) 93 profile_ = browser()->profile(); 94 else 95 profile_ = ProfileManager::GetDefaultProfile(); 96 } 97 return profile_; 98} 99 100// static 101const Extension* ExtensionBrowserTest::GetExtensionByPath( 102 const ExtensionSet* extensions, const base::FilePath& path) { 103 base::FilePath extension_path = base::MakeAbsoluteFilePath(path); 104 EXPECT_TRUE(!extension_path.empty()); 105 for (ExtensionSet::const_iterator iter = extensions->begin(); 106 iter != extensions->end(); ++iter) { 107 if ((*iter)->path() == extension_path) { 108 return iter->get(); 109 } 110 } 111 return NULL; 112} 113 114void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) { 115 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); 116 test_data_dir_ = test_data_dir_.AppendASCII("extensions"); 117 118#if defined(OS_CHROMEOS) 119 // This makes sure that we create the Default profile first, with no 120 // ExtensionService and then the real profile with one, as we do when 121 // running on chromeos. 122 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, 123 "TestUser@gmail.com"); 124 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 125#endif 126} 127 128void ExtensionBrowserTest::SetUpOnMainThread() { 129 InProcessBrowserTest::SetUpOnMainThread(); 130} 131 132const Extension* ExtensionBrowserTest::LoadExtensionWithFlags( 133 const base::FilePath& path, int flags) { 134 ExtensionService* service = extensions::ExtensionSystem::Get( 135 profile())->extension_service(); 136 { 137 content::WindowedNotificationObserver observer( 138 chrome::NOTIFICATION_EXTENSION_LOADED, 139 content::NotificationService::AllSources()); 140 content::NotificationRegistrar registrar; 141 registrar.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 142 content::NotificationService::AllSources()); 143 scoped_refptr<extensions::UnpackedInstaller> installer( 144 extensions::UnpackedInstaller::Create(service)); 145 installer->set_prompt_for_plugins(false); 146 installer->set_require_modern_manifest_version( 147 (flags & kFlagAllowOldManifestVersions) == 0); 148 installer->Load(path); 149 observer.Wait(); 150 } 151 152 // Find the loaded extension by its path. See crbug.com/59531 for why 153 // we cannot just use last_loaded_extension_id_. 154 const Extension* extension = GetExtensionByPath(service->extensions(), path); 155 if (!extension) 156 return NULL; 157 158 if (!(flags & kFlagIgnoreManifestWarnings)) { 159 const std::vector<extensions::InstallWarning>& install_warnings = 160 extension->install_warnings(); 161 if (!install_warnings.empty()) { 162 std::string install_warnings_message = base::StringPrintf( 163 "Unexpected warnings when loading test extension %s:\n", 164 path.AsUTF8Unsafe().c_str()); 165 166 for (std::vector<extensions::InstallWarning>::const_iterator it = 167 install_warnings.begin(); it != install_warnings.end(); ++it) { 168 install_warnings_message += " " + it->message + "\n"; 169 } 170 171 EXPECT_TRUE(extension->install_warnings().empty()) << 172 install_warnings_message; 173 return NULL; 174 } 175 } 176 177 const std::string extension_id = extension->id(); 178 179 // The call to OnExtensionInstalled ensures the other extension prefs 180 // are set up with the defaults. 181 service->extension_prefs()->OnExtensionInstalled( 182 extension, 183 Extension::ENABLED, 184 extensions::Blacklist::NOT_BLACKLISTED, 185 syncer::StringOrdinal::CreateInitialOrdinal()); 186 187 // Toggling incognito or file access will reload the extension, so wait for 188 // the reload and grab the new extension instance. The default state is 189 // incognito disabled and file access enabled, so we don't wait in those 190 // cases. 191 { 192 content::WindowedNotificationObserver load_signal( 193 chrome::NOTIFICATION_EXTENSION_LOADED, 194 content::Source<Profile>(profile())); 195 CHECK(!service->IsIncognitoEnabled(extension_id) || 196 extension->force_incognito_enabled()); 197 198 if (flags & kFlagEnableIncognito) { 199 service->SetIsIncognitoEnabled(extension_id, true); 200 load_signal.Wait(); 201 extension = service->GetExtensionById(extension_id, false); 202 CHECK(extension) << extension_id << " not found after reloading."; 203 } 204 } 205 206 { 207 content::WindowedNotificationObserver load_signal( 208 chrome::NOTIFICATION_EXTENSION_LOADED, 209 content::Source<Profile>(profile())); 210 CHECK(service->AllowFileAccess(extension)); 211 if (!(flags & kFlagEnableFileAccess)) { 212 service->SetAllowFileAccess(extension, false); 213 load_signal.Wait(); 214 extension = service->GetExtensionById(extension_id, false); 215 CHECK(extension) << extension_id << " not found after reloading."; 216 } 217 } 218 219 if (!WaitForExtensionViewsToLoad()) 220 return NULL; 221 222 return extension; 223} 224 225const Extension* ExtensionBrowserTest::LoadExtension( 226 const base::FilePath& path) { 227 return LoadExtensionWithFlags(path, kFlagEnableFileAccess); 228} 229 230const Extension* ExtensionBrowserTest::LoadExtensionIncognito( 231 const base::FilePath& path) { 232 return LoadExtensionWithFlags(path, 233 kFlagEnableFileAccess | kFlagEnableIncognito); 234} 235 236const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest( 237 const base::FilePath& path, 238 const base::FilePath::CharType* manifest_relative_path) { 239 ExtensionService* service = extensions::ExtensionSystem::Get( 240 profile())->extension_service(); 241 242 std::string manifest; 243 if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) { 244 return NULL; 245 } 246 247 std::string extension_id = service->component_loader()->Add(manifest, path); 248 const Extension* extension = service->extensions()->GetByID(extension_id); 249 if (!extension) 250 return NULL; 251 last_loaded_extension_id_ = extension->id(); 252 return extension; 253} 254 255const Extension* ExtensionBrowserTest::LoadExtensionAsComponent( 256 const base::FilePath& path) { 257 return LoadExtensionAsComponentWithManifest(path, 258 extensions::kManifestFilename); 259} 260 261base::FilePath ExtensionBrowserTest::PackExtension( 262 const base::FilePath& dir_path) { 263 base::FilePath crx_path = temp_dir_.path().AppendASCII("temp.crx"); 264 if (!base::DeleteFile(crx_path, false)) { 265 ADD_FAILURE() << "Failed to delete crx: " << crx_path.value(); 266 return base::FilePath(); 267 } 268 269 // Look for PEM files with the same name as the directory. 270 base::FilePath pem_path = 271 dir_path.ReplaceExtension(FILE_PATH_LITERAL(".pem")); 272 base::FilePath pem_path_out; 273 274 if (!base::PathExists(pem_path)) { 275 pem_path = base::FilePath(); 276 pem_path_out = crx_path.DirName().AppendASCII("temp.pem"); 277 if (!base::DeleteFile(pem_path_out, false)) { 278 ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value(); 279 return base::FilePath(); 280 } 281 } 282 283 return PackExtensionWithOptions(dir_path, crx_path, pem_path, pem_path_out); 284} 285 286base::FilePath ExtensionBrowserTest::PackExtensionWithOptions( 287 const base::FilePath& dir_path, 288 const base::FilePath& crx_path, 289 const base::FilePath& pem_path, 290 const base::FilePath& pem_out_path) { 291 if (!base::PathExists(dir_path)) { 292 ADD_FAILURE() << "Extension dir not found: " << dir_path.value(); 293 return base::FilePath(); 294 } 295 296 if (!base::PathExists(pem_path) && pem_out_path.empty()) { 297 ADD_FAILURE() << "Must specify a PEM file or PEM output path"; 298 return base::FilePath(); 299 } 300 301 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator()); 302 if (!creator->Run(dir_path, 303 crx_path, 304 pem_path, 305 pem_out_path, 306 ExtensionCreator::kOverwriteCRX)) { 307 ADD_FAILURE() << "ExtensionCreator::Run() failed: " 308 << creator->error_message(); 309 return base::FilePath(); 310 } 311 312 if (!base::PathExists(crx_path)) { 313 ADD_FAILURE() << crx_path.value() << " was not created."; 314 return base::FilePath(); 315 } 316 return crx_path; 317} 318 319// This class is used to simulate an installation abort by the user. 320class MockAbortExtensionInstallPrompt : public ExtensionInstallPrompt { 321 public: 322 MockAbortExtensionInstallPrompt() : ExtensionInstallPrompt(NULL) { 323 } 324 325 // Simulate a user abort on an extension installation. 326 virtual void ConfirmInstall( 327 Delegate* delegate, 328 const Extension* extension, 329 const ShowDialogCallback& show_dialog_callback) OVERRIDE { 330 delegate->InstallUIAbort(true); 331 base::MessageLoopForUI::current()->Quit(); 332 } 333 334 virtual void OnInstallSuccess(const Extension* extension, 335 SkBitmap* icon) OVERRIDE {} 336 337 virtual void OnInstallFailure( 338 const extensions::CrxInstallerError& error) OVERRIDE {} 339}; 340 341class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt { 342 public: 343 explicit MockAutoConfirmExtensionInstallPrompt( 344 content::WebContents* web_contents) 345 : ExtensionInstallPrompt(web_contents) {} 346 347 // Proceed without confirmation prompt. 348 virtual void ConfirmInstall( 349 Delegate* delegate, 350 const Extension* extension, 351 const ShowDialogCallback& show_dialog_callback) OVERRIDE { 352 delegate->InstallUIProceed(); 353 } 354}; 355 356const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle( 357 const std::string& id, 358 const base::FilePath& path, 359 int expected_change) { 360 return InstallOrUpdateExtension(id, 361 path, 362 INSTALL_UI_TYPE_NONE, 363 expected_change, 364 Manifest::INTERNAL, 365 browser(), 366 Extension::NO_FLAGS, 367 true); 368} 369 370const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore( 371 const base::FilePath& path, 372 int expected_change) { 373 return InstallOrUpdateExtension(std::string(), 374 path, 375 INSTALL_UI_TYPE_NONE, 376 expected_change, 377 Manifest::INTERNAL, 378 browser(), 379 Extension::FROM_WEBSTORE, 380 false); 381} 382 383const Extension* ExtensionBrowserTest::InstallOrUpdateExtension( 384 const std::string& id, 385 const base::FilePath& path, 386 InstallUIType ui_type, 387 int expected_change) { 388 return InstallOrUpdateExtension(id, path, ui_type, expected_change, 389 Manifest::INTERNAL, browser(), Extension::NO_FLAGS, false); 390} 391 392const Extension* ExtensionBrowserTest::InstallOrUpdateExtension( 393 const std::string& id, 394 const base::FilePath& path, 395 InstallUIType ui_type, 396 int expected_change, 397 Browser* browser, 398 Extension::InitFromValueFlags creation_flags) { 399 return InstallOrUpdateExtension(id, path, ui_type, expected_change, 400 Manifest::INTERNAL, browser, creation_flags, 401 false); 402} 403 404const Extension* ExtensionBrowserTest::InstallOrUpdateExtension( 405 const std::string& id, 406 const base::FilePath& path, 407 InstallUIType ui_type, 408 int expected_change, 409 Manifest::Location install_source) { 410 return InstallOrUpdateExtension(id, path, ui_type, expected_change, 411 install_source, browser(), Extension::NO_FLAGS, false); 412} 413 414const Extension* ExtensionBrowserTest::InstallOrUpdateExtension( 415 const std::string& id, 416 const base::FilePath& path, 417 InstallUIType ui_type, 418 int expected_change, 419 Manifest::Location install_source, 420 Browser* browser, 421 Extension::InitFromValueFlags creation_flags, 422 bool wait_for_idle) { 423 ExtensionService* service = profile()->GetExtensionService(); 424 service->set_show_extensions_prompts(false); 425 size_t num_before = service->extensions()->size(); 426 427 { 428 scoped_ptr<ExtensionInstallPrompt> install_ui; 429 if (ui_type == INSTALL_UI_TYPE_CANCEL) { 430 install_ui.reset(new MockAbortExtensionInstallPrompt()); 431 } else if (ui_type == INSTALL_UI_TYPE_NORMAL) { 432 install_ui.reset(new ExtensionInstallPrompt( 433 browser->tab_strip_model()->GetActiveWebContents())); 434 } else if (ui_type == INSTALL_UI_TYPE_AUTO_CONFIRM) { 435 install_ui.reset(new MockAutoConfirmExtensionInstallPrompt( 436 browser->tab_strip_model()->GetActiveWebContents())); 437 } 438 439 // TODO(tessamac): Update callers to always pass an unpacked extension 440 // and then always pack the extension here. 441 base::FilePath crx_path = path; 442 if (crx_path.Extension() != FILE_PATH_LITERAL(".crx")) { 443 crx_path = PackExtension(path); 444 } 445 if (crx_path.empty()) 446 return NULL; 447 448 scoped_refptr<extensions::CrxInstaller> installer( 449 extensions::CrxInstaller::Create(service, install_ui.Pass())); 450 installer->set_expected_id(id); 451 installer->set_creation_flags(creation_flags); 452 installer->set_install_source(install_source); 453 installer->set_install_wait_for_idle(wait_for_idle); 454 if (!installer->is_gallery_install()) { 455 installer->set_off_store_install_allow_reason( 456 extensions::CrxInstaller::OffStoreInstallAllowedInTest); 457 } 458 459 content::WindowedNotificationObserver observer( 460 chrome::NOTIFICATION_CRX_INSTALLER_DONE, 461 content::Source<extensions::CrxInstaller>(installer.get())); 462 content::NotificationRegistrar registrar; 463 registrar.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, 464 content::Source<extensions::CrxInstaller>(installer.get())); 465 466 installer->InstallCrx(crx_path); 467 468 observer.Wait(); 469 } 470 471 size_t num_after = service->extensions()->size(); 472 EXPECT_EQ(num_before + expected_change, num_after); 473 if (num_before + expected_change != num_after) { 474 VLOG(1) << "Num extensions before: " << base::IntToString(num_before) 475 << " num after: " << base::IntToString(num_after) 476 << " Installed extensions follow:"; 477 478 for (ExtensionSet::const_iterator it = service->extensions()->begin(); 479 it != service->extensions()->end(); ++it) 480 VLOG(1) << " " << (*it)->id(); 481 482 VLOG(1) << "Errors follow:"; 483 const std::vector<string16>* errors = 484 ExtensionErrorReporter::GetInstance()->GetErrors(); 485 for (std::vector<string16>::const_iterator iter = errors->begin(); 486 iter != errors->end(); ++iter) 487 VLOG(1) << *iter; 488 489 return NULL; 490 } 491 492 if (!WaitForExtensionViewsToLoad()) 493 return NULL; 494 return service->GetExtensionById(last_loaded_extension_id_, false); 495} 496 497void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) { 498 content::WindowedNotificationObserver observer( 499 chrome::NOTIFICATION_EXTENSION_LOADED, 500 content::NotificationService::AllSources()); 501 content::NotificationRegistrar registrar; 502 registrar.Add(this, 503 chrome::NOTIFICATION_EXTENSION_LOADED, 504 content::NotificationService::AllSources()); 505 ExtensionService* service = 506 extensions::ExtensionSystem::Get(profile())->extension_service(); 507 service->ReloadExtension(extension_id); 508 observer.Wait(); 509 WaitForExtensionViewsToLoad(); 510} 511 512void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) { 513 ExtensionService* service = extensions::ExtensionSystem::Get( 514 profile())->extension_service(); 515 service->UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_DISABLE); 516} 517 518void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) { 519 ExtensionService* service = extensions::ExtensionSystem::Get( 520 profile())->extension_service(); 521 service->UninstallExtension(extension_id, false, NULL); 522} 523 524void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) { 525 ExtensionService* service = extensions::ExtensionSystem::Get( 526 profile())->extension_service(); 527 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION); 528} 529 530void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) { 531 ExtensionService* service = extensions::ExtensionSystem::Get( 532 profile())->extension_service(); 533 service->EnableExtension(extension_id); 534} 535 536bool ExtensionBrowserTest::WaitForPageActionCountChangeTo(int count) { 537 LocationBarTesting* location_bar = 538 browser()->window()->GetLocationBar()->GetLocationBarForTesting(); 539 if (!HasExtensionPageActionCountReachedTarget(location_bar, count)) { 540 content::WindowedNotificationObserver( 541 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, 542 base::Bind( 543 &HasExtensionPageActionCountReachedTarget, location_bar, count)) 544 .Wait(); 545 } 546 return HasExtensionPageActionCountReachedTarget(location_bar, count); 547} 548 549bool ExtensionBrowserTest::WaitForPageActionVisibilityChangeTo(int count) { 550 LocationBarTesting* location_bar = 551 browser()->window()->GetLocationBar()->GetLocationBarForTesting(); 552 if (!HasExtensionPageActionVisibilityReachedTarget(location_bar, count)) { 553 content::WindowedNotificationObserver( 554 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, 555 base::Bind(&HasExtensionPageActionVisibilityReachedTarget, 556 location_bar, 557 count)) 558 .Wait(); 559 } 560 return HasExtensionPageActionVisibilityReachedTarget(location_bar, count); 561} 562 563void ExtensionBrowserTest::WaitForNotification(int notification_type) { 564 // TODO(bauerb): Using a WindowedNotificationObserver like this can break 565 // easily, if the notification we're waiting for is sent before this method. 566 // Change it so that the WindowedNotificationObserver is constructed earlier. 567 content::NotificationRegistrar registrar; 568 registrar.Add(this, notification_type, 569 content::NotificationService::AllSources()); 570 content::WindowedNotificationObserver( 571 notification_type, content::NotificationService::AllSources()).Wait(); 572} 573 574bool ExtensionBrowserTest::WaitForExtensionViewsToLoad() { 575 576 ExtensionProcessManager* manager = 577 extensions::ExtensionSystem::Get(profile())->process_manager(); 578 ExtensionProcessManager::ViewSet all_views = manager->GetAllViews(); 579 for (ExtensionProcessManager::ViewSet::const_iterator iter = 580 all_views.begin(); 581 iter != all_views.end();) { 582 if (!(*iter)->IsLoading()) { 583 ++iter; 584 } else { 585 // Wait for all the extension render view hosts that exist to finish 586 // loading. 587 content::WindowedNotificationObserver observer( 588 content::NOTIFICATION_LOAD_STOP, 589 content::NotificationService::AllSources()); 590 observer.AddNotificationType( 591 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 592 content::NotificationService::AllSources()); 593 observer.Wait(); 594 595 // Test activity may have modified the set of extension processes during 596 // message processing, so re-start the iteration to catch added/removed 597 // processes. 598 all_views = manager->GetAllViews(); 599 iter = all_views.begin(); 600 } 601 } 602 return true; 603} 604 605bool ExtensionBrowserTest::WaitForExtensionInstall() { 606 int before = extension_installs_observed_; 607 WaitForNotification(chrome::NOTIFICATION_EXTENSION_INSTALLED); 608 return extension_installs_observed_ == (before + 1); 609} 610 611bool ExtensionBrowserTest::WaitForExtensionInstallError() { 612 int before = extension_installs_observed_; 613 content::WindowedNotificationObserver( 614 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, 615 content::NotificationService::AllSources()).Wait(); 616 return extension_installs_observed_ == before; 617} 618 619void ExtensionBrowserTest::WaitForExtensionLoad() { 620 WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOADED); 621 WaitForExtensionViewsToLoad(); 622} 623 624bool ExtensionBrowserTest::WaitForExtensionLoadError() { 625 int before = extension_load_errors_observed_; 626 WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR); 627 return extension_load_errors_observed_ != before; 628} 629 630bool ExtensionBrowserTest::WaitForExtensionCrash( 631 const std::string& extension_id) { 632 ExtensionService* service = 633 extensions::ExtensionSystem::Get(profile())->extension_service(); 634 635 if (!service->GetExtensionById(extension_id, true)) { 636 // The extension is already unloaded, presumably due to a crash. 637 return true; 638 } 639 content::WindowedNotificationObserver( 640 chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 641 content::NotificationService::AllSources()).Wait(); 642 return (service->GetExtensionById(extension_id, true) == NULL); 643} 644 645bool ExtensionBrowserTest::WaitForCrxInstallerDone() { 646 int before = crx_installers_done_observed_; 647 WaitForNotification(chrome::NOTIFICATION_CRX_INSTALLER_DONE); 648 return crx_installers_done_observed_ == (before + 1); 649} 650 651void ExtensionBrowserTest::OpenWindow(content::WebContents* contents, 652 const GURL& url, 653 bool newtab_process_should_equal_opener, 654 content::WebContents** newtab_result) { 655 content::WindowedNotificationObserver observer( 656 content::NOTIFICATION_LOAD_STOP, 657 content::NotificationService::AllSources()); 658 ASSERT_TRUE(content::ExecuteScript(contents, 659 "window.open('" + url.spec() + "');")); 660 661 // The above window.open call is not user-initiated, so it will create 662 // a popup window instead of a new tab in current window. 663 // The stop notification will come from the new tab. 664 observer.Wait(); 665 content::NavigationController* controller = 666 content::Source<content::NavigationController>(observer.source()).ptr(); 667 content::WebContents* newtab = controller->GetWebContents(); 668 ASSERT_TRUE(newtab); 669 EXPECT_EQ(url, controller->GetLastCommittedEntry()->GetURL()); 670 if (newtab_process_should_equal_opener) 671 EXPECT_EQ(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost()); 672 else 673 EXPECT_NE(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost()); 674 675 if (newtab_result) 676 *newtab_result = newtab; 677} 678 679void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents, 680 const GURL& url) { 681 bool result = false; 682 content::WindowedNotificationObserver observer( 683 content::NOTIFICATION_LOAD_STOP, 684 content::NotificationService::AllSources()); 685 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 686 contents, 687 "window.addEventListener('unload', function() {" 688 " window.domAutomationController.send(true);" 689 "}, false);" 690 "window.location = '" + url.spec() + "';", 691 &result)); 692 ASSERT_TRUE(result); 693 observer.Wait(); 694 EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL()); 695} 696 697extensions::ExtensionHost* ExtensionBrowserTest::FindHostWithPath( 698 ExtensionProcessManager* manager, 699 const std::string& path, 700 int expected_hosts) { 701 extensions::ExtensionHost* host = NULL; 702 int num_hosts = 0; 703 ExtensionProcessManager::ExtensionHostSet background_hosts = 704 manager->background_hosts(); 705 for (ExtensionProcessManager::const_iterator iter = background_hosts.begin(); 706 iter != background_hosts.end(); ++iter) { 707 if ((*iter)->GetURL().path() == path) { 708 EXPECT_FALSE(host); 709 host = *iter; 710 } 711 num_hosts++; 712 } 713 EXPECT_EQ(expected_hosts, num_hosts); 714 return host; 715} 716 717std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage( 718 const std::string& extension_id, 719 const std::string& script) { 720 return extensions::browsertest_util::ExecuteScriptInBackgroundPage( 721 profile(), extension_id, script); 722} 723 724void ExtensionBrowserTest::Observe( 725 int type, 726 const content::NotificationSource& source, 727 const content::NotificationDetails& details) { 728 switch (type) { 729 case chrome::NOTIFICATION_EXTENSION_LOADED: 730 last_loaded_extension_id_ = 731 content::Details<const Extension>(details).ptr()->id(); 732 VLOG(1) << "Got EXTENSION_LOADED notification."; 733 break; 734 735 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: 736 VLOG(1) << "Got CRX_INSTALLER_DONE notification."; 737 { 738 const Extension* extension = 739 content::Details<const Extension>(details).ptr(); 740 if (extension) 741 last_loaded_extension_id_ = extension->id(); 742 else 743 last_loaded_extension_id_.clear(); 744 } 745 ++crx_installers_done_observed_; 746 break; 747 748 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 749 VLOG(1) << "Got EXTENSION_INSTALLED notification."; 750 ++extension_installs_observed_; 751 break; 752 753 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: 754 VLOG(1) << "Got EXTENSION_LOAD_ERROR notification."; 755 ++extension_load_errors_observed_; 756 break; 757 758 default: 759 NOTREACHED(); 760 break; 761 } 762} 763