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