Home | History | Annotate | Download | only in prefs
      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/file_util.h"
     11 #include "base/files/file_enumerator.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 
     32 namespace {
     33 
     34 class 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.
     48 class 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 
     68 const char kUnprotectedPref[] = "unprotected_pref";
     69 const char kTrackedAtomic[] = "tracked_atomic";
     70 const char kProtectedAtomic[] = "protected_atomic";
     71 
     72 const char kFoobar[] = "FOOBAR";
     73 const char kBarfoo[] = "BARFOO";
     74 const char kHelloWorld[] = "HELLOWORLD";
     75 const char kGoodbyeWorld[] = "GOODBYEWORLD";
     76 
     77 const 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 
     83 const size_t kExtraReportingId = 2u;
     84 const size_t kReportingIdCount = 3u;
     85 
     86 }  // namespace
     87 
     88 class 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_),
     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_);
    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_));
    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_));
    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);
    184     pref_store = NULL;
    185     base::RunLoop().RunUntilIdle();
    186   }
    187 
    188   void DestroyPrefStore() {
    189     if (pref_store_) {
    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(&registry_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);
    209     pref_store = NULL;
    210     base::RunLoop().RunUntilIdle();
    211   }
    212 
    213   void InitializePrefStore(PersistentPrefStore* pref_store) {
    214     pref_store->AddObserver(&registry_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(&registry_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(&registry_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 
    297 TEST_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 
    309 TEST_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 
    321 TEST_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 
    344 TEST_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 
    378 TEST_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 
    421 TEST_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 
    436 TEST_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 
    482 TEST_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 
    521 TEST_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.
    548 TEST_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