1// Copyright (c) 2012 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 "chrome/browser/extensions/component_loader.h"
6
7#include <string>
8
9#include "base/files/file_util.h"
10#include "base/path_service.h"
11#include "base/prefs/pref_registry_simple.h"
12#include "chrome/browser/extensions/test_extension_service.h"
13#include "chrome/common/chrome_paths.h"
14#include "chrome/common/pref_names.h"
15#include "chrome/test/base/testing_pref_service_syncable.h"
16#include "chrome/test/base/testing_profile.h"
17#include "components/pref_registry/pref_registry_syncable.h"
18#include "content/public/test/test_browser_thread_bundle.h"
19#include "extensions/common/constants.h"
20#include "extensions/common/extension.h"
21#include "extensions/common/extension_set.h"
22#include "extensions/common/manifest_handlers/background_info.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
25namespace extensions {
26
27namespace {
28
29class MockExtensionService : public TestExtensionService {
30 private:
31  bool ready_;
32  size_t unloaded_count_;
33  ExtensionSet extension_set_;
34
35 public:
36  MockExtensionService() : ready_(false), unloaded_count_(0) {
37  }
38
39  virtual void AddComponentExtension(const Extension* extension) OVERRIDE {
40    EXPECT_FALSE(extension_set_.Contains(extension->id()));
41    // ExtensionService must become the owner of the extension object.
42    extension_set_.Insert(extension);
43  }
44
45  virtual void UnloadExtension(
46      const std::string& extension_id,
47      UnloadedExtensionInfo::Reason reason) OVERRIDE {
48    ASSERT_TRUE(extension_set_.Contains(extension_id));
49    // Remove the extension with the matching id.
50    extension_set_.Remove(extension_id);
51    unloaded_count_++;
52  }
53
54  virtual void RemoveComponentExtension(const std::string & extension_id)
55      OVERRIDE {
56    UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_DISABLE);
57  }
58
59  virtual bool is_ready() OVERRIDE {
60    return ready_;
61  }
62
63  virtual const ExtensionSet* extensions() const OVERRIDE {
64    return &extension_set_;
65  }
66
67  void set_ready(bool ready) {
68    ready_ = ready;
69  }
70
71  size_t unloaded_count() const {
72    return unloaded_count_;
73  }
74
75  void clear_extensions() {
76    extension_set_.Clear();
77  }
78};
79
80}  // namespace
81
82class ComponentLoaderTest : public testing::Test {
83 public:
84  ComponentLoaderTest()
85      // Note: we pass the same pref service here, to stand in for both
86      // user prefs and local state.
87      : component_loader_(&extension_service_,
88                          &prefs_,
89                          &local_state_,
90                          &profile_) {
91  }
92
93  virtual void SetUp() OVERRIDE {
94    extension_path_ =
95        GetBasePath().AppendASCII("good")
96                     .AppendASCII("Extensions")
97                     .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
98                     .AppendASCII("1.0.0.0");
99
100    // Read in the extension manifest.
101    ASSERT_TRUE(base::ReadFileToString(
102        extension_path_.Append(kManifestFilename),
103        &manifest_contents_));
104
105    // Register the local state prefs.
106#if defined(OS_CHROMEOS)
107    local_state_.registry()->RegisterBooleanPref(
108        prefs::kAccessibilitySpokenFeedbackEnabled, false);
109#endif
110  }
111
112 protected:
113  MockExtensionService extension_service_;
114  TestingPrefServiceSyncable prefs_;
115  TestingPrefServiceSimple local_state_;
116  TestingProfile profile_;
117  ComponentLoader component_loader_;
118
119  // The root directory of the text extension.
120  base::FilePath extension_path_;
121
122  // The contents of the text extension's manifest file.
123  std::string manifest_contents_;
124
125  content::TestBrowserThreadBundle thread_bundle_;
126
127  base::FilePath GetBasePath() {
128    base::FilePath test_data_dir;
129    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
130    return test_data_dir.AppendASCII("extensions");
131  }
132};
133
134TEST_F(ComponentLoaderTest, ParseManifest) {
135  scoped_ptr<base::DictionaryValue> manifest;
136
137  // Test invalid JSON.
138  manifest.reset(
139      component_loader_.ParseManifest("{ 'test': 3 } invalid"));
140  EXPECT_FALSE(manifest.get());
141
142  // Test manifests that are valid JSON, but don't have an object literal
143  // at the root. ParseManifest() should always return NULL.
144
145  manifest.reset(component_loader_.ParseManifest(std::string()));
146  EXPECT_FALSE(manifest.get());
147
148  manifest.reset(component_loader_.ParseManifest("[{ \"foo\": 3 }]"));
149  EXPECT_FALSE(manifest.get());
150
151  manifest.reset(component_loader_.ParseManifest("\"Test\""));
152  EXPECT_FALSE(manifest.get());
153
154  manifest.reset(component_loader_.ParseManifest("42"));
155  EXPECT_FALSE(manifest.get());
156
157  manifest.reset(component_loader_.ParseManifest("true"));
158  EXPECT_FALSE(manifest.get());
159
160  manifest.reset(component_loader_.ParseManifest("false"));
161  EXPECT_FALSE(manifest.get());
162
163  manifest.reset(component_loader_.ParseManifest("null"));
164  EXPECT_FALSE(manifest.get());
165
166  // Test parsing valid JSON.
167
168  int value = 0;
169  manifest.reset(component_loader_.ParseManifest(
170      "{ \"test\": { \"one\": 1 }, \"two\": 2 }"));
171  ASSERT_TRUE(manifest.get());
172  EXPECT_TRUE(manifest->GetInteger("test.one", &value));
173  EXPECT_EQ(1, value);
174  ASSERT_TRUE(manifest->GetInteger("two", &value));
175  EXPECT_EQ(2, value);
176
177  std::string string_value;
178  manifest.reset(component_loader_.ParseManifest(manifest_contents_));
179  ASSERT_TRUE(manifest->GetString("background.page", &string_value));
180  EXPECT_EQ("backgroundpage.html", string_value);
181}
182
183// Test that the extension isn't loaded if the extension service isn't ready.
184TEST_F(ComponentLoaderTest, AddWhenNotReady) {
185  extension_service_.set_ready(false);
186  std::string extension_id =
187      component_loader_.Add(manifest_contents_, extension_path_);
188  EXPECT_NE("", extension_id);
189  EXPECT_EQ(0u, extension_service_.extensions()->size());
190}
191
192// Test that it *is* loaded when the extension service *is* ready.
193TEST_F(ComponentLoaderTest, AddWhenReady) {
194  extension_service_.set_ready(true);
195  std::string extension_id =
196      component_loader_.Add(manifest_contents_, extension_path_);
197  EXPECT_NE("", extension_id);
198  EXPECT_EQ(1u, extension_service_.extensions()->size());
199  EXPECT_TRUE(extension_service_.extensions()->GetByID(extension_id));
200}
201
202TEST_F(ComponentLoaderTest, Remove) {
203  extension_service_.set_ready(false);
204
205  // Removing an extension that was never added should be ok.
206  component_loader_.Remove(extension_path_);
207  EXPECT_EQ(0u, extension_service_.extensions()->size());
208
209  // Try adding and removing before LoadAll() is called.
210  component_loader_.Add(manifest_contents_, extension_path_);
211  component_loader_.Remove(extension_path_);
212  component_loader_.LoadAll();
213  EXPECT_EQ(0u, extension_service_.extensions()->size());
214
215  // Load an extension, and check that it's unloaded when Remove() is called.
216  extension_service_.set_ready(true);
217  std::string extension_id =
218      component_loader_.Add(manifest_contents_, extension_path_);
219  EXPECT_EQ(1u, extension_service_.extensions()->size());
220  component_loader_.Remove(extension_path_);
221  EXPECT_EQ(0u, extension_service_.extensions()->size());
222
223  // And after calling LoadAll(), it shouldn't get loaded.
224  component_loader_.LoadAll();
225  EXPECT_EQ(0u, extension_service_.extensions()->size());
226}
227
228TEST_F(ComponentLoaderTest, LoadAll) {
229  extension_service_.set_ready(false);
230
231  // No extensions should be loaded if none were added.
232  component_loader_.LoadAll();
233  EXPECT_EQ(0u, extension_service_.extensions()->size());
234
235  // Use LoadAll() to load the default extensions.
236  component_loader_.AddDefaultComponentExtensions(false);
237  component_loader_.LoadAll();
238  unsigned int default_count = extension_service_.extensions()->size();
239
240  // Clear the list of loaded extensions, and reload with one more.
241  extension_service_.clear_extensions();
242  component_loader_.Add(manifest_contents_, extension_path_);
243  component_loader_.LoadAll();
244
245  EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
246}
247
248TEST_F(ComponentLoaderTest, AddOrReplace) {
249  EXPECT_EQ(0u, component_loader_.registered_extensions_count());
250  component_loader_.AddDefaultComponentExtensions(false);
251  size_t const default_count = component_loader_.registered_extensions_count();
252  base::FilePath known_extension = GetBasePath()
253      .AppendASCII("override_component_extension");
254  base::FilePath unknow_extension = extension_path_;
255  base::FilePath invalid_extension = GetBasePath().AppendASCII("bad");
256
257  // Replace a default component extension.
258  component_loader_.AddOrReplace(known_extension);
259  EXPECT_EQ(default_count,
260            component_loader_.registered_extensions_count());
261
262  // Add a new component extension.
263  component_loader_.AddOrReplace(unknow_extension);
264  EXPECT_EQ(default_count + 1,
265            component_loader_.registered_extensions_count());
266
267  extension_service_.set_ready(true);
268  component_loader_.LoadAll();
269
270  EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
271  EXPECT_EQ(0u, extension_service_.unloaded_count());
272
273  // replace loaded component extension.
274  component_loader_.AddOrReplace(known_extension);
275  EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
276  EXPECT_EQ(1u, extension_service_.unloaded_count());
277
278  // Add an invalid component extension.
279  std::string extension_id = component_loader_.AddOrReplace(invalid_extension);
280  EXPECT_TRUE(extension_id.empty());
281}
282
283}  // namespace extensions
284