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