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