Make the ChromeOS chromecast system tray integration use a private API.
[chromium-blink-merge.git] / chrome / browser / extensions / shared_module_service_unittest.cc
blob79baa35efad7519ebe0f94dbd5f95c6fd1db9af9
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 "chrome/browser/extensions/shared_module_service.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string16.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_service_test_base.h"
13 #include "chrome/browser/extensions/pending_extension_manager.h"
14 #include "chrome/common/extensions/features/feature_channel.h"
15 #include "components/crx_file/id_util.h"
16 #include "components/version_info/version_info.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/browser/install_flag.h"
19 #include "extensions/browser/uninstall_reason.h"
20 #include "extensions/common/extension_builder.h"
21 #include "extensions/common/value_builder.h"
22 #include "sync/api/string_ordinal.h"
24 namespace extensions {
26 namespace {
28 // Return an extension with |id| which imports a module with the given
29 // |import_id|.
30 scoped_refptr<Extension> CreateExtensionImportingModule(
31 const std::string& import_id,
32 const std::string& id,
33 const std::string& version) {
34 DictionaryBuilder builder;
35 builder.Set("name", "Has Dependent Modules")
36 .Set("version", version)
37 .Set("manifest_version", 2);
38 if (!import_id.empty()) {
39 builder.Set("import",
40 ListBuilder().Append(DictionaryBuilder().Set("id", import_id)));
42 scoped_ptr<base::DictionaryValue> manifest = builder.Build();
44 return ExtensionBuilder().SetManifest(manifest.Pass())
45 .AddFlags(Extension::FROM_WEBSTORE)
46 .SetID(id)
47 .Build();
50 } // namespace
52 class SharedModuleServiceUnitTest : public ExtensionServiceTestBase {
53 public:
54 SharedModuleServiceUnitTest() :
55 // The "export" key is open for dev-channel only, but unit tests
56 // run as stable channel on the official Windows build.
57 current_channel_(version_info::Channel::UNKNOWN) {}
58 protected:
59 void SetUp() override;
61 // Install an extension and notify the ExtensionService.
62 testing::AssertionResult InstallExtension(const Extension* extension,
63 bool is_update);
64 ScopedCurrentChannel current_channel_;
67 void SharedModuleServiceUnitTest::SetUp() {
68 ExtensionServiceTestBase::SetUp();
69 InitializeGoodInstalledExtensionService();
70 service()->Init();
73 testing::AssertionResult SharedModuleServiceUnitTest::InstallExtension(
74 const Extension* extension,
75 bool is_update) {
77 const Extension* old = registry()->GetExtensionById(
78 extension->id(),
79 ExtensionRegistry::ENABLED);
81 // Verify the extension is not already installed, if it is not update.
82 if (!is_update) {
83 if (old)
84 return testing::AssertionFailure() << "Extension already installed.";
85 } else {
86 if (!old)
87 return testing::AssertionFailure() << "The extension does not exist.";
90 // Notify the service that the extension is installed. This adds it to the
91 // registry, notifies interested parties, etc.
92 service()->OnExtensionInstalled(
93 extension, syncer::StringOrdinal(), kInstallFlagInstallImmediately);
95 // Verify that the extension is now installed.
96 if (!registry()->GetExtensionById(extension->id(),
97 ExtensionRegistry::ENABLED)) {
98 return testing::AssertionFailure() << "Could not install extension.";
101 return testing::AssertionSuccess();
104 TEST_F(SharedModuleServiceUnitTest, AddDependentSharedModules) {
105 // Create an extension that has a dependency.
106 std::string import_id = crx_file::id_util::GenerateId("id");
107 std::string extension_id = crx_file::id_util::GenerateId("extension_id");
108 scoped_refptr<Extension> extension =
109 CreateExtensionImportingModule(import_id, extension_id, "1.0");
111 PendingExtensionManager* pending_extension_manager =
112 service()->pending_extension_manager();
114 // Verify that we don't currently want to install the imported module.
115 EXPECT_FALSE(pending_extension_manager->IsIdPending(import_id));
117 // Try to satisfy imports for the extension. This should queue the imported
118 // module's installation.
119 service()->shared_module_service()->SatisfyImports(extension.get());
120 EXPECT_TRUE(pending_extension_manager->IsIdPending(import_id));
123 TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUninstall) {
124 // Create a module which exports a resource, and install it.
125 scoped_ptr<base::DictionaryValue> manifest =
126 DictionaryBuilder()
127 .Set("name", "Shared Module")
128 .Set("version", "1.0")
129 .Set("manifest_version", 2)
130 .Set("export",
131 DictionaryBuilder().Set("resources",
132 ListBuilder().Append("foo.js"))).Build();
133 scoped_refptr<Extension> shared_module =
134 ExtensionBuilder()
135 .SetManifest(manifest.Pass())
136 .AddFlags(Extension::FROM_WEBSTORE)
137 .SetID(crx_file::id_util::GenerateId("shared_module"))
138 .Build();
140 EXPECT_TRUE(InstallExtension(shared_module.get(), false));
142 std::string extension_id = crx_file::id_util::GenerateId("extension_id");
143 // Create and install an extension that imports our new module.
144 scoped_refptr<Extension> importing_extension =
145 CreateExtensionImportingModule(shared_module->id(), extension_id, "1.0");
146 EXPECT_TRUE(InstallExtension(importing_extension.get(), false));
148 // Uninstall the extension that imports our module.
149 base::string16 error;
150 service()->UninstallExtension(importing_extension->id(),
151 extensions::UNINSTALL_REASON_FOR_TESTING,
152 base::Bind(&base::DoNothing),
153 &error);
154 EXPECT_TRUE(error.empty());
156 // Since the module was only referenced by that single extension, it should
157 // have been uninstalled as a side-effect of uninstalling the extension that
158 // depended upon it.
159 EXPECT_FALSE(registry()->GetExtensionById(shared_module->id(),
160 ExtensionRegistry::EVERYTHING));
163 TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUpdate) {
164 // Create two modules which export a resource, and install them.
165 scoped_ptr<base::DictionaryValue> manifest_1 =
166 DictionaryBuilder()
167 .Set("name", "Shared Module 1")
168 .Set("version", "1.0")
169 .Set("manifest_version", 2)
170 .Set("export",
171 DictionaryBuilder().Set("resources",
172 ListBuilder().Append("foo.js"))).Build();
173 scoped_refptr<Extension> shared_module_1 =
174 ExtensionBuilder()
175 .SetManifest(manifest_1.Pass())
176 .AddFlags(Extension::FROM_WEBSTORE)
177 .SetID(crx_file::id_util::GenerateId("shared_module_1"))
178 .Build();
179 EXPECT_TRUE(InstallExtension(shared_module_1.get(), false));
181 scoped_ptr<base::DictionaryValue> manifest_2 =
182 DictionaryBuilder()
183 .Set("name", "Shared Module 2")
184 .Set("version", "1.0")
185 .Set("manifest_version", 2)
186 .Set("export",
187 DictionaryBuilder().Set("resources",
188 ListBuilder().Append("foo.js"))).Build();
189 scoped_refptr<Extension> shared_module_2 =
190 ExtensionBuilder()
191 .SetManifest(manifest_2.Pass())
192 .AddFlags(Extension::FROM_WEBSTORE)
193 .SetID(crx_file::id_util::GenerateId("shared_module_2"))
194 .Build();
195 EXPECT_TRUE(InstallExtension(shared_module_2.get(), false));
197 std::string extension_id = crx_file::id_util::GenerateId("extension_id");
199 // Create and install an extension v1.0 that imports our new module 1.
200 scoped_refptr<Extension> importing_extension_1 =
201 CreateExtensionImportingModule(shared_module_1->id(),
202 extension_id,
203 "1.0");
204 EXPECT_TRUE(InstallExtension(importing_extension_1.get(), false));
206 // Create and install a new version of the extension that imports our new
207 // module 2.
208 scoped_refptr<Extension> importing_extension_2 =
209 CreateExtensionImportingModule(shared_module_2->id(),
210 extension_id,
211 "1.1");
212 EXPECT_TRUE(InstallExtension(importing_extension_2.get(), true));
214 // Since the extension v1.1 depends the module 2 insteand module 1.
215 // So the module 1 should be uninstalled.
216 EXPECT_FALSE(registry()->GetExtensionById(shared_module_1->id(),
217 ExtensionRegistry::EVERYTHING));
218 EXPECT_TRUE(registry()->GetExtensionById(shared_module_2->id(),
219 ExtensionRegistry::EVERYTHING));
221 // Create and install a new version of the extension that does not import any
222 // module.
223 scoped_refptr<Extension> importing_extension_3 =
224 CreateExtensionImportingModule("", extension_id, "1.2");
225 EXPECT_TRUE(InstallExtension(importing_extension_3.get(), true));
227 // Since the extension v1.2 does not depend any module, so the all models
228 // should have been uninstalled.
229 EXPECT_FALSE(registry()->GetExtensionById(shared_module_1->id(),
230 ExtensionRegistry::EVERYTHING));
231 EXPECT_FALSE(registry()->GetExtensionById(shared_module_2->id(),
232 ExtensionRegistry::EVERYTHING));
236 TEST_F(SharedModuleServiceUnitTest, WhitelistedImports) {
237 std::string whitelisted_id = crx_file::id_util::GenerateId("whitelisted");
238 std::string nonwhitelisted_id =
239 crx_file::id_util::GenerateId("nonwhitelisted");
240 // Create a module which exports to a restricted whitelist.
241 scoped_ptr<base::DictionaryValue> manifest =
242 DictionaryBuilder()
243 .Set("name", "Shared Module")
244 .Set("version", "1.0")
245 .Set("manifest_version", 2)
246 .Set("export",
247 DictionaryBuilder().Set("whitelist",
248 ListBuilder()
249 .Append(whitelisted_id))
250 .Set("resources",
251 ListBuilder().Append("*"))).Build();
252 scoped_refptr<Extension> shared_module =
253 ExtensionBuilder()
254 .SetManifest(manifest.Pass())
255 .AddFlags(Extension::FROM_WEBSTORE)
256 .SetID(crx_file::id_util::GenerateId("shared_module"))
257 .Build();
259 EXPECT_TRUE(InstallExtension(shared_module.get(), false));
261 // Create and install an extension with the whitelisted ID.
262 scoped_refptr<Extension> whitelisted_extension =
263 CreateExtensionImportingModule(shared_module->id(),
264 whitelisted_id,
265 "1.0");
266 EXPECT_TRUE(InstallExtension(whitelisted_extension.get(), false));
268 // Try to install an extension with an ID that is not whitelisted.
269 scoped_refptr<Extension> nonwhitelisted_extension =
270 CreateExtensionImportingModule(shared_module->id(),
271 nonwhitelisted_id,
272 "1.0");
273 // This should succeed because only CRX installer (and by extension the
274 // WebStore Installer) checks the shared module whitelist. InstallExtension
275 // bypasses the whitelist check because the SharedModuleService does not
276 // care about whitelists.
277 EXPECT_TRUE(InstallExtension(nonwhitelisted_extension.get(), false));
280 } // namespace extensions