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