1// Copyright 2014 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/prefs/profile_pref_store_manager.h" 6 7#include <vector> 8 9#include "base/compiler_specific.h" 10#include "base/files/file_enumerator.h" 11#include "base/files/file_util.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/memory/ref_counted.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/message_loop/message_loop.h" 16#include "base/prefs/json_pref_store.h" 17#include "base/prefs/persistent_pref_store.h" 18#include "base/prefs/pref_service.h" 19#include "base/prefs/pref_service_factory.h" 20#include "base/prefs/pref_store.h" 21#include "base/prefs/testing_pref_service.h" 22#include "base/run_loop.h" 23#include "base/strings/string_util.h" 24#include "base/values.h" 25#include "chrome/browser/prefs/mock_validation_delegate.h" 26#include "chrome/browser/prefs/pref_hash_filter.h" 27#include "chrome/browser/prefs/tracked/pref_service_hash_store_contents.h" 28#include "chrome/common/pref_names.h" 29#include "components/pref_registry/pref_registry_syncable.h" 30#include "testing/gtest/include/gtest/gtest.h" 31 32namespace { 33 34class FirstEqualsPredicate { 35 public: 36 explicit FirstEqualsPredicate(const std::string& expected) 37 : expected_(expected) {} 38 bool operator()(const std::pair<std::string, base::Value*>& pair) { 39 return pair.first == expected_; 40 } 41 42 private: 43 const std::string expected_; 44}; 45 46// Observes changes to the PrefStore and verifies that only registered prefs are 47// written. 48class RegistryVerifier : public PrefStore::Observer { 49 public: 50 explicit RegistryVerifier(PrefRegistry* pref_registry) 51 : pref_registry_(pref_registry) {} 52 53 // PrefStore::Observer implementation 54 virtual void OnPrefValueChanged(const std::string& key) OVERRIDE { 55 EXPECT_TRUE(pref_registry_->end() != 56 std::find_if(pref_registry_->begin(), 57 pref_registry_->end(), 58 FirstEqualsPredicate(key))) 59 << "Unregistered key " << key << " was changed."; 60 } 61 62 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} 63 64 private: 65 scoped_refptr<PrefRegistry> pref_registry_; 66}; 67 68const char kUnprotectedPref[] = "unprotected_pref"; 69const char kTrackedAtomic[] = "tracked_atomic"; 70const char kProtectedAtomic[] = "protected_atomic"; 71 72const char kFoobar[] = "FOOBAR"; 73const char kBarfoo[] = "BARFOO"; 74const char kHelloWorld[] = "HELLOWORLD"; 75const char kGoodbyeWorld[] = "GOODBYEWORLD"; 76 77const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { 78 {0u, kTrackedAtomic, PrefHashFilter::NO_ENFORCEMENT, 79 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}, 80 {1u, kProtectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, 81 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}}; 82 83const size_t kExtraReportingId = 2u; 84const size_t kReportingIdCount = 3u; 85 86} // namespace 87 88class ProfilePrefStoreManagerTest : public testing::Test { 89 public: 90 ProfilePrefStoreManagerTest() 91 : configuration_(kConfiguration, 92 kConfiguration + arraysize(kConfiguration)), 93 profile_pref_registry_(new user_prefs::PrefRegistrySyncable), 94 registry_verifier_(profile_pref_registry_.get()), 95 seed_("seed"), 96 reset_recorded_(false) {} 97 98 virtual void SetUp() OVERRIDE { 99 ProfilePrefStoreManager::RegisterPrefs(local_state_.registry()); 100 ProfilePrefStoreManager::RegisterProfilePrefs(profile_pref_registry_.get()); 101 for (const PrefHashFilter::TrackedPreferenceMetadata* it = kConfiguration; 102 it != kConfiguration + arraysize(kConfiguration); 103 ++it) { 104 if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { 105 profile_pref_registry_->RegisterStringPref( 106 it->name, 107 std::string(), 108 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 109 } else { 110 profile_pref_registry_->RegisterDictionaryPref( 111 it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 112 } 113 } 114 profile_pref_registry_->RegisterStringPref( 115 kUnprotectedPref, 116 std::string(), 117 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 118 119 // As in chrome_pref_service_factory.cc, kPreferencesResetTime needs to be 120 // declared as protected in order to be read from the proper store by the 121 // SegregatedPrefStore. Only declare it after configured prefs have been 122 // registered above for this test as kPreferenceResetTime is already 123 // registered in ProfilePrefStoreManager::RegisterProfilePrefs. 124 PrefHashFilter::TrackedPreferenceMetadata pref_reset_time_config = 125 {configuration_.rbegin()->reporting_id + 1, prefs::kPreferenceResetTime, 126 PrefHashFilter::ENFORCE_ON_LOAD, 127 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; 128 configuration_.push_back(pref_reset_time_config); 129 130 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); 131 ReloadConfiguration(); 132 } 133 134 void ReloadConfiguration() { 135 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), 136 configuration_, 137 kReportingIdCount, 138 seed_, 139 "device_id", 140 &local_state_)); 141 } 142 143 virtual void TearDown() OVERRIDE { DestroyPrefStore(); } 144 145 protected: 146 // Verifies whether a reset was reported via the RecordReset() hook. Also 147 // verifies that GetResetTime() was set (or not) accordingly. 148 void VerifyResetRecorded(bool reset_expected) { 149 EXPECT_EQ(reset_expected, reset_recorded_); 150 151 base::PrefServiceFactory pref_service_factory; 152 pref_service_factory.set_user_prefs(pref_store_); 153 154 scoped_ptr<PrefService> pref_service( 155 pref_service_factory.Create(profile_pref_registry_.get())); 156 157 EXPECT_EQ( 158 reset_expected, 159 !ProfilePrefStoreManager::GetResetTime(pref_service.get()).is_null()); 160 } 161 162 void ClearResetRecorded() { 163 reset_recorded_ = false; 164 165 base::PrefServiceFactory pref_service_factory; 166 pref_service_factory.set_user_prefs(pref_store_); 167 168 scoped_ptr<PrefService> pref_service( 169 pref_service_factory.Create(profile_pref_registry_.get())); 170 171 ProfilePrefStoreManager::ClearResetTime(pref_service.get()); 172 } 173 174 void InitializePrefs() { 175 // According to the implementation of ProfilePrefStoreManager, this is 176 // actually a SegregatedPrefStore backed by two underlying pref stores. 177 scoped_refptr<PersistentPrefStore> pref_store = 178 manager_->CreateProfilePrefStore( 179 main_message_loop_.message_loop_proxy(), 180 base::Bind(&ProfilePrefStoreManagerTest::RecordReset, 181 base::Unretained(this)), 182 &mock_validation_delegate_); 183 InitializePrefStore(pref_store.get()); 184 pref_store = NULL; 185 base::RunLoop().RunUntilIdle(); 186 } 187 188 void DestroyPrefStore() { 189 if (pref_store_.get()) { 190 ClearResetRecorded(); 191 // Force everything to be written to disk, triggering the PrefHashFilter 192 // while our RegistryVerifier is watching. 193 pref_store_->CommitPendingWrite(); 194 base::RunLoop().RunUntilIdle(); 195 196 pref_store_->RemoveObserver(®istry_verifier_); 197 pref_store_ = NULL; 198 // Nothing should have to happen on the background threads, but just in 199 // case... 200 base::RunLoop().RunUntilIdle(); 201 } 202 } 203 204 void InitializeDeprecatedCombinedProfilePrefStore() { 205 scoped_refptr<PersistentPrefStore> pref_store = 206 manager_->CreateDeprecatedCombinedProfilePrefStore( 207 main_message_loop_.message_loop_proxy()); 208 InitializePrefStore(pref_store.get()); 209 pref_store = NULL; 210 base::RunLoop().RunUntilIdle(); 211 } 212 213 void InitializePrefStore(PersistentPrefStore* pref_store) { 214 pref_store->AddObserver(®istry_verifier_); 215 PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); 216 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); 217 pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); 218 pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); 219 pref_store->SetValue(kUnprotectedPref, new base::StringValue(kFoobar)); 220 pref_store->RemoveObserver(®istry_verifier_); 221 pref_store->CommitPendingWrite(); 222 base::RunLoop().RunUntilIdle(); 223 } 224 225 void LoadExistingPrefs() { 226 DestroyPrefStore(); 227 pref_store_ = manager_->CreateProfilePrefStore( 228 main_message_loop_.message_loop_proxy(), 229 base::Bind(&ProfilePrefStoreManagerTest::RecordReset, 230 base::Unretained(this)), 231 NULL); 232 pref_store_->AddObserver(®istry_verifier_); 233 pref_store_->ReadPrefs(); 234 } 235 236 void ReplaceStringInPrefs(const std::string& find, 237 const std::string& replace) { 238 base::FileEnumerator file_enum( 239 profile_dir_.path(), true, base::FileEnumerator::FILES); 240 241 for (base::FilePath path = file_enum.Next(); !path.empty(); 242 path = file_enum.Next()) { 243 // Tamper with the file's contents 244 std::string contents; 245 EXPECT_TRUE(base::ReadFileToString(path, &contents)); 246 ReplaceSubstringsAfterOffset(&contents, 0u, find, replace); 247 EXPECT_EQ(static_cast<int>(contents.length()), 248 base::WriteFile(path, contents.c_str(), contents.length())); 249 } 250 } 251 252 void ExpectStringValueEquals(const std::string& name, 253 const std::string& expected) { 254 const base::Value* value = NULL; 255 std::string as_string; 256 if (!pref_store_->GetValue(name, &value)) { 257 ADD_FAILURE() << name << " is not a defined value."; 258 } else if (!value->GetAsString(&as_string)) { 259 ADD_FAILURE() << name << " could not be coerced to a string."; 260 } else { 261 EXPECT_EQ(expected, as_string); 262 } 263 } 264 265 void ExpectValidationObserved(const std::string& pref_path) { 266 // No validations are expected for platforms that do not support tracking. 267 if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking) 268 return; 269 if (!mock_validation_delegate_.GetEventForPath(pref_path)) 270 ADD_FAILURE() << "No validation observed for preference: " << pref_path; 271 } 272 273 base::MessageLoop main_message_loop_; 274 std::vector<PrefHashFilter::TrackedPreferenceMetadata> configuration_; 275 base::ScopedTempDir profile_dir_; 276 TestingPrefServiceSimple local_state_; 277 scoped_refptr<user_prefs::PrefRegistrySyncable> profile_pref_registry_; 278 RegistryVerifier registry_verifier_; 279 MockValidationDelegate mock_validation_delegate_; 280 scoped_ptr<ProfilePrefStoreManager> manager_; 281 scoped_refptr<PersistentPrefStore> pref_store_; 282 283 std::string seed_; 284 285 private: 286 void RecordReset() { 287 // As-is |reset_recorded_| is only designed to remember a single reset, make 288 // sure none was previously recorded (or that ClearResetRecorded() was 289 // called). 290 EXPECT_FALSE(reset_recorded_); 291 reset_recorded_ = true; 292 } 293 294 bool reset_recorded_; 295}; 296 297TEST_F(ProfilePrefStoreManagerTest, StoreValues) { 298 InitializePrefs(); 299 300 LoadExistingPrefs(); 301 302 ExpectStringValueEquals(kTrackedAtomic, kFoobar); 303 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 304 VerifyResetRecorded(false); 305 ExpectValidationObserved(kTrackedAtomic); 306 ExpectValidationObserved(kProtectedAtomic); 307} 308 309TEST_F(ProfilePrefStoreManagerTest, GetPrefFilePathFromProfilePath) { 310 base::FilePath pref_file_path = 311 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( 312 profile_dir_.path()); 313 314 EXPECT_FALSE(base::PathExists(pref_file_path)); 315 316 InitializePrefs(); 317 318 EXPECT_TRUE(base::PathExists(pref_file_path)); 319} 320 321TEST_F(ProfilePrefStoreManagerTest, ProtectValues) { 322 InitializePrefs(); 323 324 ReplaceStringInPrefs(kFoobar, kBarfoo); 325 ReplaceStringInPrefs(kHelloWorld, kGoodbyeWorld); 326 327 LoadExistingPrefs(); 328 329 // kTrackedAtomic is unprotected and thus will be loaded as it appears on 330 // disk. 331 ExpectStringValueEquals(kTrackedAtomic, kBarfoo); 332 333 // If preference tracking is supported, the tampered value of kProtectedAtomic 334 // will be discarded at load time, leaving this preference undefined. 335 EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 336 pref_store_->GetValue(kProtectedAtomic, NULL)); 337 VerifyResetRecorded( 338 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking); 339 340 ExpectValidationObserved(kTrackedAtomic); 341 ExpectValidationObserved(kProtectedAtomic); 342} 343 344TEST_F(ProfilePrefStoreManagerTest, MigrateFromOneFile) { 345 InitializeDeprecatedCombinedProfilePrefStore(); 346 347 // The deprecated model stores hashes in local state (on supported 348 // platforms).. 349 ASSERT_EQ( 350 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 351 local_state_.GetUserPrefValue( 352 PrefServiceHashStoreContents::kProfilePreferenceHashes) != NULL); 353 354 LoadExistingPrefs(); 355 356 // After a first migration, the hashes were copied to the two user preference 357 // files but were not cleaned. 358 ASSERT_EQ( 359 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 360 local_state_.GetUserPrefValue( 361 PrefServiceHashStoreContents::kProfilePreferenceHashes) != NULL); 362 363 ExpectStringValueEquals(kTrackedAtomic, kFoobar); 364 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 365 VerifyResetRecorded(false); 366 367 LoadExistingPrefs(); 368 369 // In a subsequent launch, the local state hash store should be reset. 370 ASSERT_FALSE(local_state_.GetUserPrefValue( 371 PrefServiceHashStoreContents::kProfilePreferenceHashes)); 372 373 ExpectStringValueEquals(kTrackedAtomic, kFoobar); 374 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 375 VerifyResetRecorded(false); 376} 377 378TEST_F(ProfilePrefStoreManagerTest, MigrateWithTampering) { 379 InitializeDeprecatedCombinedProfilePrefStore(); 380 381 ReplaceStringInPrefs(kFoobar, kBarfoo); 382 ReplaceStringInPrefs(kHelloWorld, kGoodbyeWorld); 383 384 // The deprecated model stores hashes in local state (on supported 385 // platforms).. 386 ASSERT_EQ( 387 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 388 local_state_.GetUserPrefValue( 389 PrefServiceHashStoreContents::kProfilePreferenceHashes) != NULL); 390 391 LoadExistingPrefs(); 392 393 // After a first migration, the hashes were copied to the two user preference 394 // files but were not cleaned. 395 ASSERT_EQ( 396 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 397 local_state_.GetUserPrefValue( 398 PrefServiceHashStoreContents::kProfilePreferenceHashes) != NULL); 399 400 // kTrackedAtomic is unprotected and thus will be loaded as it appears on 401 // disk. 402 ExpectStringValueEquals(kTrackedAtomic, kBarfoo); 403 404 // If preference tracking is supported, the tampered value of kProtectedAtomic 405 // will be discarded at load time, leaving this preference undefined. 406 EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 407 pref_store_->GetValue(kProtectedAtomic, NULL)); 408 VerifyResetRecorded( 409 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking); 410 411 LoadExistingPrefs(); 412 413 // In a subsequent launch, the local state hash store would be reset. 414 ASSERT_FALSE(local_state_.GetUserPrefValue( 415 PrefServiceHashStoreContents::kProfilePreferenceHashes)); 416 417 ExpectStringValueEquals(kTrackedAtomic, kBarfoo); 418 VerifyResetRecorded(false); 419} 420 421TEST_F(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) { 422 base::DictionaryValue master_prefs; 423 master_prefs.Set(kTrackedAtomic, new base::StringValue(kFoobar)); 424 master_prefs.Set(kProtectedAtomic, new base::StringValue(kHelloWorld)); 425 EXPECT_TRUE(manager_->InitializePrefsFromMasterPrefs(master_prefs)); 426 427 LoadExistingPrefs(); 428 429 // Verify that InitializePrefsFromMasterPrefs correctly applied the MACs 430 // necessary to authenticate these values. 431 ExpectStringValueEquals(kTrackedAtomic, kFoobar); 432 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 433 VerifyResetRecorded(false); 434} 435 436TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) { 437 InitializePrefs(); 438 439 ExpectValidationObserved(kTrackedAtomic); 440 ExpectValidationObserved(kProtectedAtomic); 441 442 LoadExistingPrefs(); 443 ExpectStringValueEquals(kUnprotectedPref, kFoobar); 444 445 // Ensure everything is written out to disk. 446 DestroyPrefStore(); 447 448 ReplaceStringInPrefs(kFoobar, kBarfoo); 449 450 // It's unprotected, so we can load the modified value. 451 LoadExistingPrefs(); 452 ExpectStringValueEquals(kUnprotectedPref, kBarfoo); 453 454 // Now update the configuration to protect it. 455 PrefHashFilter::TrackedPreferenceMetadata new_protected = { 456 kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, 457 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; 458 configuration_.push_back(new_protected); 459 ReloadConfiguration(); 460 461 // And try loading with the new configuration. 462 LoadExistingPrefs(); 463 464 // Since there was a valid super MAC we were able to extend the existing trust 465 // to the newly protected preference. 466 ExpectStringValueEquals(kUnprotectedPref, kBarfoo); 467 VerifyResetRecorded(false); 468 469 // Ensure everything is written out to disk. 470 DestroyPrefStore(); 471 472 // It's protected now, so (if the platform supports it) any tampering should 473 // lead to a reset. 474 ReplaceStringInPrefs(kBarfoo, kFoobar); 475 LoadExistingPrefs(); 476 EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 477 pref_store_->GetValue(kUnprotectedPref, NULL)); 478 VerifyResetRecorded( 479 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking); 480} 481 482TEST_F(ProfilePrefStoreManagerTest, NewPrefWhenFirstProtecting) { 483 std::vector<PrefHashFilter::TrackedPreferenceMetadata> 484 original_configuration = configuration_; 485 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = 486 configuration_.begin(); 487 it != configuration_.end(); 488 ++it) { 489 it->enforcement_level = PrefHashFilter::NO_ENFORCEMENT; 490 } 491 ReloadConfiguration(); 492 493 InitializePrefs(); 494 495 ExpectValidationObserved(kTrackedAtomic); 496 ExpectValidationObserved(kProtectedAtomic); 497 498 LoadExistingPrefs(); 499 ExpectStringValueEquals(kUnprotectedPref, kFoobar); 500 501 // Ensure everything is written out to disk. 502 DestroyPrefStore(); 503 504 // Now introduce protection, including the never-before tracked "new_pref". 505 configuration_ = original_configuration; 506 PrefHashFilter::TrackedPreferenceMetadata new_protected = { 507 kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, 508 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; 509 configuration_.push_back(new_protected); 510 ReloadConfiguration(); 511 512 // And try loading with the new configuration. 513 LoadExistingPrefs(); 514 515 // Since there was a valid super MAC we were able to extend the existing trust 516 // to the newly tracked & protected preference. 517 ExpectStringValueEquals(kUnprotectedPref, kFoobar); 518 VerifyResetRecorded(false); 519} 520 521TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) { 522 InitializePrefs(); 523 524 ExpectValidationObserved(kTrackedAtomic); 525 ExpectValidationObserved(kProtectedAtomic); 526 527 // Now update the configuration to protect it. 528 PrefHashFilter::TrackedPreferenceMetadata new_protected = { 529 kExtraReportingId, kUnprotectedPref, PrefHashFilter::ENFORCE_ON_LOAD, 530 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; 531 configuration_.push_back(new_protected); 532 seed_ = "new-seed-to-break-trust"; 533 ReloadConfiguration(); 534 535 // And try loading with the new configuration. 536 LoadExistingPrefs(); 537 538 // If preference tracking is supported, kUnprotectedPref will have been 539 // discarded because new values are not accepted without a valid super MAC. 540 EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, 541 pref_store_->GetValue(kUnprotectedPref, NULL)); 542 VerifyResetRecorded( 543 ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking); 544} 545 546// This test verifies that preference values are correctly maintained when a 547// preference's protection state changes from protected to unprotected. 548TEST_F(ProfilePrefStoreManagerTest, ProtectedToUnprotected) { 549 InitializePrefs(); 550 551 ExpectValidationObserved(kTrackedAtomic); 552 ExpectValidationObserved(kProtectedAtomic); 553 554 DestroyPrefStore(); 555 556 // Unconfigure protection for kProtectedAtomic 557 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = 558 configuration_.begin(); 559 it != configuration_.end(); 560 ++it) { 561 if (it->name == kProtectedAtomic) { 562 it->enforcement_level = PrefHashFilter::NO_ENFORCEMENT; 563 break; 564 } 565 } 566 567 seed_ = "new-seed-to-break-trust"; 568 ReloadConfiguration(); 569 LoadExistingPrefs(); 570 571 // Verify that the value was not reset. 572 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 573 VerifyResetRecorded(false); 574 575 // Accessing the value of the previously protected pref didn't trigger its 576 // move to the unprotected preferences file, though the loading of the pref 577 // store should still have caused the MAC store to be recalculated. 578 LoadExistingPrefs(); 579 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); 580 581 // Trigger the logic that migrates it back to the unprotected preferences 582 // file. 583 pref_store_->SetValue(kProtectedAtomic, new base::StringValue(kGoodbyeWorld)); 584 LoadExistingPrefs(); 585 ExpectStringValueEquals(kProtectedAtomic, kGoodbyeWorld); 586 VerifyResetRecorded(false); 587} 588