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 <stddef.h>
8 
9 #include <utility>
10 #include <vector>
11 
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/path_service.h"
18 #include "base/run_loop.h"
19 #include "base/strings/strcat.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/task/post_task.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "build/build_config.h"
26 #include "chrome/browser/apps/app_service/app_launch_params.h"
27 #include "chrome/browser/apps/app_service/app_service_proxy.h"
28 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
29 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
30 #include "chrome/browser/extensions/browsertest_util.h"
31 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
32 #include "chrome/browser/extensions/component_loader.h"
33 #include "chrome/browser/extensions/crx_installer.h"
34 #include "chrome/browser/extensions/extension_install_prompt.h"
35 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
36 #include "chrome/browser/extensions/extension_service.h"
37 #include "chrome/browser/extensions/extension_util.h"
38 #include "chrome/browser/extensions/load_error_reporter.h"
39 #include "chrome/browser/extensions/unpacked_installer.h"
40 #include "chrome/browser/extensions/updater/extension_updater.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/profiles/profile_manager.h"
43 #include "chrome/browser/ui/browser.h"
44 #include "chrome/browser/ui/browser_list.h"
45 #include "chrome/browser/ui/browser_window.h"
46 #include "chrome/browser/ui/extensions/extension_message_bubble_factory.h"
47 #include "chrome/browser/ui/tabs/tab_strip_model.h"
48 #include "chrome/common/chrome_paths.h"
49 #include "chrome/common/chrome_switches.h"
50 #include "components/crx_file/crx_verifier.h"
51 #include "components/sync/model/string_ordinal.h"
52 #include "components/version_info/version_info.h"
53 #include "content/public/browser/navigation_controller.h"
54 #include "content/public/browser/navigation_entry.h"
55 #include "content/public/browser/notification_registrar.h"
56 #include "content/public/browser/notification_service.h"
57 #include "content/public/browser/render_frame_host.h"
58 #include "content/public/browser/render_view_host.h"
59 #include "content/public/test/browser_test_utils.h"
60 #include "content/public/test/test_utils.h"
61 #include "extensions/browser/browsertest_util.h"
62 #include "extensions/browser/disable_reason.h"
63 #include "extensions/browser/extension_dialog_auto_confirm.h"
64 #include "extensions/browser/extension_host.h"
65 #include "extensions/browser/extension_prefs.h"
66 #include "extensions/browser/extension_registry.h"
67 #include "extensions/browser/extension_system.h"
68 #include "extensions/browser/notification_types.h"
69 #include "extensions/browser/test_extension_registry_observer.h"
70 #include "extensions/browser/uninstall_reason.h"
71 #include "extensions/browser/updater/extension_cache_fake.h"
72 #include "extensions/common/constants.h"
73 #include "extensions/common/extension_set.h"
74 #include "extensions/common/file_test_util.h"
75 #include "extensions/common/file_util.h"
76 #include "extensions/common/switches.h"
77 #include "extensions/common/value_builder.h"
78 
79 #if defined(OS_CHROMEOS)
80 #include "chromeos/constants/chromeos_switches.h"
81 #endif
82 
83 namespace extensions {
84 
85 namespace {
86 
87 // Maps all chrome-extension://<id>/_test_resources/foo requests to
88 // <test_dir_root>/foo or <test_dir_gen_root>/foo, where |test_dir_gen_root| is
89 // inferred from <test_dir_root>. The latter is triggered only if the first path
90 // does not correspond to an existing file. This is what allows us to share code
91 // between tests without needing to duplicate files in each extension.
92 // Example invocation #1, where the requested file exists in |test_dir_root|
93 //   Input:
94 //     test_dir_root: /abs/path/src/chrome/test/data
95 //     directory_path: /abs/path/src/out/<out_dir>/resources/pdf
96 //     relative_path: _test_resources/webui/test_browser_proxy.js
97 //   Output:
98 //     directory_path: /abs/path/src/chrome/test/data
99 //     relative_path: webui/test_browser_proxy.js
100 //
101 // Example invocation #2, where the requested file exists in |test_dir_gen_root|
102 //   Input:
103 //     test_dir_root: /abs/path/src/chrome/test/data
104 //     directory_path: /abs/path/src/out/<out_dir>/resources/pdf
105 //     relative_path: _test_resources/webui/test_browser_proxy.js
106 //   Output:
107 //     directory_path: /abs/path/src/out/<out_dir>/gen/chrome/test/data
108 //     relative_path: webui/test_browser_proxy.js
ExtensionProtocolTestResourcesHandler(const base::FilePath & test_dir_root,base::FilePath * directory_path,base::FilePath * relative_path)109 void ExtensionProtocolTestResourcesHandler(const base::FilePath& test_dir_root,
110                                            base::FilePath* directory_path,
111                                            base::FilePath* relative_path) {
112   // Only map paths that begin with _test_resources.
113   if (!base::FilePath(FILE_PATH_LITERAL("_test_resources"))
114            .IsParent(*relative_path)) {
115     return;
116   }
117 
118   // Strip the '_test_resources/' prefix from |relative_path|.
119   std::vector<base::FilePath::StringType> components;
120   relative_path->GetComponents(&components);
121   DCHECK_GT(components.size(), 1u);
122   base::FilePath new_relative_path;
123   for (size_t i = 1u; i < components.size(); ++i)
124     new_relative_path = new_relative_path.Append(components[i]);
125   *relative_path = new_relative_path;
126 
127   // Check if the file exists in the |test_dir_root| folder first.
128   base::FilePath src_path = test_dir_root.Append(new_relative_path);
129   // Replace _test_resources/foo with <test_dir_root>/foo.
130   *directory_path = test_dir_root;
131   {
132     base::ScopedAllowBlockingForTesting scoped_allow_blocking;
133     if (base::PathExists(src_path)) {
134       return;
135     }
136   }
137 
138   // Infer |test_dir_gen_root| from |test_dir_root|.
139   // E.g., if |test_dir_root| is /abs/path/src/chrome/test/data,
140   // |test_dir_gen_root| will be /abs/path/out/<out_dir>/gen/chrome/test/data.
141   base::FilePath dir_source_root;
142   base::PathService::Get(base::DIR_SOURCE_ROOT, &dir_source_root);
143   base::FilePath exe_dir;
144   base::PathService::Get(base::DIR_EXE, &exe_dir);
145   base::FilePath relative_root_path;
146   dir_source_root.AppendRelativePath(test_dir_root, &relative_root_path);
147   // TODO(dpapad): Add a new DIR_GEN key to PathService instead of manually
148   // appending "gen".
149   base::FilePath test_dir_gen_root =
150       exe_dir.AppendASCII("gen").Append(relative_root_path);
151 
152   // Then check if the file exists in the |test_dir_gen_root| folder
153   // covering cases where the test file is generated at build time.
154   base::FilePath gen_path = test_dir_gen_root.Append(new_relative_path);
155   {
156     base::ScopedAllowBlockingForTesting scoped_allow_blocking;
157     if (base::PathExists(gen_path)) {
158       *directory_path = test_dir_gen_root;
159     }
160   }
161 }
162 
163 }  // namespace
164 
ExtensionBrowserTest()165 ExtensionBrowserTest::ExtensionBrowserTest()
166     :
167 #if defined(OS_CHROMEOS)
168       set_chromeos_user_(true),
169 #endif
170       // Default channel is STABLE but override with UNKNOWN so that unlaunched
171       // or incomplete APIs can write tests.
172       current_channel_(version_info::Channel::UNKNOWN),
173       override_prompt_for_external_extensions_(
174           FeatureSwitch::prompt_for_external_extensions(),
175           false),
176 #if defined(OS_WIN)
177       user_desktop_override_(base::DIR_USER_DESKTOP),
178       common_desktop_override_(base::DIR_COMMON_DESKTOP),
179       user_quick_launch_override_(base::DIR_USER_QUICK_LAUNCH),
180       start_menu_override_(base::DIR_START_MENU),
181       common_start_menu_override_(base::DIR_COMMON_START_MENU),
182 #endif
183       profile_(nullptr),
184       verifier_format_override_(crx_file::VerifierFormat::CRX3) {
185   EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
186 }
187 
~ExtensionBrowserTest()188 ExtensionBrowserTest::~ExtensionBrowserTest() {
189 }
190 
profile()191 Profile* ExtensionBrowserTest::profile() {
192   if (!profile_) {
193     if (browser())
194       profile_ = browser()->profile();
195     else
196       profile_ = ProfileManager::GetActiveUserProfile();
197   }
198   return profile_;
199 }
200 
ShouldEnableContentVerification()201 bool ExtensionBrowserTest::ShouldEnableContentVerification() {
202   return false;
203 }
204 
ShouldEnableInstallVerification()205 bool ExtensionBrowserTest::ShouldEnableInstallVerification() {
206   return false;
207 }
208 
GetTestResourcesParentDir()209 base::FilePath ExtensionBrowserTest::GetTestResourcesParentDir() {
210   // Don't use |test_data_dir_| here (even though it points to
211   // chrome/test/data/extensions by default) because subclasses have the ability
212   // to alter it by overriding the SetUpCommandLine() method.
213   base::FilePath test_root_path;
214   base::PathService::Get(chrome::DIR_TEST_DATA, &test_root_path);
215   return test_root_path.AppendASCII("extensions");
216 }
217 
218 // static
GetExtensionByPath(const ExtensionSet & extensions,const base::FilePath & path)219 const Extension* ExtensionBrowserTest::GetExtensionByPath(
220     const ExtensionSet& extensions,
221     const base::FilePath& path) {
222   base::ScopedAllowBlockingForTesting allow_blocking;
223   base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
224   EXPECT_TRUE(!extension_path.empty());
225   for (const scoped_refptr<const Extension>& extension : extensions) {
226     if (extension->path() == extension_path) {
227       return extension.get();
228     }
229   }
230   return NULL;
231 }
232 
SetUp()233 void ExtensionBrowserTest::SetUp() {
234   test_extension_cache_.reset(new ExtensionCacheFake());
235   InProcessBrowserTest::SetUp();
236 }
237 
SetUpCommandLine(base::CommandLine * command_line)238 void ExtensionBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
239   base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
240   test_data_dir_ = test_data_dir_.AppendASCII("extensions");
241 
242   // We don't want any warning bubbles for, e.g., unpacked extensions.
243   ExtensionMessageBubbleFactory::set_override_for_tests(
244       ExtensionMessageBubbleFactory::OVERRIDE_DISABLED);
245 
246   if (!ShouldEnableContentVerification()) {
247     ignore_content_verification_.reset(
248         new ScopedIgnoreContentVerifierForTest());
249   }
250 
251   if (!ShouldEnableInstallVerification()) {
252     ignore_install_verification_.reset(
253         new ScopedInstallVerifierBypassForTest());
254   }
255 
256 #if defined(OS_CHROMEOS)
257   if (set_chromeos_user_) {
258     // This makes sure that we create the Default profile first, with no
259     // ExtensionService and then the real profile with one, as we do when
260     // running on chromeos.
261     command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
262                                     "testuser@gmail.com");
263     command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
264   }
265 #endif
266 }
267 
SetUpOnMainThread()268 void ExtensionBrowserTest::SetUpOnMainThread() {
269   observer_.reset(new ChromeExtensionTestNotificationObserver(browser()));
270   if (extension_service()->updater()) {
271     extension_service()->updater()->SetExtensionCacheForTesting(
272         test_extension_cache_.get());
273   }
274 
275   test_protocol_handler_ = base::Bind(&ExtensionProtocolTestResourcesHandler,
276                                       GetTestResourcesParentDir());
277   SetExtensionProtocolTestHandler(&test_protocol_handler_);
278 }
279 
TearDownOnMainThread()280 void ExtensionBrowserTest::TearDownOnMainThread() {
281   ExtensionMessageBubbleFactory::set_override_for_tests(
282       ExtensionMessageBubbleFactory::NO_OVERRIDE);
283   SetExtensionProtocolTestHandler(nullptr);
284 }
285 
LoadExtension(const base::FilePath & path)286 const Extension* ExtensionBrowserTest::LoadExtension(
287     const base::FilePath& path) {
288   return LoadExtensionWithFlags(path, kFlagEnableFileAccess);
289 }
290 
LoadExtensionIncognito(const base::FilePath & path)291 const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
292     const base::FilePath& path) {
293   return LoadExtensionWithFlags(path,
294                                 kFlagEnableFileAccess | kFlagEnableIncognito);
295 }
296 
LoadExtensionWithFlags(const base::FilePath & path,int flags)297 const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
298     const base::FilePath& path, int flags) {
299   base::FilePath extension_path = path;
300   if (flags & kFlagRunAsServiceWorkerBasedExtension) {
301     if (!CreateServiceWorkerBasedExtension(path, &extension_path))
302       return nullptr;
303   }
304   return LoadExtensionWithInstallParam(extension_path, flags, std::string());
305 }
306 
LoadExtensionWithInstallParam(const base::FilePath & path,int flags,const std::string & install_param)307 const Extension* ExtensionBrowserTest::LoadExtensionWithInstallParam(
308     const base::FilePath& path,
309     int flags,
310     const std::string& install_param) {
311   // Make sure there aren't any stray bits in "flags." This could happen
312   // if someone inadvertently used any of the ExtensionApiTest flag values.
313   CHECK_LT(flags, kFlagNextValue);
314   ChromeTestExtensionLoader loader(profile());
315   loader.set_require_modern_manifest_version(
316       (flags & kFlagAllowOldManifestVersions) == 0);
317   loader.set_ignore_manifest_warnings(flags & kFlagIgnoreManifestWarnings);
318   loader.set_allow_incognito_access(flags & kFlagEnableIncognito);
319   loader.set_allow_file_access(flags & kFlagEnableFileAccess);
320   loader.set_install_param(install_param);
321 
322   // Note: Rely on the default value to wait for renderers unless otherwise
323   // specified.
324   if (flags & kFlagDontWaitForExtensionRenderers)
325     loader.set_wait_for_renderers(false);
326 
327   if ((flags & kFlagLoadForLoginScreen) != 0) {
328     loader.add_creation_flag(Extension::FOR_LOGIN_SCREEN);
329     loader.set_location(Manifest::EXTERNAL_POLICY);
330   }
331   scoped_refptr<const Extension> extension = loader.LoadExtension(path);
332   if (extension)
333     observer_->set_last_loaded_extension_id(extension->id());
334   return extension.get();
335 }
336 
CreateServiceWorkerBasedExtension(const base::FilePath & path,base::FilePath * out_path)337 bool ExtensionBrowserTest::CreateServiceWorkerBasedExtension(
338     const base::FilePath& path,
339     base::FilePath* out_path) {
340   base::ScopedAllowBlockingForTesting allow_blocking;
341 
342   // This dir will contain all files for the Service Worker based extension.
343   base::FilePath temp_extension_container;
344   if (!base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
345                                      base::FilePath::StringType(),
346                                      &temp_extension_container)) {
347     ADD_FAILURE() << "Could not create temporary dir for test under "
348                   << temp_dir_.GetPath();
349     return false;
350   }
351 
352   // Copy all files from test dir to temp dir.
353   if (!base::CopyDirectory(path, temp_extension_container,
354                            true /* recursive */)) {
355     ADD_FAILURE() << path.value() << " could not be copied to "
356                   << temp_extension_container.value();
357     return false;
358   }
359 
360   const base::FilePath extension_root =
361       temp_extension_container.Append(path.BaseName());
362 
363   std::string error;
364   std::unique_ptr<base::DictionaryValue> manifest_dict =
365       file_util::LoadManifest(extension_root, &error);
366   if (!manifest_dict) {
367     ADD_FAILURE() << path.value() << " could not load manifest: " << error;
368     return false;
369   }
370 
371   // Retrieve the value of the "background" key and verify that it is
372   // non-persistent and specifies JS files.
373   // Persistent background pages or background pages that specify HTML files
374   // are not supported.
375   base::Value* background_dict =
376       manifest_dict->FindKeyOfType("background", base::Value::Type::DICTIONARY);
377   if (!background_dict) {
378     ADD_FAILURE() << path.value()
379                   << " 'background' key not found in manifest.json";
380     return false;
381   }
382   {
383     base::Value* background_persistent = background_dict->FindKeyOfType(
384         "persistent", base::Value::Type::BOOLEAN);
385     if (!background_persistent) {
386       ADD_FAILURE() << path.value()
387                     << ": The \"persistent\" key must be specified to run as a "
388                        "Service Worker-based extension.";
389       return false;
390     }
391   }
392   base::Value* background_scripts_list =
393       background_dict->FindKeyOfType("scripts", base::Value::Type::LIST);
394   if (!background_scripts_list) {
395     ADD_FAILURE() << path.value()
396                   << ": Only event pages with JS script(s) can be loaded "
397                      "as SW extension.";
398     return false;
399   }
400 
401   // Number of JS scripts must be > 1.
402   base::Value::ConstListView scripts_list = background_scripts_list->GetList();
403   if (scripts_list.size() < 1) {
404     ADD_FAILURE() << path.value()
405                   << ": Only event pages with JS script(s) can be loaded "
406                      " as SW extension.";
407     return false;
408   }
409 
410   // Generate combined script as Service Worker script using importScripts().
411   constexpr const char kGeneratedSWFileName[] = "generated_service_worker__.js";
412 
413   std::vector<std::string> script_filenames;
414   for (const base::Value& script : scripts_list)
415     script_filenames.push_back(base::StrCat({"'", script.GetString(), "'"}));
416 
417   base::FilePath combined_script_filepath =
418       extension_root.AppendASCII(kGeneratedSWFileName);
419   // Collision with generated script filename.
420   if (base::PathExists(combined_script_filepath)) {
421     ADD_FAILURE() << combined_script_filepath.value()
422                   << " already exists, make sure " << path.value()
423                   << " does not contained file named " << kGeneratedSWFileName;
424     return false;
425   }
426   std::string generated_sw_script_content = base::StringPrintf(
427       "importScripts(%s);", base::JoinString(script_filenames, ",").c_str());
428   if (!file_test_util::WriteFile(combined_script_filepath,
429                                  generated_sw_script_content)) {
430     ADD_FAILURE() << "Could not write combined Service Worker script to: "
431                   << combined_script_filepath.value();
432     return false;
433   }
434 
435   // Remove the existing background specification and replace it with a service
436   // worker.
437   background_dict->RemoveKey("persistent");
438   background_dict->RemoveKey("scripts");
439   background_dict->SetStringPath("service_worker", kGeneratedSWFileName);
440 
441   // Write out manifest.json.
442   DictionaryBuilder manifest_builder(*manifest_dict);
443   std::string manifest_contents = manifest_builder.ToJSON();
444   base::FilePath manifest_path = extension_root.Append(kManifestFilename);
445   if (!file_test_util::WriteFile(manifest_path, manifest_contents)) {
446     ADD_FAILURE() << "Could not write manifest file to "
447                   << manifest_path.value();
448     return false;
449   }
450 
451   *out_path = extension_root;
452   return true;
453 }
454 
LoadExtensionAsComponentWithManifest(const base::FilePath & path,const base::FilePath::CharType * manifest_relative_path)455 const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
456     const base::FilePath& path,
457     const base::FilePath::CharType* manifest_relative_path) {
458   base::ScopedAllowBlockingForTesting allow_blocking;
459   std::string manifest;
460   if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) {
461     return NULL;
462   }
463 
464   extension_service()->component_loader()->set_ignore_allowlist_for_testing(
465       true);
466   std::string extension_id =
467       extension_service()->component_loader()->Add(manifest, path);
468   const Extension* extension =
469       extension_registry()->enabled_extensions().GetByID(extension_id);
470   if (!extension)
471     return NULL;
472   observer_->set_last_loaded_extension_id(extension->id());
473   return extension;
474 }
475 
LoadExtensionAsComponent(const base::FilePath & path)476 const Extension* ExtensionBrowserTest::LoadExtensionAsComponent(
477     const base::FilePath& path) {
478   return LoadExtensionAsComponentWithManifest(path, kManifestFilename);
479 }
480 
LoadAndLaunchApp(const base::FilePath & path)481 const Extension* ExtensionBrowserTest::LoadAndLaunchApp(
482     const base::FilePath& path) {
483   const Extension* app = LoadExtension(path);
484   CHECK(app);
485   content::WindowedNotificationObserver app_loaded_observer(
486       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
487       content::NotificationService::AllSources());
488   apps::AppLaunchParams params(app->id(), LaunchContainer::kLaunchContainerNone,
489                                WindowOpenDisposition::NEW_WINDOW,
490                                AppLaunchSource::kSourceTest);
491   params.command_line = *base::CommandLine::ForCurrentProcess();
492   apps::AppServiceProxyFactory::GetForProfile(profile())
493       ->BrowserAppLauncher()
494       ->LaunchAppWithParams(std::move(params));
495   app_loaded_observer.Wait();
496 
497   return app;
498 }
499 
LaunchAppBrowser(const Extension * extension)500 Browser* ExtensionBrowserTest::LaunchAppBrowser(const Extension* extension) {
501   return browsertest_util::LaunchAppBrowser(profile(), extension);
502 }
503 
PackExtension(const base::FilePath & dir_path,int extra_run_flags)504 base::FilePath ExtensionBrowserTest::PackExtension(
505     const base::FilePath& dir_path,
506     int extra_run_flags) {
507   base::ScopedAllowBlockingForTesting allow_blocking;
508   base::FilePath crx_path = temp_dir_.GetPath().AppendASCII("temp.crx");
509   if (!base::DeleteFile(crx_path)) {
510     ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
511     return base::FilePath();
512   }
513 
514   // Look for PEM files with the same name as the directory.
515   base::FilePath pem_path =
516       dir_path.ReplaceExtension(FILE_PATH_LITERAL(".pem"));
517   base::FilePath pem_path_out;
518 
519   if (!base::PathExists(pem_path)) {
520     pem_path = base::FilePath();
521     pem_path_out = crx_path.DirName().AppendASCII("temp.pem");
522     if (!base::DeleteFile(pem_path_out)) {
523       ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value();
524       return base::FilePath();
525     }
526   }
527 
528   return PackExtensionWithOptions(dir_path, crx_path, pem_path, pem_path_out,
529                                   extra_run_flags);
530 }
531 
PackExtensionWithOptions(const base::FilePath & dir_path,const base::FilePath & crx_path,const base::FilePath & pem_path,const base::FilePath & pem_out_path,int extra_run_flags)532 base::FilePath ExtensionBrowserTest::PackExtensionWithOptions(
533     const base::FilePath& dir_path,
534     const base::FilePath& crx_path,
535     const base::FilePath& pem_path,
536     const base::FilePath& pem_out_path,
537     int extra_run_flags) {
538   base::ScopedAllowBlockingForTesting allow_blocking;
539   if (!base::PathExists(dir_path)) {
540     ADD_FAILURE() << "Extension dir not found: " << dir_path.value();
541     return base::FilePath();
542   }
543 
544   if (!base::PathExists(pem_path) && pem_out_path.empty()) {
545     ADD_FAILURE() << "Must specify a PEM file or PEM output path";
546     return base::FilePath();
547   }
548 
549   std::unique_ptr<ExtensionCreator> creator(new ExtensionCreator());
550   if (!creator->Run(dir_path, crx_path, pem_path, pem_out_path,
551                     extra_run_flags | ExtensionCreator::kOverwriteCRX)) {
552     ADD_FAILURE() << "ExtensionCreator::Run() failed: "
553                   << creator->error_message();
554     return base::FilePath();
555   }
556 
557   if (!base::PathExists(crx_path)) {
558     ADD_FAILURE() << crx_path.value() << " was not created.";
559     return base::FilePath();
560   }
561   return crx_path;
562 }
563 
UpdateExtensionWaitForIdle(const std::string & id,const base::FilePath & path,int expected_change)564 const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
565     const std::string& id,
566     const base::FilePath& path,
567     int expected_change) {
568   return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE,
569                                   expected_change, Manifest::INTERNAL,
570                                   browser(), Extension::NO_FLAGS, false, false);
571 }
572 
InstallExtensionFromWebstore(const base::FilePath & path,int expected_change)573 const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore(
574     const base::FilePath& path,
575     int expected_change) {
576   return InstallOrUpdateExtension(
577       std::string(), path, INSTALL_UI_TYPE_AUTO_CONFIRM, expected_change,
578       Manifest::INTERNAL, browser(), Extension::FROM_WEBSTORE, true, false);
579 }
580 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change)581 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
582     const std::string& id,
583     const base::FilePath& path,
584     InstallUIType ui_type,
585     int expected_change) {
586   return InstallOrUpdateExtension(id, path, ui_type, expected_change,
587                                   Manifest::INTERNAL, browser(),
588                                   Extension::NO_FLAGS, true, false);
589 }
590 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change,Browser * browser,Extension::InitFromValueFlags creation_flags)591 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
592     const std::string& id,
593     const base::FilePath& path,
594     InstallUIType ui_type,
595     int expected_change,
596     Browser* browser,
597     Extension::InitFromValueFlags creation_flags) {
598   return InstallOrUpdateExtension(id, path, ui_type, expected_change,
599                                   Manifest::INTERNAL, browser, creation_flags,
600                                   true, false);
601 }
602 
InstallOrUpdateExtension(const std::string & id,const base::FilePath & path,InstallUIType ui_type,int expected_change,Manifest::Location install_source)603 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
604     const std::string& id,
605     const base::FilePath& path,
606     InstallUIType ui_type,
607     int expected_change,
608     Manifest::Location install_source) {
609   return InstallOrUpdateExtension(id, path, ui_type, expected_change,
610                                   install_source, browser(),
611                                   Extension::NO_FLAGS, true, false);
612 }
613 
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 grant_permissions)614 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
615     const std::string& id,
616     const base::FilePath& path,
617     InstallUIType ui_type,
618     int expected_change,
619     Manifest::Location install_source,
620     Browser* browser,
621     Extension::InitFromValueFlags creation_flags,
622     bool install_immediately,
623     bool grant_permissions) {
624   ExtensionRegistry* registry = extension_registry();
625   size_t num_before = registry->enabled_extensions().size();
626 
627   {
628     std::unique_ptr<ScopedTestDialogAutoConfirm> prompt_auto_confirm;
629     if (ui_type == INSTALL_UI_TYPE_CANCEL) {
630       prompt_auto_confirm.reset(new ScopedTestDialogAutoConfirm(
631           ScopedTestDialogAutoConfirm::CANCEL));
632     } else if (ui_type == INSTALL_UI_TYPE_NORMAL) {
633       prompt_auto_confirm.reset(new ScopedTestDialogAutoConfirm(
634           ScopedTestDialogAutoConfirm::NONE));
635     } else if (ui_type == INSTALL_UI_TYPE_AUTO_CONFIRM) {
636       prompt_auto_confirm.reset(new ScopedTestDialogAutoConfirm(
637           ScopedTestDialogAutoConfirm::ACCEPT));
638     }
639 
640     // TODO(tessamac): Update callers to always pass an unpacked extension
641     //                 and then always pack the extension here.
642     base::FilePath crx_path = path;
643     if (crx_path.Extension() != FILE_PATH_LITERAL(".crx")) {
644       int run_flags = ExtensionCreator::kNoRunFlags;
645       if (creation_flags & Extension::FROM_BOOKMARK) {
646         run_flags = ExtensionCreator::kBookmarkApp;
647         if (install_source == Manifest::EXTERNAL_COMPONENT)
648           run_flags |= ExtensionCreator::kSystemApp;
649       }
650 
651       crx_path = PackExtension(path, run_flags);
652     }
653     if (crx_path.empty())
654       return NULL;
655 
656     std::unique_ptr<ExtensionInstallPrompt> install_ui;
657     if (prompt_auto_confirm) {
658       install_ui.reset(new ExtensionInstallPrompt(
659          browser->tab_strip_model()->GetActiveWebContents()));
660     }
661     scoped_refptr<CrxInstaller> installer(
662         CrxInstaller::Create(extension_service(), std::move(install_ui)));
663     installer->set_expected_id(id);
664     installer->set_creation_flags(creation_flags);
665     installer->set_install_source(install_source);
666     installer->set_install_immediately(install_immediately);
667     installer->set_allow_silent_install(grant_permissions);
668     if (!installer->is_gallery_install()) {
669       installer->set_off_store_install_allow_reason(
670           CrxInstaller::OffStoreInstallAllowedInTest);
671     }
672 
673     observer_->Watch(NOTIFICATION_CRX_INSTALLER_DONE,
674                      content::Source<CrxInstaller>(installer.get()));
675 
676     installer->InstallCrx(crx_path);
677 
678     observer_->Wait();
679   }
680 
681   size_t num_after = registry->enabled_extensions().size();
682   EXPECT_EQ(num_before + expected_change, num_after);
683   if (num_before + expected_change != num_after) {
684     VLOG(1) << "Num extensions before: " << base::NumberToString(num_before)
685             << " num after: " << base::NumberToString(num_after)
686             << " Installed extensions follow:";
687 
688     for (const scoped_refptr<const Extension>& extension :
689          registry->enabled_extensions())
690       VLOG(1) << "  " << extension->id();
691 
692     VLOG(1) << "Errors follow:";
693     const std::vector<base::string16>* errors =
694         LoadErrorReporter::GetInstance()->GetErrors();
695     for (auto iter = errors->begin(); iter != errors->end(); ++iter)
696       VLOG(1) << *iter;
697 
698     return NULL;
699   }
700 
701   if (!observer_->WaitForExtensionViewsToLoad())
702     return NULL;
703   return registry->GetExtensionById(last_loaded_extension_id(),
704                                     ExtensionRegistry::ENABLED);
705 }
706 
ReloadExtension(const std::string & extension_id)707 void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) {
708   const Extension* extension =
709       extension_registry()->GetInstalledExtension(extension_id);
710   ASSERT_TRUE(extension);
711   TestExtensionRegistryObserver observer(extension_registry(), extension_id);
712   extension_service()->ReloadExtension(extension_id);
713   observer.WaitForExtensionLoaded();
714 
715   // We need to let other ExtensionRegistryObservers handle the extension load
716   // in order to finish initialization. This has to be done before waiting for
717   // extension views to load, since we only register views after observing
718   // extension load.
719   base::RunLoop().RunUntilIdle();
720   observer_->WaitForExtensionViewsToLoad();
721 }
722 
UnloadExtension(const std::string & extension_id)723 void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
724   extension_service()->UnloadExtension(extension_id,
725                                        UnloadedExtensionReason::DISABLE);
726 }
727 
UninstallExtension(const std::string & extension_id)728 void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
729   extension_service()->UninstallExtension(
730       extension_id, UNINSTALL_REASON_FOR_TESTING, nullptr);
731 }
732 
DisableExtension(const std::string & extension_id)733 void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
734   extension_service()->DisableExtension(extension_id,
735                                         disable_reason::DISABLE_USER_ACTION);
736 }
737 
EnableExtension(const std::string & extension_id)738 void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
739   extension_service()->EnableExtension(extension_id);
740 }
741 
OpenWindow(content::WebContents * contents,const GURL & url,bool newtab_process_should_equal_opener,bool should_succeed,content::WebContents ** newtab_result)742 void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
743                                       const GURL& url,
744                                       bool newtab_process_should_equal_opener,
745                                       bool should_succeed,
746                                       content::WebContents** newtab_result) {
747   content::WebContentsAddedObserver tab_added_observer;
748   ASSERT_TRUE(content::ExecuteScript(contents,
749                                      "window.open('" + url.spec() + "');"));
750   content::WebContents* newtab = tab_added_observer.GetWebContents();
751   ASSERT_TRUE(newtab);
752   WaitForLoadStop(newtab);
753 
754   if (should_succeed) {
755     EXPECT_EQ(url, newtab->GetLastCommittedURL());
756     EXPECT_EQ(content::PAGE_TYPE_NORMAL,
757               newtab->GetController().GetLastCommittedEntry()->GetPageType());
758   } else {
759     // "Failure" comes in two forms: redirecting to about:blank or showing an
760     // error page. At least one should be true.
761     EXPECT_TRUE(
762         newtab->GetLastCommittedURL() == GURL(url::kAboutBlankURL) ||
763         newtab->GetController().GetLastCommittedEntry()->GetPageType() ==
764             content::PAGE_TYPE_ERROR);
765   }
766 
767   if (newtab_process_should_equal_opener) {
768     EXPECT_EQ(contents->GetMainFrame()->GetSiteInstance(),
769               newtab->GetMainFrame()->GetSiteInstance());
770   } else {
771     EXPECT_NE(contents->GetMainFrame()->GetSiteInstance(),
772               newtab->GetMainFrame()->GetSiteInstance());
773   }
774 
775   if (newtab_result)
776     *newtab_result = newtab;
777 }
778 
NavigateInRenderer(content::WebContents * contents,const GURL & url)779 void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
780                                               const GURL& url) {
781   // Note: We use ExecuteScript instead of ExecJS here, because ExecuteScript
782   // works on pages with a Content Security Policy.
783   EXPECT_TRUE(content::ExecuteScript(
784       contents, "window.location = '" + url.spec() + "';"));
785   content::WaitForLoadStop(contents);
786   EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
787 }
788 
FindHostWithPath(ProcessManager * manager,const std::string & path,int expected_hosts)789 ExtensionHost* ExtensionBrowserTest::FindHostWithPath(ProcessManager* manager,
790                                                       const std::string& path,
791                                                       int expected_hosts) {
792   ExtensionHost* result_host = nullptr;
793   int num_hosts = 0;
794   for (ExtensionHost* host : manager->background_hosts()) {
795     if (host->GetLastCommittedURL().path() == path) {
796       EXPECT_FALSE(result_host);
797       result_host = host;
798     }
799     num_hosts++;
800   }
801   EXPECT_EQ(expected_hosts, num_hosts);
802   return result_host;
803 }
804 
ExecuteScriptInBackgroundPage(const std::string & extension_id,const std::string & script,browsertest_util::ScriptUserActivation script_user_activation)805 std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
806     const std::string& extension_id,
807     const std::string& script,
808     browsertest_util::ScriptUserActivation script_user_activation) {
809   return browsertest_util::ExecuteScriptInBackgroundPage(
810       profile(), extension_id, script, script_user_activation);
811 }
812 
ExecuteScriptInBackgroundPageNoWait(const std::string & extension_id,const std::string & script)813 bool ExtensionBrowserTest::ExecuteScriptInBackgroundPageNoWait(
814     const std::string& extension_id,
815     const std::string& script) {
816   return browsertest_util::ExecuteScriptInBackgroundPageNoWait(
817       profile(), extension_id, script);
818 }
819 
820 }  // namespace extensions
821