Add GCMChannelStatusSyncer to schedule requests and enable/disable GCM
[chromium-blink-merge.git] / chrome / browser / prefs / profile_pref_store_manager_unittest.cc
blob9f26fd359ce74e6e0c8e92d5da69e07170abb713
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.
5 #include "chrome/browser/prefs/profile_pref_store_manager.h"
7 #include <vector>
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"
32 namespace {
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_;
42 private:
43 const std::string expected_;
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) {}
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.";
62 virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {}
64 private:
65 scoped_refptr<PrefRegistry> pref_registry_;
68 const char kUnprotectedPref[] = "unprotected_pref";
69 const char kTrackedAtomic[] = "tracked_atomic";
70 const char kProtectedAtomic[] = "protected_atomic";
72 const char kFoobar[] = "FOOBAR";
73 const char kBarfoo[] = "BARFOO";
74 const char kHelloWorld[] = "HELLOWORLD";
75 const char kGoodbyeWorld[] = "GOODBYEWORLD";
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}};
83 const size_t kExtraReportingId = 2u;
84 const size_t kReportingIdCount = 3u;
86 } // namespace
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_.get()),
95 seed_("seed"),
96 reset_recorded_(false) {}
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);
114 profile_pref_registry_->RegisterStringPref(
115 kUnprotectedPref,
116 std::string(),
117 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
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);
130 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
131 ReloadConfiguration();
134 void ReloadConfiguration() {
135 manager_.reset(new ProfilePrefStoreManager(profile_dir_.path(),
136 configuration_,
137 kReportingIdCount,
138 seed_,
139 "device_id",
140 &local_state_));
143 virtual void TearDown() OVERRIDE { DestroyPrefStore(); }
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_);
151 base::PrefServiceFactory pref_service_factory;
152 pref_service_factory.set_user_prefs(pref_store_);
154 scoped_ptr<PrefService> pref_service(
155 pref_service_factory.Create(profile_pref_registry_.get()));
157 EXPECT_EQ(
158 reset_expected,
159 !ProfilePrefStoreManager::GetResetTime(pref_service.get()).is_null());
162 void ClearResetRecorded() {
163 reset_recorded_ = false;
165 base::PrefServiceFactory pref_service_factory;
166 pref_service_factory.set_user_prefs(pref_store_);
168 scoped_ptr<PrefService> pref_service(
169 pref_service_factory.Create(profile_pref_registry_.get()));
171 ProfilePrefStoreManager::ClearResetTime(pref_service.get());
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();
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();
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();
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();
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();
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();
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);
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()));
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);
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;
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_;
283 std::string seed_;
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;
294 bool reset_recorded_;
297 TEST_F(ProfilePrefStoreManagerTest, StoreValues) {
298 InitializePrefs();
300 LoadExistingPrefs();
302 ExpectStringValueEquals(kTrackedAtomic, kFoobar);
303 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld);
304 VerifyResetRecorded(false);
305 ExpectValidationObserved(kTrackedAtomic);
306 ExpectValidationObserved(kProtectedAtomic);
309 TEST_F(ProfilePrefStoreManagerTest, GetPrefFilePathFromProfilePath) {
310 base::FilePath pref_file_path =
311 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
312 profile_dir_.path());
314 EXPECT_FALSE(base::PathExists(pref_file_path));
316 InitializePrefs();
318 EXPECT_TRUE(base::PathExists(pref_file_path));
321 TEST_F(ProfilePrefStoreManagerTest, ProtectValues) {
322 InitializePrefs();
324 ReplaceStringInPrefs(kFoobar, kBarfoo);
325 ReplaceStringInPrefs(kHelloWorld, kGoodbyeWorld);
327 LoadExistingPrefs();
329 // kTrackedAtomic is unprotected and thus will be loaded as it appears on
330 // disk.
331 ExpectStringValueEquals(kTrackedAtomic, kBarfoo);
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);
340 ExpectValidationObserved(kTrackedAtomic);
341 ExpectValidationObserved(kProtectedAtomic);
344 TEST_F(ProfilePrefStoreManagerTest, MigrateFromOneFile) {
345 InitializeDeprecatedCombinedProfilePrefStore();
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);
354 LoadExistingPrefs();
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);
363 ExpectStringValueEquals(kTrackedAtomic, kFoobar);
364 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld);
365 VerifyResetRecorded(false);
367 LoadExistingPrefs();
369 // In a subsequent launch, the local state hash store should be reset.
370 ASSERT_FALSE(local_state_.GetUserPrefValue(
371 PrefServiceHashStoreContents::kProfilePreferenceHashes));
373 ExpectStringValueEquals(kTrackedAtomic, kFoobar);
374 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld);
375 VerifyResetRecorded(false);
378 TEST_F(ProfilePrefStoreManagerTest, MigrateWithTampering) {
379 InitializeDeprecatedCombinedProfilePrefStore();
381 ReplaceStringInPrefs(kFoobar, kBarfoo);
382 ReplaceStringInPrefs(kHelloWorld, kGoodbyeWorld);
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);
391 LoadExistingPrefs();
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);
400 // kTrackedAtomic is unprotected and thus will be loaded as it appears on
401 // disk.
402 ExpectStringValueEquals(kTrackedAtomic, kBarfoo);
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);
411 LoadExistingPrefs();
413 // In a subsequent launch, the local state hash store would be reset.
414 ASSERT_FALSE(local_state_.GetUserPrefValue(
415 PrefServiceHashStoreContents::kProfilePreferenceHashes));
417 ExpectStringValueEquals(kTrackedAtomic, kBarfoo);
418 VerifyResetRecorded(false);
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));
427 LoadExistingPrefs();
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);
436 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtected) {
437 InitializePrefs();
439 ExpectValidationObserved(kTrackedAtomic);
440 ExpectValidationObserved(kProtectedAtomic);
442 LoadExistingPrefs();
443 ExpectStringValueEquals(kUnprotectedPref, kFoobar);
445 // Ensure everything is written out to disk.
446 DestroyPrefStore();
448 ReplaceStringInPrefs(kFoobar, kBarfoo);
450 // It's unprotected, so we can load the modified value.
451 LoadExistingPrefs();
452 ExpectStringValueEquals(kUnprotectedPref, kBarfoo);
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();
461 // And try loading with the new configuration.
462 LoadExistingPrefs();
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);
469 // Ensure everything is written out to disk.
470 DestroyPrefStore();
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);
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;
491 ReloadConfiguration();
493 InitializePrefs();
495 ExpectValidationObserved(kTrackedAtomic);
496 ExpectValidationObserved(kProtectedAtomic);
498 LoadExistingPrefs();
499 ExpectStringValueEquals(kUnprotectedPref, kFoobar);
501 // Ensure everything is written out to disk.
502 DestroyPrefStore();
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();
512 // And try loading with the new configuration.
513 LoadExistingPrefs();
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);
521 TEST_F(ProfilePrefStoreManagerTest, UnprotectedToProtectedWithoutTrust) {
522 InitializePrefs();
524 ExpectValidationObserved(kTrackedAtomic);
525 ExpectValidationObserved(kProtectedAtomic);
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();
535 // And try loading with the new configuration.
536 LoadExistingPrefs();
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);
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();
551 ExpectValidationObserved(kTrackedAtomic);
552 ExpectValidationObserved(kProtectedAtomic);
554 DestroyPrefStore();
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;
567 seed_ = "new-seed-to-break-trust";
568 ReloadConfiguration();
569 LoadExistingPrefs();
571 // Verify that the value was not reset.
572 ExpectStringValueEquals(kProtectedAtomic, kHelloWorld);
573 VerifyResetRecorded(false);
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);
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);