Index: chrome/browser/prefs/profile_pref_store_manager_unittest.cc |
diff --git a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc |
index c7bb7459d8f62393318a7f95b3d853a5451b601c..064cab0e9088b476a34ef8343cebe03b02d5a5dd 100644 |
--- a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc |
+++ b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc |
@@ -8,6 +8,7 @@ |
#include "base/compiler_specific.h" |
#include "base/file_util.h" |
+#include "base/files/file_enumerator.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/memory/ref_counted.h" |
#include "base/memory/scoped_ptr.h" |
@@ -15,6 +16,7 @@ |
#include "base/prefs/json_pref_store.h" |
#include "base/prefs/persistent_pref_store.h" |
#include "base/prefs/pref_service.h" |
+#include "base/prefs/pref_service_factory.h" |
#include "base/prefs/pref_store.h" |
#include "base/prefs/testing_pref_service.h" |
#include "base/run_loop.h" |
@@ -60,9 +62,9 @@ class RegistryVerifier : public PrefStore::Observer { |
scoped_refptr<PrefRegistry> pref_registry_; |
}; |
+const char kUnprotectedAtomic[] = "unprotected_atomic"; |
gab
2014/04/03 15:38:49
nit: s/unprotected_atomic/unprotected_pref
"atomi
|
const char kTrackedAtomic[] = "tracked_atomic"; |
const char kProtectedAtomic[] = "protected_atomic"; |
-const char kProtectedSplit[] = "protected_split"; |
const char kFoobar[] = "FOOBAR"; |
const char kBarfoo[] = "BARFOO"; |
@@ -70,12 +72,13 @@ const char kHelloWorld[] = "HELLOWORLD"; |
const char kGoodbyeWorld[] = "GOODBYEWORLD"; |
const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { |
- {0, kTrackedAtomic, PrefHashFilter::NO_ENFORCEMENT, |
+ {0u, kTrackedAtomic, PrefHashFilter::NO_ENFORCEMENT, |
PrefHashFilter::TRACKING_STRATEGY_ATOMIC}, |
- {1, kProtectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, |
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC}, |
- {2, kProtectedSplit, PrefHashFilter::ENFORCE_ON_LOAD, |
- PrefHashFilter::TRACKING_STRATEGY_SPLIT}}; |
+ {1u, kProtectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, |
+ PrefHashFilter::TRACKING_STRATEGY_ATOMIC}}; |
+ |
+const size_t kExtraReportingId = 2u; |
+const size_t kReportingIdCount = 3u; |
} // namespace |
@@ -101,17 +104,49 @@ class ProfilePrefStoreManagerTest : public testing::Test { |
it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
} |
} |
+ profile_pref_registry_->RegisterStringPref( |
+ kUnprotectedAtomic, |
+ std::string(), |
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
+ |
ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); |
+ ReloadConfiguration(); |
+ } |
+ void ReloadConfiguration() { |
manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), |
configuration_, |
- configuration_.size(), |
+ kReportingIdCount, |
"seed", |
"device_id", |
&local_state_)); |
} |
- virtual void TearDown() OVERRIDE { |
+ virtual void TearDown() OVERRIDE { DestroyPrefStore(); } |
+ |
+ protected: |
+ bool WasResetRecorded() { |
+ base::PrefServiceFactory pref_service_factory; |
+ pref_service_factory.set_user_prefs(pref_store_); |
+ |
+ scoped_ptr<PrefService> pref_service( |
+ pref_service_factory.Create(profile_pref_registry_)); |
+ |
+ return !ProfilePrefStoreManager::GetResetTime(pref_service.get()).is_null(); |
+ } |
+ |
+ void InitializePrefs() { |
+ // According to the implementation of ProfilePrefStoreManager, this is |
+ // actually a SegregatedPrefStore backed by two underlying pref stores. |
+ scoped_refptr<PersistentPrefStore> pref_store = |
+ manager_->CreateProfilePrefStore( |
+ main_message_loop_.message_loop_proxy()); |
+ InitializePrefStore(pref_store); |
+ pref_store = NULL; |
+ base::RunLoop().RunUntilIdle(); |
+ } |
+ |
+ void DestroyPrefStore() { |
if (pref_store_) { |
// Force everything to be written to disk, triggering the PrefHashFilter |
// while our RegistryVerifier is watching. |
@@ -126,42 +161,49 @@ class ProfilePrefStoreManagerTest : public testing::Test { |
} |
} |
- protected: |
- void InitializePrefs() { |
+ void InitializeDeprecatedCombinedProfilePrefStore() { |
scoped_refptr<PersistentPrefStore> pref_store = |
- manager_->CreateProfilePrefStore( |
+ manager_->CreateDeprecatedCombinedProfilePrefStore( |
main_message_loop_.message_loop_proxy()); |
+ InitializePrefStore(pref_store); |
+ pref_store = NULL; |
+ base::RunLoop().RunUntilIdle(); |
+ } |
+ |
+ void InitializePrefStore(PersistentPrefStore* pref_store) { |
pref_store->AddObserver(®istry_verifier_); |
PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); |
- ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); |
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); |
pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); |
pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); |
+ pref_store->SetValue(kUnprotectedAtomic, new base::StringValue(kFoobar)); |
pref_store->RemoveObserver(®istry_verifier_); |
- pref_store = NULL; |
+ pref_store->CommitPendingWrite(); |
base::RunLoop().RunUntilIdle(); |
} |
void LoadExistingPrefs() { |
+ DestroyPrefStore(); |
pref_store_ = manager_->CreateProfilePrefStore( |
main_message_loop_.message_loop_proxy()); |
pref_store_->AddObserver(®istry_verifier_); |
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, |
- pref_store_->ReadPrefs()); |
+ pref_store_->ReadPrefs(); |
} |
void ReplaceStringInPrefs(const std::string& find, |
const std::string& replace) { |
- // Tamper with the file's contents |
- base::FilePath pref_file_path = |
- ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( |
- profile_dir_.path()); |
- std::string pref_file_contents; |
- EXPECT_TRUE(base::ReadFileToString(pref_file_path, &pref_file_contents)); |
- ReplaceSubstringsAfterOffset(&pref_file_contents, 0u, find, replace); |
- EXPECT_EQ(static_cast<int>(pref_file_contents.length()), |
- base::WriteFile(pref_file_path, |
- pref_file_contents.c_str(), |
- pref_file_contents.length())); |
+ base::FileEnumerator file_enum( |
+ profile_dir_.path(), true, base::FileEnumerator::FILES); |
+ |
+ for (base::FilePath path = file_enum.Next(); !path.empty(); |
+ path = file_enum.Next()) { |
+ // Tamper with the file's contents |
+ std::string contents; |
+ EXPECT_TRUE(base::ReadFileToString(path, &contents)); |
+ ReplaceSubstringsAfterOffset(&contents, 0u, find, replace); |
+ EXPECT_EQ(static_cast<int>(contents.length()), |
+ base::WriteFile(path, contents.c_str(), contents.length())); |
+ } |
} |
void ExpectStringValueEquals(const std::string& name, |
@@ -194,6 +236,7 @@ TEST_F(ProfilePrefStoreManagerTest, StoreValues) { |
ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
} |
TEST_F(ProfilePrefStoreManagerTest, GetPrefFilePathFromProfilePath) { |
@@ -201,11 +244,11 @@ TEST_F(ProfilePrefStoreManagerTest, GetPrefFilePathFromProfilePath) { |
ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( |
profile_dir_.path()); |
- ASSERT_FALSE(base::PathExists(pref_file_path)); |
+ EXPECT_FALSE(base::PathExists(pref_file_path)); |
InitializePrefs(); |
- ASSERT_TRUE(base::PathExists(pref_file_path)); |
+ EXPECT_TRUE(base::PathExists(pref_file_path)); |
} |
TEST_F(ProfilePrefStoreManagerTest, ProtectValues) { |
@@ -222,8 +265,10 @@ TEST_F(ProfilePrefStoreManagerTest, ProtectValues) { |
// If preference tracking is supported, the tampered value of kProtectedAtomic |
// will be discarded at load time, leaving this preference undefined. |
- EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
pref_store_->GetValue(kProtectedAtomic, NULL)); |
+ EXPECT_EQ(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ WasResetRecorded()); |
} |
TEST_F(ProfilePrefStoreManagerTest, ResetPrefHashStore) { |
@@ -237,8 +282,10 @@ TEST_F(ProfilePrefStoreManagerTest, ResetPrefHashStore) { |
ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
// If preference tracking is supported, the tampered value of kProtectedAtomic |
// will be discarded at load time, leaving this preference undefined. |
- EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
pref_store_->GetValue(kProtectedAtomic, NULL)); |
+ EXPECT_EQ(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ WasResetRecorded()); |
} |
TEST_F(ProfilePrefStoreManagerTest, ResetAllPrefHashStores) { |
@@ -252,14 +299,32 @@ TEST_F(ProfilePrefStoreManagerTest, ResetAllPrefHashStores) { |
ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
// If preference tracking is supported, kProtectedAtomic will be undefined |
// because the value was discarded due to loss of the hash store contents. |
- EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
pref_store_->GetValue(kProtectedAtomic, NULL)); |
+ EXPECT_EQ(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ WasResetRecorded()); |
} |
-TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { |
- InitializePrefs(); |
+TEST_F(ProfilePrefStoreManagerTest, MigrateFromOneFile) { |
+ InitializeDeprecatedCombinedProfilePrefStore(); |
- manager_->ResetPrefHashStore(); |
+ LoadExistingPrefs(); |
+ |
+ ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
+ ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
+} |
+ |
+TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { |
+ scoped_refptr<JsonPrefStore> legacy_prefs( |
+ new JsonPrefStore(ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( |
+ profile_dir_.path()), |
+ main_message_loop_.message_loop_proxy(), |
+ scoped_ptr<PrefFilter>())); |
+ legacy_prefs->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); |
+ legacy_prefs->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); |
+ legacy_prefs = NULL; |
+ base::RunLoop().RunUntilIdle(); |
// This is a no-op if !kPlatformSupportsPreferenceTracking. |
manager_->UpdateProfileHashStoreIfRequired( |
@@ -273,6 +338,7 @@ TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { |
// These expectations hold whether or not tracking is supported. |
ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
} |
TEST_F(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) { |
@@ -280,7 +346,7 @@ TEST_F(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) { |
new base::DictionaryValue); |
master_prefs->Set(kTrackedAtomic, new base::StringValue(kFoobar)); |
master_prefs->Set(kProtectedAtomic, new base::StringValue(kHelloWorld)); |
- ASSERT_TRUE( |
+ EXPECT_TRUE( |
manager_->InitializePrefsFromMasterPrefs(*master_prefs)); |
LoadExistingPrefs(); |
@@ -289,4 +355,113 @@ TEST_F(ProfilePrefStoreManagerTest, InitializePrefsFromMasterPrefs) { |
// necessary to authenticate these values. |
ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
+} |
+ |
+TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) { |
+ InitializePrefs(); |
+ LoadExistingPrefs(); |
+ ExpectStringValueEquals(kUnprotectedAtomic, kFoobar); |
+ |
+ // Ensure everything is written out to disk. |
+ DestroyPrefStore(); |
+ |
+ ReplaceStringInPrefs(kFoobar, kBarfoo); |
+ |
+ // It's unprotected, so we can load the modified value. |
+ LoadExistingPrefs(); |
+ ExpectStringValueEquals(kUnprotectedAtomic, kBarfoo); |
+ |
+ // Now update the configuration to protect it. |
+ PrefHashFilter::TrackedPreferenceMetadata new_protected = { |
+ kExtraReportingId, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, |
+ PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; |
+ configuration_.push_back(new_protected); |
+ ReloadConfiguration(); |
+ |
+ // And try loading with the new configuration. |
+ LoadExistingPrefs(); |
+ |
+ // Since there was a valid super MAC we were able to extend the existing trust |
+ // to the newly proteted preference. |
+ ExpectStringValueEquals(kUnprotectedAtomic, kBarfoo); |
+ EXPECT_FALSE(WasResetRecorded()); |
+ |
+ // Ensure everything is written out to disk. |
+ DestroyPrefStore(); |
+ |
+ // It's protected now, so (if the platform supports it) any tampering should |
+ // lead to a reset. |
+ ReplaceStringInPrefs(kBarfoo, kFoobar); |
+ LoadExistingPrefs(); |
+ EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ pref_store_->GetValue(kUnprotectedAtomic, NULL)); |
+ EXPECT_EQ(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ WasResetRecorded()); |
+} |
+ |
+TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) { |
+ InitializePrefs(); |
+ |
+ // Now update the configuration to protect it. |
+ PrefHashFilter::TrackedPreferenceMetadata new_protected = { |
+ kExtraReportingId, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, |
+ PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; |
+ configuration_.push_back(new_protected); |
+ ReloadConfiguration(); |
+ ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); |
+ |
+ // And try loading with the new configuration. |
+ LoadExistingPrefs(); |
+ |
+ // If preference tracking is supported, kUnprotectedAtomic will have been |
+ // discarded because new values are not accepted without a valid super MAC. |
+ EXPECT_NE(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ pref_store_->GetValue(kUnprotectedAtomic, NULL)); |
+ EXPECT_EQ(ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
+ WasResetRecorded()); |
+} |
+ |
+// This test does not directly verify that the values are moved from one pref |
+// store to the other. segregated_pref_store_unittest.cc _does_ verify that |
+// functionality. |
+// |
+// _This_ test verifies that preference values are correctly maintained when a |
+// preference's protection state changes from protected to unprotected. |
+TEST_F(ProfilePrefStoreManagerTest, ProtectedToUnprotected) { |
+ InitializePrefs(); |
+ DestroyPrefStore(); |
+ |
+ // Unconfigure protection for kProtectedAtomic |
+ for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = |
+ configuration_.begin(); |
+ it != configuration_.end(); |
+ ++it) { |
+ if (it->name == kProtectedAtomic) { |
+ configuration_.erase(it); |
+ break; |
+ } |
+ } |
+ ReloadConfiguration(); |
+ |
+ // Reset the hash stores and then try loading the prefs. |
+ ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); |
+ LoadExistingPrefs(); |
+ |
+ // Verify that the value was not reset. |
+ ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
+ |
+ // Accessing the value of the previously protected pref didn't trigger its |
+ // move to the unprotected preferences file, though the loading of the pref |
+ // store should still have caused the MAC store to be recalculated. |
+ LoadExistingPrefs(); |
+ ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
+ |
+ // Trigger the logic that migrates it back to the unprotected preferences |
+ // file. |
+ pref_store_->SetValue(kProtectedAtomic, new base::StringValue(kGoodbyeWorld)); |
+ LoadExistingPrefs(); |
+ ExpectStringValueEquals(kProtectedAtomic, kGoodbyeWorld); |
+ EXPECT_FALSE(WasResetRecorded()); |
} |