1// Copyright 2013 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 <string> 6 7#include "base/memory/ref_counted.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/prefs/mock_pref_change_callback.h" 10#include "base/values.h" 11#include "chrome/browser/extensions/./extension_prefs_unittest.h" 12#include "chrome/browser/extensions/api/content_settings/content_settings_service.h" 13#include "chrome/browser/extensions/api/preference/preference_api.h" 14#include "chrome/test/base/testing_profile.h" 15#include "components/pref_registry/pref_registry_syncable.h" 16#include "extensions/browser/extension_prefs.h" 17#include "extensions/common/extension.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20using base::Value; 21 22namespace extensions { 23 24namespace { 25 26const char kPref1[] = "path1.subpath"; 27const char kPref2[] = "path2"; 28const char kPref3[] = "path3"; 29const char kPref4[] = "path4"; 30 31// Default values in case an extension pref value is not overridden. 32const char kDefaultPref1[] = "default pref 1"; 33const char kDefaultPref2[] = "default pref 2"; 34const char kDefaultPref3[] = "default pref 3"; 35const char kDefaultPref4[] = "default pref 4"; 36 37} // namespace 38 39// An implementation of the PreferenceAPI which returns the ExtensionPrefs and 40// ExtensionPrefValueMap from the TestExtensionPrefs, rather than from a 41// profile (which we don't create in unittests). 42class TestPreferenceAPI : public PreferenceAPIBase { 43 public: 44 explicit TestPreferenceAPI(TestExtensionPrefs* test_extension_prefs, 45 ContentSettingsService* content_settings) 46 : test_extension_prefs_(test_extension_prefs), 47 content_settings_(content_settings) {} 48 ~TestPreferenceAPI() {} 49 50 private: 51 // PreferenceAPIBase implementation. 52 virtual ExtensionPrefs* extension_prefs() OVERRIDE { 53 return test_extension_prefs_->prefs(); 54 } 55 virtual ExtensionPrefValueMap* extension_pref_value_map() OVERRIDE { 56 return test_extension_prefs_->extension_pref_value_map(); 57 } 58 virtual scoped_refptr<ContentSettingsStore> content_settings_store() 59 OVERRIDE { 60 return content_settings_->content_settings_store(); 61 } 62 63 TestExtensionPrefs* test_extension_prefs_; 64 ContentSettingsService* content_settings_; 65 66 DISALLOW_COPY_AND_ASSIGN(TestPreferenceAPI); 67}; 68 69class ExtensionControlledPrefsTest : public PrefsPrepopulatedTestBase { 70 public: 71 ExtensionControlledPrefsTest(); 72 virtual ~ExtensionControlledPrefsTest(); 73 74 virtual void RegisterPreferences(user_prefs::PrefRegistrySyncable* registry) 75 OVERRIDE; 76 void InstallExtensionControlledPref(Extension* extension, 77 const std::string& key, 78 base::Value* value); 79 void InstallExtensionControlledPrefIncognito(Extension* extension, 80 const std::string& key, 81 base::Value* value); 82 void InstallExtensionControlledPrefIncognitoSessionOnly( 83 Extension* extension, 84 const std::string& key, 85 base::Value* value); 86 void InstallExtension(Extension* extension); 87 void UninstallExtension(const std::string& extension_id); 88 89 scoped_refptr<ContentSettingsStore> content_settings_store() { 90 return content_settings_->content_settings_store(); 91 } 92 93 protected: 94 void EnsureExtensionInstalled(Extension* extension); 95 void EnsureExtensionUninstalled(const std::string& extension_id); 96 97 TestingProfile profile_; 98 ContentSettingsService* content_settings_; 99 TestPreferenceAPI test_preference_api_; 100}; 101 102ExtensionControlledPrefsTest::ExtensionControlledPrefsTest() 103 : PrefsPrepopulatedTestBase(), 104 content_settings_(ContentSettingsService::Get(&profile_)), 105 test_preference_api_(&prefs_, content_settings_) { 106 prefs_.prefs()->AddObserver(content_settings_); 107} 108 109ExtensionControlledPrefsTest::~ExtensionControlledPrefsTest() { 110} 111 112void ExtensionControlledPrefsTest::RegisterPreferences( 113 user_prefs::PrefRegistrySyncable* registry) { 114 registry->RegisterStringPref( 115 kPref1, kDefaultPref1, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 116 registry->RegisterStringPref( 117 kPref2, kDefaultPref2, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 118 registry->RegisterStringPref( 119 kPref3, kDefaultPref3, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 120 registry->RegisterStringPref( 121 kPref4, kDefaultPref4, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 122} 123 124void ExtensionControlledPrefsTest::InstallExtensionControlledPref( 125 Extension* extension, 126 const std::string& key, 127 base::Value* value) { 128 EnsureExtensionInstalled(extension); 129 test_preference_api_.SetExtensionControlledPref( 130 extension->id(), key, kExtensionPrefsScopeRegular, value); 131} 132 133void ExtensionControlledPrefsTest::InstallExtensionControlledPrefIncognito( 134 Extension* extension, 135 const std::string& key, 136 base::Value* value) { 137 EnsureExtensionInstalled(extension); 138 test_preference_api_.SetExtensionControlledPref( 139 extension->id(), key, kExtensionPrefsScopeIncognitoPersistent, value); 140} 141 142void ExtensionControlledPrefsTest:: 143InstallExtensionControlledPrefIncognitoSessionOnly(Extension* extension, 144 const std::string& key, 145 base::Value* value) { 146 EnsureExtensionInstalled(extension); 147 test_preference_api_.SetExtensionControlledPref( 148 extension->id(), key, kExtensionPrefsScopeIncognitoSessionOnly, value); 149} 150 151void ExtensionControlledPrefsTest::InstallExtension(Extension* extension) { 152 EnsureExtensionInstalled(extension); 153} 154 155void ExtensionControlledPrefsTest::UninstallExtension( 156 const std::string& extension_id) { 157 EnsureExtensionUninstalled(extension_id); 158} 159 160void ExtensionControlledPrefsTest::EnsureExtensionInstalled( 161 Extension* extension) { 162 // Install extension the first time a preference is set for it. 163 Extension* extensions[] = { extension1(), 164 extension2(), 165 extension3(), 166 extension4() }; 167 for (size_t i = 0; i < kNumInstalledExtensions; ++i) { 168 if (extension == extensions[i] && !installed_[i]) { 169 prefs()->OnExtensionInstalled(extension, 170 Extension::ENABLED, 171 syncer::StringOrdinal(), 172 std::string()); 173 prefs()->SetIsIncognitoEnabled(extension->id(), true); 174 installed_[i] = true; 175 break; 176 } 177 } 178} 179 180void ExtensionControlledPrefsTest::EnsureExtensionUninstalled( 181 const std::string& extension_id) { 182 Extension* extensions[] = { extension1(), 183 extension2(), 184 extension3(), 185 extension4() }; 186 for (size_t i = 0; i < kNumInstalledExtensions; ++i) { 187 if (extensions[i]->id() == extension_id) { 188 installed_[i] = false; 189 break; 190 } 191 } 192 prefs()->OnExtensionUninstalled(extension_id, Manifest::INTERNAL, false); 193} 194 195class ControlledPrefsInstallOneExtension 196 : public ExtensionControlledPrefsTest { 197 virtual void Initialize() OVERRIDE { 198 InstallExtensionControlledPref(extension1(), 199 kPref1, 200 new base::StringValue("val1")); 201 } 202 virtual void Verify() OVERRIDE { 203 std::string actual = prefs()->pref_service()->GetString(kPref1); 204 EXPECT_EQ("val1", actual); 205 } 206}; 207TEST_F(ControlledPrefsInstallOneExtension, 208 ControlledPrefsInstallOneExtension) { } 209 210// Check that we do not forget persistent incognito values after a reload. 211class ControlledPrefsInstallIncognitoPersistent 212 : public ExtensionControlledPrefsTest { 213 public: 214 virtual void Initialize() OVERRIDE { 215 InstallExtensionControlledPref( 216 extension1(), kPref1, new base::StringValue("val1")); 217 InstallExtensionControlledPrefIncognito( 218 extension1(), kPref1, new base::StringValue("val2")); 219 scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService()); 220 std::string actual = incog_prefs->GetString(kPref1); 221 EXPECT_EQ("val2", actual); 222 } 223 224 virtual void Verify() OVERRIDE { 225 // Main pref service shall see only non-incognito settings. 226 std::string actual = prefs()->pref_service()->GetString(kPref1); 227 EXPECT_EQ("val1", actual); 228 // Incognito pref service shall see incognito values. 229 scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService()); 230 actual = incog_prefs->GetString(kPref1); 231 EXPECT_EQ("val2", actual); 232 } 233}; 234TEST_F(ControlledPrefsInstallIncognitoPersistent, 235 ControlledPrefsInstallIncognitoPersistent) { } 236 237// Check that we forget 'session only' incognito values after a reload. 238class ControlledPrefsInstallIncognitoSessionOnly 239 : public ExtensionControlledPrefsTest { 240 public: 241 ControlledPrefsInstallIncognitoSessionOnly() : iteration_(0) {} 242 243 virtual void Initialize() OVERRIDE { 244 InstallExtensionControlledPref( 245 extension1(), kPref1, new base::StringValue("val1")); 246 InstallExtensionControlledPrefIncognitoSessionOnly( 247 extension1(), kPref1, new base::StringValue("val2")); 248 scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService()); 249 std::string actual = incog_prefs->GetString(kPref1); 250 EXPECT_EQ("val2", actual); 251 } 252 virtual void Verify() OVERRIDE { 253 // Main pref service shall see only non-incognito settings. 254 std::string actual = prefs()->pref_service()->GetString(kPref1); 255 EXPECT_EQ("val1", actual); 256 // Incognito pref service shall see session-only incognito values only 257 // during first run. Once the pref service was reloaded, all values shall be 258 // discarded. 259 scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService()); 260 actual = incog_prefs->GetString(kPref1); 261 if (iteration_ == 0) { 262 EXPECT_EQ("val2", actual); 263 } else { 264 EXPECT_EQ("val1", actual); 265 } 266 ++iteration_; 267 } 268 int iteration_; 269}; 270TEST_F(ControlledPrefsInstallIncognitoSessionOnly, 271 ControlledPrefsInstallIncognitoSessionOnly) { } 272 273class ControlledPrefsUninstallExtension : public ExtensionControlledPrefsTest { 274 virtual void Initialize() OVERRIDE { 275 InstallExtensionControlledPref( 276 extension1(), kPref1, new base::StringValue("val1")); 277 InstallExtensionControlledPref( 278 extension1(), kPref2, new base::StringValue("val2")); 279 scoped_refptr<ContentSettingsStore> store = content_settings_store(); 280 ContentSettingsPattern pattern = 281 ContentSettingsPattern::FromString("http://[*.]example.com"); 282 store->SetExtensionContentSetting(extension1()->id(), 283 pattern, pattern, 284 CONTENT_SETTINGS_TYPE_IMAGES, 285 std::string(), 286 CONTENT_SETTING_BLOCK, 287 kExtensionPrefsScopeRegular); 288 289 UninstallExtension(extension1()->id()); 290 } 291 virtual void Verify() OVERRIDE { 292 EXPECT_FALSE(prefs()->HasPrefForExtension(extension1()->id())); 293 294 std::string actual; 295 actual = prefs()->pref_service()->GetString(kPref1); 296 EXPECT_EQ(kDefaultPref1, actual); 297 actual = prefs()->pref_service()->GetString(kPref2); 298 EXPECT_EQ(kDefaultPref2, actual); 299 } 300}; 301TEST_F(ControlledPrefsUninstallExtension, 302 ControlledPrefsUninstallExtension) { } 303 304// Tests triggering of notifications to registered observers. 305class ControlledPrefsNotifyWhenNeeded : public ExtensionControlledPrefsTest { 306 virtual void Initialize() OVERRIDE { 307 using testing::_; 308 using testing::Mock; 309 using testing::StrEq; 310 311 MockPrefChangeCallback observer(prefs()->pref_service()); 312 PrefChangeRegistrar registrar; 313 registrar.Init(prefs()->pref_service()); 314 registrar.Add(kPref1, observer.GetCallback()); 315 316 MockPrefChangeCallback incognito_observer(prefs()->pref_service()); 317 scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService()); 318 PrefChangeRegistrar incognito_registrar; 319 incognito_registrar.Init(incog_prefs.get()); 320 incognito_registrar.Add(kPref1, incognito_observer.GetCallback()); 321 322 // Write value and check notification. 323 EXPECT_CALL(observer, OnPreferenceChanged(_)); 324 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)); 325 InstallExtensionControlledPref(extension1(), kPref1, 326 new base::StringValue("https://www.chromium.org")); 327 Mock::VerifyAndClearExpectations(&observer); 328 Mock::VerifyAndClearExpectations(&incognito_observer); 329 330 // Write same value. 331 EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0); 332 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)).Times(0); 333 InstallExtensionControlledPref(extension1(), kPref1, 334 new base::StringValue("https://www.chromium.org")); 335 Mock::VerifyAndClearExpectations(&observer); 336 Mock::VerifyAndClearExpectations(&incognito_observer); 337 338 // Change value. 339 EXPECT_CALL(observer, OnPreferenceChanged(_)); 340 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)); 341 InstallExtensionControlledPref(extension1(), kPref1, 342 new base::StringValue("chrome://newtab")); 343 Mock::VerifyAndClearExpectations(&observer); 344 Mock::VerifyAndClearExpectations(&incognito_observer); 345 // Change only incognito persistent value. 346 EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0); 347 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)); 348 InstallExtensionControlledPrefIncognito(extension1(), kPref1, 349 new base::StringValue("chrome://newtab2")); 350 Mock::VerifyAndClearExpectations(&observer); 351 Mock::VerifyAndClearExpectations(&incognito_observer); 352 353 // Change only incognito session-only value. 354 EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0); 355 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)); 356 InstallExtensionControlledPrefIncognito(extension1(), kPref1, 357 new base::StringValue("chrome://newtab3")); 358 Mock::VerifyAndClearExpectations(&observer); 359 Mock::VerifyAndClearExpectations(&incognito_observer); 360 361 // Uninstall. 362 EXPECT_CALL(observer, OnPreferenceChanged(_)); 363 EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)); 364 UninstallExtension(extension1()->id()); 365 Mock::VerifyAndClearExpectations(&observer); 366 Mock::VerifyAndClearExpectations(&incognito_observer); 367 368 registrar.Remove(kPref1); 369 incognito_registrar.Remove(kPref1); 370 } 371 virtual void Verify() OVERRIDE { 372 std::string actual = prefs()->pref_service()->GetString(kPref1); 373 EXPECT_EQ(kDefaultPref1, actual); 374 } 375}; 376TEST_F(ControlledPrefsNotifyWhenNeeded, 377 ControlledPrefsNotifyWhenNeeded) { } 378 379// Tests disabling an extension. 380class ControlledPrefsDisableExtension : public ExtensionControlledPrefsTest { 381 virtual void Initialize() OVERRIDE { 382 InstallExtensionControlledPref( 383 extension1(), kPref1, new base::StringValue("val1")); 384 std::string actual = prefs()->pref_service()->GetString(kPref1); 385 EXPECT_EQ("val1", actual); 386 prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED); 387 } 388 virtual void Verify() OVERRIDE { 389 std::string actual = prefs()->pref_service()->GetString(kPref1); 390 EXPECT_EQ(kDefaultPref1, actual); 391 } 392}; 393TEST_F(ControlledPrefsDisableExtension, ControlledPrefsDisableExtension) { } 394 395// Tests disabling and reenabling an extension. 396class ControlledPrefsReenableExtension : public ExtensionControlledPrefsTest { 397 virtual void Initialize() OVERRIDE { 398 InstallExtensionControlledPref( 399 extension1(), kPref1, new base::StringValue("val1")); 400 prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED); 401 prefs()->SetExtensionState(extension1()->id(), Extension::ENABLED); 402 } 403 virtual void Verify() OVERRIDE { 404 std::string actual = prefs()->pref_service()->GetString(kPref1); 405 EXPECT_EQ("val1", actual); 406 } 407}; 408TEST_F(ControlledPrefsDisableExtension, ControlledPrefsReenableExtension) { } 409 410// Mock class to test whether objects are deleted correctly. 411class MockStringValue : public base::StringValue { 412 public: 413 explicit MockStringValue(const std::string& in_value) 414 : base::StringValue(in_value) { 415 } 416 virtual ~MockStringValue() { 417 Die(); 418 } 419 MOCK_METHOD0(Die, void()); 420}; 421 422class ControlledPrefsSetExtensionControlledPref 423 : public ExtensionControlledPrefsTest { 424 public: 425 virtual void Initialize() OVERRIDE { 426 MockStringValue* v1 = new MockStringValue("https://www.chromium.org"); 427 MockStringValue* v2 = new MockStringValue("https://www.chromium.org"); 428 MockStringValue* v1i = new MockStringValue("https://www.chromium.org"); 429 MockStringValue* v2i = new MockStringValue("https://www.chromium.org"); 430 // Ownership is taken, value shall not be deleted. 431 EXPECT_CALL(*v1, Die()).Times(0); 432 EXPECT_CALL(*v1i, Die()).Times(0); 433 InstallExtensionControlledPref(extension1(), kPref1, v1); 434 InstallExtensionControlledPrefIncognito(extension1(), kPref1, v1i); 435 testing::Mock::VerifyAndClearExpectations(v1); 436 testing::Mock::VerifyAndClearExpectations(v1i); 437 // Make sure there is no memory leak and both values are deleted. 438 EXPECT_CALL(*v1, Die()).Times(1); 439 EXPECT_CALL(*v1i, Die()).Times(1); 440 EXPECT_CALL(*v2, Die()).Times(1); 441 EXPECT_CALL(*v2i, Die()).Times(1); 442 InstallExtensionControlledPref(extension1(), kPref1, v2); 443 InstallExtensionControlledPrefIncognito(extension1(), kPref1, v2i); 444 prefs_.RecreateExtensionPrefs(); 445 testing::Mock::VerifyAndClearExpectations(v1); 446 testing::Mock::VerifyAndClearExpectations(v1i); 447 testing::Mock::VerifyAndClearExpectations(v2); 448 testing::Mock::VerifyAndClearExpectations(v2i); 449 } 450 451 virtual void Verify() OVERRIDE { 452 } 453}; 454TEST_F(ControlledPrefsSetExtensionControlledPref, 455 ControlledPrefsSetExtensionControlledPref) { } 456 457// Tests that the switches::kDisableExtensions command-line flag prevents 458// extension controlled preferences from being enacted. 459class ControlledPrefsDisableExtensions : public ExtensionControlledPrefsTest { 460 public: 461 ControlledPrefsDisableExtensions() 462 : iteration_(0) {} 463 virtual ~ControlledPrefsDisableExtensions() {} 464 virtual void Initialize() OVERRIDE { 465 InstallExtensionControlledPref( 466 extension1(), kPref1, new base::StringValue("val1")); 467 // This becomes only active in the second verification phase. 468 prefs_.set_extensions_disabled(true); 469 } 470 virtual void Verify() OVERRIDE { 471 std::string actual = prefs()->pref_service()->GetString(kPref1); 472 if (iteration_ == 0) { 473 EXPECT_EQ("val1", actual); 474 ++iteration_; 475 } else { 476 EXPECT_EQ(kDefaultPref1, actual); 477 } 478 } 479 480 private: 481 int iteration_; 482}; 483TEST_F(ControlledPrefsDisableExtensions, ControlledPrefsDisableExtensions) { } 484 485} // namespace extensions 486