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 "extensions/browser/extension_registry.h" 15 #include "extensions/browser/install_flag.h" 16 #include "extensions/common/extension_builder.h" 17 #include "extensions/common/id_util.h" 18 #include "extensions/common/value_builder.h" 19 #include "sync/api/string_ordinal.h" 20 21 namespace extensions { 22 23 namespace { 24 25 // Return an extension with |id| which imports a module with the given 26 // |import_id|. 27 scoped_refptr<Extension> CreateExtensionImportingModule( 28 const std::string& import_id, const std::string& id) { 29 scoped_ptr<base::DictionaryValue> manifest = 30 DictionaryBuilder() 31 .Set("name", "Has Dependent Modules") 32 .Set("version", "1.0") 33 .Set("manifest_version", 2) 34 .Set("import", 35 ListBuilder().Append(DictionaryBuilder().Set("id", import_id))) 36 .Build(); 37 38 return ExtensionBuilder().SetManifest(manifest.Pass()) 39 .AddFlags(Extension::FROM_WEBSTORE) 40 .SetID(id) 41 .Build(); 42 } 43 44 } // namespace 45 46 class SharedModuleServiceUnitTest : public ExtensionServiceTestBase { 47 public: 48 SharedModuleServiceUnitTest() : 49 // The "export" key is open for dev-channel only, but unit tests 50 // run as stable channel on the official Windows build. 51 current_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN) {} 52 protected: 53 virtual void SetUp() OVERRIDE; 54 55 // Install an extension and notify the ExtensionService. 56 testing::AssertionResult InstallExtension(const Extension* extension); 57 ScopedCurrentChannel current_channel_; 58 }; 59 60 void SharedModuleServiceUnitTest::SetUp() { 61 ExtensionServiceTestBase::SetUp(); 62 InitializeGoodInstalledExtensionService(); 63 service_->Init(); 64 } 65 66 testing::AssertionResult SharedModuleServiceUnitTest::InstallExtension( 67 const Extension* extension) { 68 // Verify the extension is not already installed. 69 if (registry()->GetExtensionById(extension->id(), 70 ExtensionRegistry::ENABLED)) { 71 return testing::AssertionFailure() << "Extension already installed."; 72 } 73 74 // Notify the service that the extension is installed. This adds it to the 75 // registry, notifies interested parties, etc. 76 service_->OnExtensionInstalled( 77 extension, syncer::StringOrdinal(), kInstallFlagInstallImmediately); 78 79 // Verify that the extension is now installed. 80 if (!registry()->GetExtensionById(extension->id(), 81 ExtensionRegistry::ENABLED)) { 82 return testing::AssertionFailure() << "Could not install extension."; 83 } 84 85 return testing::AssertionSuccess(); 86 } 87 88 TEST_F(SharedModuleServiceUnitTest, AddDependentSharedModules) { 89 // Create an extension that has a dependency. 90 std::string import_id = id_util::GenerateId("id"); 91 std::string extension_id = id_util::GenerateId("extension_id"); 92 scoped_refptr<Extension> extension = 93 CreateExtensionImportingModule(import_id, extension_id); 94 95 PendingExtensionManager* pending_extension_manager = 96 service_->pending_extension_manager(); 97 98 // Verify that we don't currently want to install the imported module. 99 EXPECT_FALSE(pending_extension_manager->IsIdPending(import_id)); 100 101 // Try to satisfy imports for the extension. This should queue the imported 102 // module's installation. 103 service_->shared_module_service()->SatisfyImports(extension); 104 EXPECT_TRUE(pending_extension_manager->IsIdPending(import_id)); 105 } 106 107 TEST_F(SharedModuleServiceUnitTest, PruneSharedModulesOnUninstall) { 108 // Create a module which exports a resource, and install it. 109 scoped_ptr<base::DictionaryValue> manifest = 110 DictionaryBuilder() 111 .Set("name", "Shared Module") 112 .Set("version", "1.0") 113 .Set("manifest_version", 2) 114 .Set("export", 115 DictionaryBuilder().Set("resources", 116 ListBuilder().Append("foo.js"))).Build(); 117 scoped_refptr<Extension> shared_module = 118 ExtensionBuilder().SetManifest(manifest.Pass()) 119 .AddFlags(Extension::FROM_WEBSTORE) 120 .SetID(id_util::GenerateId("shared_module")) 121 .Build(); 122 123 EXPECT_TRUE(InstallExtension(shared_module)); 124 125 std::string extension_id = id_util::GenerateId("extension_id"); 126 // Create and install an extension that imports our new module. 127 scoped_refptr<Extension> importing_extension = 128 CreateExtensionImportingModule(shared_module->id(), extension_id); 129 EXPECT_TRUE(InstallExtension(importing_extension)); 130 131 // Uninstall the extension that imports our module. 132 base::string16 error; 133 service_->UninstallExtension(importing_extension->id(), 134 false, // Not external uninstall. 135 &error); 136 EXPECT_TRUE(error.empty()); 137 138 // Since the module was only referenced by that single extension, it should 139 // have been uninstalled as a side-effect of uninstalling the extension that 140 // depended upon it. 141 EXPECT_FALSE(registry()->GetExtensionById(shared_module->id(), 142 ExtensionRegistry::EVERYTHING)); 143 } 144 145 TEST_F(SharedModuleServiceUnitTest, WhitelistedImports) { 146 std::string whitelisted_id = id_util::GenerateId("whitelisted"); 147 std::string nonwhitelisted_id = id_util::GenerateId("nonwhitelisted"); 148 // Create a module which exports to a restricted whitelist. 149 scoped_ptr<base::DictionaryValue> manifest = 150 DictionaryBuilder() 151 .Set("name", "Shared Module") 152 .Set("version", "1.0") 153 .Set("manifest_version", 2) 154 .Set("export", 155 DictionaryBuilder().Set("whitelist", 156 ListBuilder() 157 .Append(whitelisted_id)) 158 .Set("resources", 159 ListBuilder().Append("*"))).Build(); 160 scoped_refptr<Extension> shared_module = 161 ExtensionBuilder().SetManifest(manifest.Pass()) 162 .AddFlags(Extension::FROM_WEBSTORE) 163 .SetID(id_util::GenerateId("shared_module")) 164 .Build(); 165 166 EXPECT_TRUE(InstallExtension(shared_module)); 167 168 // Create and install an extension with the whitelisted ID. 169 scoped_refptr<Extension> whitelisted_extension = 170 CreateExtensionImportingModule(shared_module->id(), whitelisted_id); 171 EXPECT_TRUE(InstallExtension(whitelisted_extension)); 172 173 // Try to install an extension with an ID that is not whitelisted. 174 scoped_refptr<Extension> nonwhitelisted_extension = 175 CreateExtensionImportingModule(shared_module->id(), nonwhitelisted_id); 176 EXPECT_FALSE(InstallExtension(nonwhitelisted_extension)); 177 } 178 179 } // namespace extensions 180