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