[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 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 | |
sdefresne | 9fb6769 | 2015-08-03 18:48:22 | [diff] [blame] | 5 | #include "chrome/browser/extensions/shared_module_service.h" |
| 6 | |
dcheng | c963c714 | 2016-04-08 03:55:22 | [diff] [blame] | 7 | #include <memory> |
limasdf | 3d10254 | 2015-12-09 03:58:45 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 10 | #include "base/memory/ref_counted.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 11 | #include "base/strings/string16.h" |
| 12 | #include "base/values.h" |
| 13 | #include "chrome/browser/extensions/extension_service.h" |
[email protected] | f484f8d5 | 2014-06-12 08:38:18 | [diff] [blame] | 14 | #include "chrome/browser/extensions/extension_service_test_base.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 15 | #include "chrome/browser/extensions/pending_extension_manager.h" |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 16 | #include "components/crx_file/id_util.h" |
skym | 7160384 | 2016-10-10 18:17:31 | [diff] [blame] | 17 | #include "components/sync/model/string_ordinal.h" |
sdefresne | 9fb6769 | 2015-08-03 18:48:22 | [diff] [blame] | 18 | #include "components/version_info/version_info.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 19 | #include "extensions/browser/extension_registry.h" |
[email protected] | 4a1d9c0d | 2014-06-13 12:50:11 | [diff] [blame] | 20 | #include "extensions/browser/install_flag.h" |
[email protected] | e43c61f | 2014-07-20 21:46:34 | [diff] [blame] | 21 | #include "extensions/browser/uninstall_reason.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 22 | #include "extensions/common/extension_builder.h" |
rdevlin.cronin | 4122753 | 2016-07-13 21:24:34 | [diff] [blame] | 23 | #include "extensions/common/features/feature_channel.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 24 | #include "extensions/common/value_builder.h" |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 25 | |
| 26 | namespace extensions { |
| 27 | |
| 28 | namespace { |
| 29 | |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 30 | // Return an extension with |id| which imports all the modules that are in the |
| 31 | // container |import_ids|. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 32 | scoped_refptr<const Extension> CreateExtensionImportingModules( |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 33 | const std::vector<std::string>& import_ids, |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 34 | const std::string& id, |
| 35 | const std::string& version) { |
| 36 | DictionaryBuilder builder; |
| 37 | builder.Set("name", "Has Dependent Modules") |
| 38 | .Set("version", version) |
| 39 | .Set("manifest_version", 2); |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 40 | if (!import_ids.empty()) { |
| 41 | ListBuilder import_list; |
| 42 | for (const std::string& id : import_ids) |
| 43 | import_list.Append(DictionaryBuilder().Set("id", id).Build()); |
| 44 | builder.Set("import", import_list.Build()); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 45 | } |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 46 | return ExtensionBuilder() |
| 47 | .SetManifest(builder.Build()) |
| 48 | .AddFlags(Extension::FROM_WEBSTORE) |
| 49 | .SetID(id) |
| 50 | .Build(); |
| 51 | } |
| 52 | |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 53 | scoped_refptr<const Extension> CreateSharedModule( |
| 54 | const std::string& module_id) { |
dcheng | c963c714 | 2016-04-08 03:55:22 | [diff] [blame] | 55 | std::unique_ptr<base::DictionaryValue> manifest = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 56 | DictionaryBuilder() |
| 57 | .Set("name", "Shared Module") |
| 58 | .Set("version", "1.0") |
| 59 | .Set("manifest_version", 2) |
| 60 | .Set("export", |
| 61 | DictionaryBuilder() |
| 62 | .Set("resources", ListBuilder().Append("foo.js").Build()) |
| 63 | .Build()) |
| 64 | .Build(); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 65 | |
dcheng | 1fc00f1 | 2015-12-26 22:18:03 | [diff] [blame] | 66 | return ExtensionBuilder() |
| 67 | .SetManifest(std::move(manifest)) |
| 68 | .AddFlags(Extension::FROM_WEBSTORE) |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 69 | .SetID(crx_file::id_util::GenerateId(module_id)) |
dcheng | 1fc00f1 | 2015-12-26 22:18:03 | [diff] [blame] | 70 | .Build(); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | } // namespace |
| 74 | |
| 75 | class SharedModuleServiceUnitTest : public ExtensionServiceTestBase { |
[email protected] | f043dba8 | 2014-05-09 17:13:48 | [diff] [blame] | 76 | public: |
| 77 | SharedModuleServiceUnitTest() : |
| 78 | // The "export" key is open for dev-channel only, but unit tests |
| 79 | // run as stable channel on the official Windows build. |
sdefresne | 6e883e4 | 2015-07-30 08:05:54 | [diff] [blame] | 80 | current_channel_(version_info::Channel::UNKNOWN) {} |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 81 | protected: |
dcheng | 7219181 | 2014-10-28 20:49:56 | [diff] [blame] | 82 | void SetUp() override; |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 83 | |
| 84 | // Install an extension and notify the ExtensionService. |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 85 | testing::AssertionResult InstallExtension(const Extension* extension, |
| 86 | bool is_update); |
[email protected] | f043dba8 | 2014-05-09 17:13:48 | [diff] [blame] | 87 | ScopedCurrentChannel current_channel_; |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 88 | }; |
| 89 | |
| 90 | void SharedModuleServiceUnitTest::SetUp() { |
| 91 | ExtensionServiceTestBase::SetUp(); |
| 92 | InitializeGoodInstalledExtensionService(); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 93 | service()->Init(); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | testing::AssertionResult SharedModuleServiceUnitTest::InstallExtension( |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 97 | const Extension* extension, |
| 98 | bool is_update) { |
| 99 | |
| 100 | const Extension* old = registry()->GetExtensionById( |
| 101 | extension->id(), |
| 102 | ExtensionRegistry::ENABLED); |
| 103 | |
| 104 | // Verify the extension is not already installed, if it is not update. |
| 105 | if (!is_update) { |
| 106 | if (old) |
| 107 | return testing::AssertionFailure() << "Extension already installed."; |
| 108 | } else { |
| 109 | if (!old) |
| 110 | return testing::AssertionFailure() << "The extension does not exist."; |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | // Notify the service that the extension is installed. This adds it to the |
| 114 | // registry, notifies interested parties, etc. |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 115 | service()->OnExtensionInstalled( |
[email protected] | 4a1d9c0d | 2014-06-13 12:50:11 | [diff] [blame] | 116 | extension, syncer::StringOrdinal(), kInstallFlagInstallImmediately); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 117 | |
| 118 | // Verify that the extension is now installed. |
[email protected] | f484f8d5 | 2014-06-12 08:38:18 | [diff] [blame] | 119 | if (!registry()->GetExtensionById(extension->id(), |
| 120 | ExtensionRegistry::ENABLED)) { |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 121 | return testing::AssertionFailure() << "Could not install extension."; |
| 122 | } |
| 123 | |
| 124 | return testing::AssertionSuccess(); |
| 125 | } |
| 126 | |
| 127 | TEST_F(SharedModuleServiceUnitTest, AddDependentSharedModules) { |
| 128 | // Create an extension that has a dependency. |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 129 | std::string import_id = crx_file::id_util::GenerateId("id"); |
| 130 | std::string extension_id = crx_file::id_util::GenerateId("extension_id"); |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 131 | scoped_refptr<const Extension> extension = CreateExtensionImportingModules( |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 132 | std::vector<std::string>(1, import_id), extension_id, "1.0"); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 133 | |
| 134 | PendingExtensionManager* pending_extension_manager = |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 135 | service()->pending_extension_manager(); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 136 | |
| 137 | // Verify that we don't currently want to install the imported module. |
| 138 | EXPECT_FALSE(pending_extension_manager->IsIdPending(import_id)); |
| 139 | |
| 140 | // Try to satisfy imports for the extension. This should queue the imported |
| 141 | // module's installation. |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 142 | service()->shared_module_service()->SatisfyImports(extension.get()); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 143 | EXPECT_TRUE(pending_extension_manager->IsIdPending(import_id)); |
| 144 | } |
| 145 | |
| 146 | TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUninstall) { |
| 147 | // Create a module which exports a resource, and install it. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 148 | scoped_refptr<const Extension> shared_module = |
| 149 | CreateSharedModule("shared_module"); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 150 | |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 151 | EXPECT_TRUE(InstallExtension(shared_module.get(), false)); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 152 | |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 153 | std::string extension_id = crx_file::id_util::GenerateId("extension_id"); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 154 | // Create and install an extension that imports our new module. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 155 | scoped_refptr<const Extension> importing_extension = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 156 | CreateExtensionImportingModules( |
| 157 | std::vector<std::string>(1, shared_module->id()), extension_id, |
| 158 | "1.0"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 159 | EXPECT_TRUE(InstallExtension(importing_extension.get(), false)); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 160 | |
| 161 | // Uninstall the extension that imports our module. |
| 162 | base::string16 error; |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 163 | service()->UninstallExtension(importing_extension->id(), |
[email protected] | e43c61f | 2014-07-20 21:46:34 | [diff] [blame] | 164 | extensions::UNINSTALL_REASON_FOR_TESTING, |
| 165 | &error); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 166 | EXPECT_TRUE(error.empty()); |
| 167 | |
| 168 | // Since the module was only referenced by that single extension, it should |
| 169 | // have been uninstalled as a side-effect of uninstalling the extension that |
| 170 | // depended upon it. |
[email protected] | f484f8d5 | 2014-06-12 08:38:18 | [diff] [blame] | 171 | EXPECT_FALSE(registry()->GetExtensionById(shared_module->id(), |
| 172 | ExtensionRegistry::EVERYTHING)); |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 173 | } |
| 174 | |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 175 | TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUpdate) { |
| 176 | // Create two modules which export a resource, and install them. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 177 | scoped_refptr<const Extension> shared_module_1 = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 178 | CreateSharedModule("shared_module_1"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 179 | EXPECT_TRUE(InstallExtension(shared_module_1.get(), false)); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 180 | |
dcheng | c963c714 | 2016-04-08 03:55:22 | [diff] [blame] | 181 | std::unique_ptr<base::DictionaryValue> manifest_2 = |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 182 | DictionaryBuilder() |
| 183 | .Set("name", "Shared Module 2") |
| 184 | .Set("version", "1.0") |
| 185 | .Set("manifest_version", 2) |
| 186 | .Set("export", |
dcheng | 794d2bd | 2016-02-27 03:51:32 | [diff] [blame] | 187 | DictionaryBuilder() |
| 188 | .Set("resources", ListBuilder().Append("foo.js").Build()) |
| 189 | .Build()) |
limasdf | 3d10254 | 2015-12-09 03:58:45 | [diff] [blame] | 190 | .Build(); |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 191 | scoped_refptr<const Extension> shared_module_2 = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 192 | CreateSharedModule("shared_module_2"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 193 | EXPECT_TRUE(InstallExtension(shared_module_2.get(), false)); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 194 | |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 195 | std::string extension_id = crx_file::id_util::GenerateId("extension_id"); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 196 | |
| 197 | // Create and install an extension v1.0 that imports our new module 1. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 198 | scoped_refptr<const Extension> importing_extension_1 = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 199 | CreateExtensionImportingModules( |
| 200 | std::vector<std::string>(1, shared_module_1->id()), extension_id, |
| 201 | "1.0"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 202 | EXPECT_TRUE(InstallExtension(importing_extension_1.get(), false)); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 203 | |
| 204 | // Create and install a new version of the extension that imports our new |
| 205 | // module 2. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 206 | scoped_refptr<const Extension> importing_extension_2 = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 207 | CreateExtensionImportingModules( |
| 208 | std::vector<std::string>(1, shared_module_2->id()), extension_id, |
| 209 | "1.1"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 210 | EXPECT_TRUE(InstallExtension(importing_extension_2.get(), true)); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 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. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 221 | scoped_refptr<const Extension> importing_extension_3 = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 222 | CreateExtensionImportingModules(std::vector<std::string>(), extension_id, |
| 223 | "1.2"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 224 | EXPECT_TRUE(InstallExtension(importing_extension_3.get(), true)); |
[email protected] | 38e87253 | 2014-07-16 23:27:51 | [diff] [blame] | 225 | |
| 226 | // Since the extension v1.2 does not depend any module, so the all models |
| 227 | // should have been uninstalled. |
| 228 | EXPECT_FALSE(registry()->GetExtensionById(shared_module_1->id(), |
| 229 | ExtensionRegistry::EVERYTHING)); |
| 230 | EXPECT_FALSE(registry()->GetExtensionById(shared_module_2->id(), |
| 231 | ExtensionRegistry::EVERYTHING)); |
| 232 | |
| 233 | } |
| 234 | |
[email protected] | f043dba8 | 2014-05-09 17:13:48 | [diff] [blame] | 235 | TEST_F(SharedModuleServiceUnitTest, WhitelistedImports) { |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 236 | std::string whitelisted_id = crx_file::id_util::GenerateId("whitelisted"); |
| 237 | std::string nonwhitelisted_id = |
| 238 | crx_file::id_util::GenerateId("nonwhitelisted"); |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 239 | // Create a module which exports to a restricted whitelist. |
dcheng | c963c714 | 2016-04-08 03:55:22 | [diff] [blame] | 240 | std::unique_ptr<base::DictionaryValue> manifest = |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 241 | DictionaryBuilder() |
| 242 | .Set("name", "Shared Module") |
| 243 | .Set("version", "1.0") |
| 244 | .Set("manifest_version", 2) |
| 245 | .Set("export", |
dcheng | 794d2bd | 2016-02-27 03:51:32 | [diff] [blame] | 246 | DictionaryBuilder() |
| 247 | .Set("whitelist", |
| 248 | ListBuilder().Append(whitelisted_id).Build()) |
| 249 | .Set("resources", ListBuilder().Append("*").Build()) |
| 250 | .Build()) |
limasdf | 3d10254 | 2015-12-09 03:58:45 | [diff] [blame] | 251 | .Build(); |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 252 | scoped_refptr<const Extension> shared_module = |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 253 | ExtensionBuilder() |
dcheng | 1fc00f1 | 2015-12-26 22:18:03 | [diff] [blame] | 254 | .SetManifest(std::move(manifest)) |
[email protected] | fdd2837 | 2014-08-21 02:27:26 | [diff] [blame] | 255 | .AddFlags(Extension::FROM_WEBSTORE) |
| 256 | .SetID(crx_file::id_util::GenerateId("shared_module")) |
| 257 | .Build(); |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 258 | |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 259 | EXPECT_TRUE(InstallExtension(shared_module.get(), false)); |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 260 | |
| 261 | // Create and install an extension with the whitelisted ID. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 262 | scoped_refptr<const Extension> whitelisted_extension = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 263 | CreateExtensionImportingModules( |
| 264 | std::vector<std::string>(1, shared_module->id()), whitelisted_id, |
| 265 | "1.0"); |
dcheng | c704794 | 2014-08-26 05:05:31 | [diff] [blame] | 266 | EXPECT_TRUE(InstallExtension(whitelisted_extension.get(), false)); |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 267 | |
| 268 | // Try to install an extension with an ID that is not whitelisted. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 269 | scoped_refptr<const Extension> nonwhitelisted_extension = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 270 | CreateExtensionImportingModules( |
| 271 | std::vector<std::string>(1, shared_module->id()), nonwhitelisted_id, |
| 272 | "1.0"); |
elijahtaylor | 1511c01 | 2014-09-23 02:47:18 | [diff] [blame] | 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)); |
[email protected] | 897147a | 2014-05-02 22:28:04 | [diff] [blame] | 278 | } |
| 279 | |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 280 | TEST_F(SharedModuleServiceUnitTest, PruneMultipleSharedModules) { |
| 281 | // Create two modules which export a resource each, and install it. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 282 | scoped_refptr<const Extension> shared_module_one = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 283 | CreateSharedModule("shared_module_one"); |
| 284 | EXPECT_TRUE(InstallExtension(shared_module_one.get(), false)); |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 285 | scoped_refptr<const Extension> shared_module_two = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 286 | CreateSharedModule("shared_module_two"); |
| 287 | EXPECT_TRUE(InstallExtension(shared_module_two.get(), false)); |
| 288 | |
| 289 | std::string extension_id = crx_file::id_util::GenerateId("extension_id"); |
| 290 | std::vector<std::string> module_ids; |
| 291 | module_ids.push_back(shared_module_one->id()); |
| 292 | module_ids.push_back(shared_module_two->id()); |
| 293 | // Create and install an extension that imports both the modules. |
Devlin Cronin | 8e5892f | 2018-10-04 00:13:43 | [diff] [blame] | 294 | scoped_refptr<const Extension> importing_extension = |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 295 | CreateExtensionImportingModules(module_ids, extension_id, "1.0"); |
| 296 | EXPECT_TRUE(InstallExtension(importing_extension.get(), false)); |
| 297 | |
| 298 | // Uninstall the extension that imports our modules. |
| 299 | base::string16 error; |
| 300 | service()->UninstallExtension(importing_extension->id(), |
| 301 | extensions::UNINSTALL_REASON_FOR_TESTING, |
Devlin Cronin | 218df7f | 2017-11-21 21:41:31 | [diff] [blame] | 302 | &error); |
lazyboy | ef4fe6a | 2016-02-29 22:18:04 | [diff] [blame] | 303 | EXPECT_TRUE(error.empty()); |
| 304 | |
| 305 | // Since the modules were only referenced by that single extension, they |
| 306 | // should have been uninstalled as a side-effect of uninstalling the extension |
| 307 | // that depended upon it. |
| 308 | EXPECT_FALSE(registry()->GetExtensionById(shared_module_one->id(), |
| 309 | ExtensionRegistry::EVERYTHING)); |
| 310 | EXPECT_FALSE(registry()->GetExtensionById(shared_module_two->id(), |
| 311 | ExtensionRegistry::EVERYTHING)); |
| 312 | } |
| 313 | |
[email protected] | 90878c5 | 2014-04-04 18:21:02 | [diff] [blame] | 314 | } // namespace extensions |