1 // Copyright 2014 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.
5 #include "base/memory/ref_counted.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/strings/string16.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_service_unittest.h"
11 #include "chrome/browser/extensions/pending_extension_manager.h"
12 #include "chrome/browser/extensions/shared_module_service.h"
13 #include "chrome/common/extensions/features/feature_channel.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/common/extension_builder.h"
16 #include "extensions/common/id_util.h"
17 #include "extensions/common/value_builder.h"
18 #include "sync/api/string_ordinal.h"
20 namespace extensions {
24 // Return an extension with |id| which imports a module with the given
26 scoped_refptr<Extension> CreateExtensionImportingModule(
27 const std::string& import_id, const std::string& id) {
28 scoped_ptr<base::DictionaryValue> manifest =
30 .Set("name", "Has Dependent Modules")
31 .Set("version", "1.0")
32 .Set("manifest_version", 2)
34 ListBuilder().Append(DictionaryBuilder().Set("id", import_id)))
37 return ExtensionBuilder().SetManifest(manifest.Pass())
38 .AddFlags(Extension::FROM_WEBSTORE)
45 class SharedModuleServiceUnitTest : public ExtensionServiceTestBase {
47 SharedModuleServiceUnitTest() :
48 // The "export" key is open for dev-channel only, but unit tests
49 // run as stable channel on the official Windows build.
50 current_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN) {}
52 virtual void SetUp() OVERRIDE;
54 // Install an extension and notify the ExtensionService.
55 testing::AssertionResult InstallExtension(const Extension* extension);
56 ScopedCurrentChannel current_channel_;
59 void SharedModuleServiceUnitTest::SetUp() {
60 ExtensionServiceTestBase::SetUp();
61 InitializeGoodInstalledExtensionService();
65 testing::AssertionResult SharedModuleServiceUnitTest::InstallExtension(
66 const Extension* extension) {
67 // Verify the extension is not already installed.
68 if (registry_->GetExtensionById(extension->id(),
69 ExtensionRegistry::ENABLED)) {
70 return testing::AssertionFailure() << "Extension already installed.";
73 // Notify the service that the extension is installed. This adds it to the
74 // registry, notifies interested parties, etc.
75 service_->OnExtensionInstalled(extension,
76 syncer::StringOrdinal(),
77 false, // No requirement errors.
79 false); // Don't wait for idle.
81 // Verify that the extension is now installed.
82 if (!registry_->GetExtensionById(extension->id(),
83 ExtensionRegistry::ENABLED)) {
84 return testing::AssertionFailure() << "Could not install extension.";
87 return testing::AssertionSuccess();
90 TEST_F(SharedModuleServiceUnitTest, AddDependentSharedModules) {
91 // Create an extension that has a dependency.
92 std::string import_id = id_util::GenerateId("id");
93 std::string extension_id = id_util::GenerateId("extension_id");
94 scoped_refptr<Extension> extension =
95 CreateExtensionImportingModule(import_id, extension_id);
97 PendingExtensionManager* pending_extension_manager =
98 service_->pending_extension_manager();
100 // Verify that we don't currently want to install the imported module.
101 EXPECT_FALSE(pending_extension_manager->IsIdPending(import_id));
103 // Try to satisfy imports for the extension. This should queue the imported
104 // module's installation.
105 service_->shared_module_service()->SatisfyImports(extension);
106 EXPECT_TRUE(pending_extension_manager->IsIdPending(import_id));
109 TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUninstall) {
110 // Create a module which exports a resource, and install it.
111 scoped_ptr<base::DictionaryValue> manifest =
113 .Set("name", "Shared Module")
114 .Set("version", "1.0")
115 .Set("manifest_version", 2)
117 DictionaryBuilder().Set("resources",
118 ListBuilder().Append("foo.js"))).Build();
119 scoped_refptr<Extension> shared_module =
120 ExtensionBuilder().SetManifest(manifest.Pass())
121 .AddFlags(Extension::FROM_WEBSTORE)
122 .SetID(id_util::GenerateId("shared_module"))
125 EXPECT_TRUE(InstallExtension(shared_module));
127 std::string extension_id = id_util::GenerateId("extension_id");
128 // Create and install an extension that imports our new module.
129 scoped_refptr<Extension> importing_extension =
130 CreateExtensionImportingModule(shared_module->id(), extension_id);
131 EXPECT_TRUE(InstallExtension(importing_extension));
133 // Uninstall the extension that imports our module.
134 base::string16 error;
135 service_->UninstallExtension(importing_extension->id(),
136 false, // Not external uninstall.
138 EXPECT_TRUE(error.empty());
140 // Since the module was only referenced by that single extension, it should
141 // have been uninstalled as a side-effect of uninstalling the extension that
143 EXPECT_FALSE(registry_->GetExtensionById(shared_module->id(),
144 ExtensionRegistry::EVERYTHING));
147 TEST_F(SharedModuleServiceUnitTest, WhitelistedImports) {
148 std::string whitelisted_id = id_util::GenerateId("whitelisted");
149 std::string nonwhitelisted_id = id_util::GenerateId("nonwhitelisted");
150 // Create a module which exports to a restricted whitelist.
151 scoped_ptr<base::DictionaryValue> manifest =
153 .Set("name", "Shared Module")
154 .Set("version", "1.0")
155 .Set("manifest_version", 2)
157 DictionaryBuilder().Set("whitelist",
159 .Append(whitelisted_id))
161 ListBuilder().Append("*"))).Build();
162 scoped_refptr<Extension> shared_module =
163 ExtensionBuilder().SetManifest(manifest.Pass())
164 .AddFlags(Extension::FROM_WEBSTORE)
165 .SetID(id_util::GenerateId("shared_module"))
168 EXPECT_TRUE(InstallExtension(shared_module));
170 // Create and install an extension with the whitelisted ID.
171 scoped_refptr<Extension> whitelisted_extension =
172 CreateExtensionImportingModule(shared_module->id(), whitelisted_id);
173 EXPECT_TRUE(InstallExtension(whitelisted_extension));
175 // Try to install an extension with an ID that is not whitelisted.
176 scoped_refptr<Extension> nonwhitelisted_extension =
177 CreateExtensionImportingModule(shared_module->id(), nonwhitelisted_id);
178 EXPECT_FALSE(InstallExtension(nonwhitelisted_extension));
181 } // namespace extensions