Home | History | Annotate | Download | only in extensions
      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