• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ExtensionBrowserTest()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 
~ExtensionBrowserTest()75 ExtensionBrowserTest::~ExtensionBrowserTest() {
76 }
77 
profile()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
GetExtensionByPath(const extensions::ExtensionSet * extensions,const base::FilePath & path)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 
SetUp()102 void ExtensionBrowserTest::SetUp() {
103   test_extension_cache_.reset(new extensions::ExtensionCacheFake());
104   InProcessBrowserTest::SetUp();
105 }
106 
SetUpCommandLine(CommandLine * command_line)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@gmail.com");
119     command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
120   }
121 #endif
122 }
123 
SetUpOnMainThread()124 void ExtensionBrowserTest::SetUpOnMainThread() {
125   InProcessBrowserTest::SetUpOnMainThread();
126   observer_.reset(new ExtensionTestNotificationObserver(browser()));
127 }
128 
LoadExtension(const base::FilePath & path)129 const Extension* ExtensionBrowserTest::LoadExtension(
130     const base::FilePath& path) {
131   return LoadExtensionWithFlags(path, kFlagEnableFileAccess);
132 }
133 
LoadExtensionIncognito(const base::FilePath & path)134 const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
135     const base::FilePath& path) {
136   return LoadExtensionWithFlags(path,
137                                 kFlagEnableFileAccess | kFlagEnableIncognito);
138 }
139 
LoadExtensionWithFlags(const base::FilePath & path,int flags)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*
LoadExtensionWithInstallParam(const base::FilePath & path,int flags,const std::string & install_param)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 
LoadExtensionAsComponentWithManifest(const base::FilePath & path,const base::FilePath::CharType * manifest_relative_path)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 
LoadExtensionAsComponent(const base::FilePath & path)267 const Extension* ExtensionBrowserTest::LoadExtensionAsComponent(
268     const base::FilePath& path) {
269   return LoadExtensionAsComponentWithManifest(path,
270                                               extensions::kManifestFilename);
271 }
272 
PackExtension(const base::FilePath & dir_path)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 
PackExtensionWithOptions(const base::FilePath & dir_path,const base::FilePath & crx_path,const base::FilePath & pem_path,const base::FilePath & pem_out_path)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:
MockAbortExtensionInstallPrompt()334   MockAbortExtensionInstallPrompt() : ExtensionInstallPrompt(NULL) {
335   }
336 
337   // Simulate a user abort on an extension installation.
ConfirmInstall(Delegate * delegate,const Extension * extension,const ShowDialogCallback & show_dialog_callback)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 
OnInstallSuccess(const Extension * extension,SkBitmap * icon)346   virtual void OnInstallSuccess(const Extension* extension,
347                                 SkBitmap* icon) OVERRIDE {}
348 
OnInstallFailure(const extensions::CrxInstallerError & error)349   virtual void OnInstallFailure(
350       const extensions::CrxInstallerError& error) OVERRIDE {}
351 };
352 
353 class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt {
354  public:
MockAutoConfirmExtensionInstallPrompt(content::WebContents * web_contents)355   explicit MockAutoConfirmExtensionInstallPrompt(
356       content::WebContents* web_contents)
357     : ExtensionInstallPrompt(web_contents) {}
358 
359   // Proceed without confirmation prompt.
ConfirmInstall(Delegate * delegate,const Extension * extension,const ShowDialogCallback & show_dialog_callback)360   virtual void ConfirmInstall(
361       Delegate* delegate,
362       const Extension* extension,
363       const ShowDialogCallback& show_dialog_callback) OVERRIDE {
364     delegate->InstallUIProceed();
365   }
366 };
367 
UpdateExtensionWaitForIdle(const std::string & id,const base::FilePath & path,int expected_change)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 
InstallExtensionFromWebstore(const base::FilePath & path,int expected_change)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 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change)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 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change,Browser * browser,Extension::InitFromValueFlags creation_flags)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 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change,Manifest::Location install_source)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 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change,Manifest::Location install_source,Browser * browser,Extension::InitFromValueFlags creation_flags,bool install_immediately,bool is_ephemeral)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 
ReloadExtension(const std::string extension_id)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 
UnloadExtension(const std::string & extension_id)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 
UninstallExtension(const std::string & extension_id)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 
DisableExtension(const std::string & extension_id)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 
EnableExtension(const std::string & extension_id)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 
OpenWindow(content::WebContents * contents,const GURL & url,bool newtab_process_should_equal_opener,content::WebContents ** newtab_result)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 
NavigateInRenderer(content::WebContents * contents,const GURL & url)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 
FindHostWithPath(extensions::ProcessManager * manager,const std::string & path,int expected_hosts)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 
ExecuteScriptInBackgroundPage(const std::string & extension_id,const std::string & script)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 
ExecuteScriptInBackgroundPageNoWait(const std::string & extension_id,const std::string & script)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