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