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