OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/prefs/profile_pref_store_manager.h" | 5 #include "chrome/browser/prefs/profile_pref_store_manager.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/files/file_enumerator.h" | |
11 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
12 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
14 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
15 #include "base/prefs/json_pref_store.h" | 16 #include "base/prefs/json_pref_store.h" |
16 #include "base/prefs/persistent_pref_store.h" | 17 #include "base/prefs/persistent_pref_store.h" |
17 #include "base/prefs/pref_service.h" | 18 #include "base/prefs/pref_service.h" |
18 #include "base/prefs/pref_store.h" | 19 #include "base/prefs/pref_store.h" |
19 #include "base/prefs/testing_pref_service.h" | 20 #include "base/prefs/testing_pref_service.h" |
20 #include "base/run_loop.h" | 21 #include "base/run_loop.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 pref_registry_->end(), | 53 pref_registry_->end(), |
53 FirstEqualsPredicate(key))); | 54 FirstEqualsPredicate(key))); |
54 } | 55 } |
55 | 56 |
56 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} | 57 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} |
57 | 58 |
58 private: | 59 private: |
59 scoped_refptr<PrefRegistry> pref_registry_; | 60 scoped_refptr<PrefRegistry> pref_registry_; |
60 }; | 61 }; |
61 | 62 |
63 const char kUnprotectedAtomic[] = "unprotected_atomic"; | |
62 const char kTrackedAtomic[] = "tracked_atomic"; | 64 const char kTrackedAtomic[] = "tracked_atomic"; |
63 const char kProtectedAtomic[] = "protected_atomic"; | 65 const char kProtectedAtomic[] = "protected_atomic"; |
64 const char kProtectedSplit[] = "protected_split"; | 66 const char kProtectedSplit[] = "protected_split"; |
65 | 67 |
66 const char kFoobar[] = "FOOBAR"; | 68 const char kFoobar[] = "FOOBAR"; |
67 const char kBarfoo[] = "BARFOO"; | 69 const char kBarfoo[] = "BARFOO"; |
68 const char kHelloWorld[] = "HELLOWORLD"; | 70 const char kHelloWorld[] = "HELLOWORLD"; |
69 const char kGoodbyeWorld[] = "GOODBYEWORLD"; | 71 const char kGoodbyeWorld[] = "GOODBYEWORLD"; |
70 | 72 |
71 const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { | 73 const PrefHashFilter::TrackedPreferenceMetadata kConfiguration[] = { |
(...skipping 21 matching lines...) Expand all Loading... | |
93 it != kConfiguration + arraysize(kConfiguration); | 95 it != kConfiguration + arraysize(kConfiguration); |
94 ++it) { | 96 ++it) { |
95 if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { | 97 if (it->strategy == PrefHashFilter::TRACKING_STRATEGY_ATOMIC) { |
96 profile_pref_registry_->RegisterStringPref( | 98 profile_pref_registry_->RegisterStringPref( |
97 it->name, "", user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 99 it->name, "", user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
98 } else { | 100 } else { |
99 profile_pref_registry_->RegisterDictionaryPref( | 101 profile_pref_registry_->RegisterDictionaryPref( |
100 it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 102 it->name, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
101 } | 103 } |
102 } | 104 } |
105 profile_pref_registry_->RegisterStringPref( | |
106 kUnprotectedAtomic, | |
107 "", | |
108 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
109 | |
103 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); | 110 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); |
111 ReloadConfiguration(); | |
112 } | |
104 | 113 |
114 void ReloadConfiguration() { | |
105 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), | 115 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(), |
106 configuration_, | 116 configuration_, |
107 configuration_.size(), | 117 configuration_.size(), |
108 "seed", | 118 "seed", |
109 "device_id", | 119 "device_id", |
110 &local_state_)); | 120 &local_state_)); |
111 } | 121 } |
112 | 122 |
113 virtual void TearDown() OVERRIDE { | 123 virtual void TearDown() OVERRIDE { DestroyPrefStore(); } |
124 | |
125 protected: | |
126 void InitializePrefs() { | |
127 scoped_refptr<PersistentPrefStore> pref_store = | |
128 manager_->CreateProfilePrefStore( | |
129 main_message_loop_.message_loop_proxy()); | |
130 InitializePrefStore(pref_store); | |
131 pref_store = NULL; | |
132 base::RunLoop().RunUntilIdle(); | |
133 } | |
134 void DestroyPrefStore() { | |
114 if (pref_store_) { | 135 if (pref_store_) { |
115 // Force everything to be written to disk, triggering the PrefHashFilter | 136 // Force everything to be written to disk, triggering the PrefHashFilter |
116 // while our RegistryVerifier is watching. | 137 // while our RegistryVerifier is watching. |
117 pref_store_->CommitPendingWrite(); | 138 pref_store_->CommitPendingWrite(); |
118 base::RunLoop().RunUntilIdle(); | 139 base::RunLoop().RunUntilIdle(); |
119 | 140 |
120 pref_store_->RemoveObserver(®istry_verifier_); | 141 pref_store_->RemoveObserver(®istry_verifier_); |
121 pref_store_ = NULL; | 142 pref_store_ = NULL; |
122 // Nothing should have to happen on the background threads, but just in | 143 // Nothing should have to happen on the background threads, but just in |
123 // case... | 144 // case... |
124 base::RunLoop().RunUntilIdle(); | 145 base::RunLoop().RunUntilIdle(); |
125 } | 146 } |
126 } | 147 } |
127 | 148 |
128 protected: | 149 void InitializeDeprecatedCombinedProfilePrefStore() { |
129 void InitializePrefs() { | |
130 scoped_refptr<PersistentPrefStore> pref_store = | 150 scoped_refptr<PersistentPrefStore> pref_store = |
131 manager_->CreateProfilePrefStore( | 151 manager_->CreateDeprecatedCombinedProfilePrefStore( |
132 main_message_loop_.message_loop_proxy()); | 152 main_message_loop_.message_loop_proxy()); |
153 InitializePrefStore(pref_store); | |
154 pref_store = NULL; | |
155 base::RunLoop().RunUntilIdle(); | |
156 } | |
157 | |
158 void InitializePrefStore(PersistentPrefStore* pref_store) { | |
133 pref_store->AddObserver(®istry_verifier_); | 159 pref_store->AddObserver(®istry_verifier_); |
134 PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); | 160 PersistentPrefStore::PrefReadError error = pref_store->ReadPrefs(); |
135 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); | 161 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, error); |
136 pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); | 162 pref_store->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); |
137 pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); | 163 pref_store->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); |
164 pref_store->SetValue(kUnprotectedAtomic, new base::StringValue(kFoobar)); | |
138 pref_store->RemoveObserver(®istry_verifier_); | 165 pref_store->RemoveObserver(®istry_verifier_); |
139 pref_store = NULL; | 166 pref_store->CommitPendingWrite(); |
140 base::RunLoop().RunUntilIdle(); | 167 base::RunLoop().RunUntilIdle(); |
141 } | 168 } |
142 | 169 |
143 void LoadExistingPrefs() { | 170 void LoadExistingPrefs() { |
171 DestroyPrefStore(); | |
144 pref_store_ = manager_->CreateProfilePrefStore( | 172 pref_store_ = manager_->CreateProfilePrefStore( |
145 main_message_loop_.message_loop_proxy()); | 173 main_message_loop_.message_loop_proxy()); |
146 pref_store_->AddObserver(®istry_verifier_); | 174 pref_store_->AddObserver(®istry_verifier_); |
147 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, | 175 pref_store_->ReadPrefs(); |
148 pref_store_->ReadPrefs()); | |
149 } | 176 } |
150 | 177 |
151 void ReplaceStringInPrefs(const std::string& find, | 178 void ReplaceStringInPrefs(const std::string& find, |
152 const std::string& replace) { | 179 const std::string& replace) { |
153 // Tamper with the file's contents | 180 base::FileEnumerator file_enumerator( |
154 base::FilePath pref_file_path = | 181 profile_dir_.path(), true, base::FileEnumerator::FILES); |
155 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( | 182 |
156 profile_dir_.path()); | 183 base::FilePath pref_file_path; |
157 std::string pref_file_contents; | 184 while (!(pref_file_path = file_enumerator.Next()).empty()) { |
158 EXPECT_TRUE(base::ReadFileToString(pref_file_path, &pref_file_contents)); | 185 // Tamper with the file's contents |
159 ReplaceSubstringsAfterOffset(&pref_file_contents, 0u, find, replace); | 186 std::string pref_file_contents; |
160 EXPECT_EQ(static_cast<int>(pref_file_contents.length()), | 187 EXPECT_TRUE(base::ReadFileToString(pref_file_path, &pref_file_contents)); |
161 base::WriteFile(pref_file_path, | 188 ReplaceSubstringsAfterOffset(&pref_file_contents, 0u, find, replace); |
162 pref_file_contents.c_str(), | 189 EXPECT_EQ((int)pref_file_contents.length(), |
163 pref_file_contents.length())); | 190 base::WriteFile(pref_file_path, |
191 pref_file_contents.c_str(), | |
192 pref_file_contents.length())); | |
193 } | |
164 } | 194 } |
165 | 195 |
166 void ExpectStringValueEquals(const std::string& name, | 196 void ExpectStringValueEquals(const std::string& name, |
167 const std::string& expected) { | 197 const std::string& expected) { |
168 const base::Value* value = NULL; | 198 const base::Value* value = NULL; |
169 std::string as_string; | 199 std::string as_string; |
170 if (!pref_store_->GetValue(name, &value)) { | 200 if (!pref_store_->GetValue(name, &value)) { |
171 ADD_FAILURE() << name << " is not a defined value."; | 201 ADD_FAILURE() << name << " is not a defined value."; |
172 } else if (!value->GetAsString(&as_string)) { | 202 } else if (!value->GetAsString(&as_string)) { |
173 ADD_FAILURE() << name << " could not be coerced to a string."; | 203 ADD_FAILURE() << name << " could not be coerced to a string."; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 LoadExistingPrefs(); | 278 LoadExistingPrefs(); |
249 | 279 |
250 // kTrackedAtomic is loaded as it appears on disk. | 280 // kTrackedAtomic is loaded as it appears on disk. |
251 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | 281 ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
252 // If preference tracking is supported, kProtectedAtomic will be undefined | 282 // If preference tracking is supported, kProtectedAtomic will be undefined |
253 // because the value was discarded due to loss of the hash store contents. | 283 // because the value was discarded due to loss of the hash store contents. |
254 EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, | 284 EXPECT_EQ(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking, |
255 pref_store_->GetValue(kProtectedAtomic, NULL)); | 285 pref_store_->GetValue(kProtectedAtomic, NULL)); |
256 } | 286 } |
257 | 287 |
288 TEST_F(ProfilePrefStoreManagerTest, MigrateFromOneFile) { | |
289 InitializeDeprecatedCombinedProfilePrefStore(); | |
290 | |
291 LoadExistingPrefs(); | |
292 | |
293 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | |
294 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
295 } | |
296 | |
258 TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { | 297 TEST_F(ProfilePrefStoreManagerTest, UpdateProfileHashStoreIfRequired) { |
259 InitializePrefs(); | 298 scoped_refptr<JsonPrefStore> legacy_prefs( |
260 | 299 new JsonPrefStore(ProfilePrefStoreManager::GetPrefFilePathFromProfilePath( |
261 manager_->ResetPrefHashStore(); | 300 profile_dir_.path()), |
301 main_message_loop_.message_loop_proxy(), | |
302 scoped_ptr<PrefFilter>())); | |
303 legacy_prefs->SetValue(kTrackedAtomic, new base::StringValue(kFoobar)); | |
304 legacy_prefs->SetValue(kProtectedAtomic, new base::StringValue(kHelloWorld)); | |
305 legacy_prefs = NULL; | |
306 base::RunLoop().RunUntilIdle(); | |
262 | 307 |
263 // This is a no-op if !kPlatformSupportsPreferenceTracking. | 308 // This is a no-op if !kPlatformSupportsPreferenceTracking. |
264 manager_->UpdateProfileHashStoreIfRequired( | 309 manager_->UpdateProfileHashStoreIfRequired( |
265 main_message_loop_.message_loop_proxy()); | 310 main_message_loop_.message_loop_proxy()); |
266 base::RunLoop().RunUntilIdle(); | 311 base::RunLoop().RunUntilIdle(); |
267 | 312 |
268 // At the moment, UpdateProfileHashStoreIfRequired will accept existing | 313 // At the moment, UpdateProfileHashStoreIfRequired will accept existing |
269 // values. | 314 // values. |
270 LoadExistingPrefs(); | 315 LoadExistingPrefs(); |
271 | 316 |
(...skipping 10 matching lines...) Expand all Loading... | |
282 ASSERT_TRUE( | 327 ASSERT_TRUE( |
283 manager_->InitializePrefsFromMasterPrefs(*master_prefs)); | 328 manager_->InitializePrefsFromMasterPrefs(*master_prefs)); |
284 | 329 |
285 LoadExistingPrefs(); | 330 LoadExistingPrefs(); |
286 | 331 |
287 // Verify that InitializePrefsFromMasterPrefs correctly applied the MACs | 332 // Verify that InitializePrefsFromMasterPrefs correctly applied the MACs |
288 // necessary to authenticate these values. | 333 // necessary to authenticate these values. |
289 ExpectStringValueEquals(kTrackedAtomic, kFoobar); | 334 ExpectStringValueEquals(kTrackedAtomic, kFoobar); |
290 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | 335 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); |
291 } | 336 } |
337 | |
338 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) { | |
339 InitializePrefs(); | |
340 LoadExistingPrefs(); | |
341 ExpectStringValueEquals(kUnprotectedAtomic, kFoobar); | |
342 | |
343 PrefHashFilter::TrackedPreferenceMetadata new_protected = { | |
344 99u, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, | |
345 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; | |
346 configuration_.push_back(new_protected); | |
347 ReloadConfiguration(); | |
348 LoadExistingPrefs(); | |
349 ExpectStringValueEquals(kUnprotectedAtomic, kFoobar); | |
350 } | |
351 | |
352 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) { | |
robertshield
2014/03/25 03:05:12
Can we add a test that simulates partial migration
erikwright (departed)
2014/03/25 20:28:26
Yes. That's a bit trickier so I'm going to upload
| |
353 InitializePrefs(); | |
354 PrefHashFilter::TrackedPreferenceMetadata new_protected = { | |
355 99u, kUnprotectedAtomic, PrefHashFilter::ENFORCE_ON_LOAD, | |
356 PrefHashFilter::TRACKING_STRATEGY_ATOMIC}; | |
357 configuration_.push_back(new_protected); | |
358 ReloadConfiguration(); | |
359 ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); | |
360 | |
361 LoadExistingPrefs(); | |
362 ASSERT_FALSE(pref_store_->GetValue(kUnprotectedAtomic, NULL)); | |
363 } | |
364 | |
365 | |
366 TEST_F(ProfilePrefStoreManagerTest, ProtectedToUnprotected) { | |
367 InitializePrefs(); | |
368 ProfilePrefStoreManager::ResetAllPrefHashStores(&local_state_); | |
369 | |
370 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = | |
371 configuration_.begin(); | |
372 it != configuration_.end(); | |
373 ++it) { | |
374 if (it->name == std::string(kProtectedAtomic)) { | |
375 configuration_.erase(it); | |
376 break; | |
377 } | |
378 } | |
379 | |
380 ReloadConfiguration(); | |
381 | |
382 LoadExistingPrefs(); | |
383 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
384 | |
385 // Accessing the value of the previously proteted pref didn't trigger its move | |
386 // to the unprotected preferences file, though the loading of the pref store | |
387 // should still have caused the MAC store to be recalculated. | |
388 LoadExistingPrefs(); | |
389 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld); | |
390 | |
391 // Trigger the logic that migrates it back to the unprotected preferences | |
392 // file. | |
393 pref_store_->SetValue(kProtectedAtomic, new base::StringValue(kGoodbyeWorld)); | |
394 LoadExistingPrefs(); | |
395 ExpectStringValueEquals(kProtectedAtomic, kGoodbyeWorld); | |
396 } | |
397 | |
398 // Add test coverage for when Reset events should and should not be recorded. | |
OLD | NEW |