1 // Copyright 2013 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/pref_hash_filter.h" 6 7 #include <map> 8 #include <set> 9 #include <string> 10 #include <utility> 11 #include <vector> 12 13 #include "base/basictypes.h" 14 #include "base/bind.h" 15 #include "base/callback_forward.h" 16 #include "base/compiler_specific.h" 17 #include "base/logging.h" 18 #include "base/memory/ref_counted.h" 19 #include "base/memory/scoped_ptr.h" 20 #include "base/metrics/histogram_base.h" 21 #include "base/metrics/histogram_samples.h" 22 #include "base/metrics/statistics_recorder.h" 23 #include "base/prefs/testing_pref_store.h" 24 #include "base/values.h" 25 #include "chrome/browser/prefs/mock_validation_delegate.h" 26 #include "chrome/browser/prefs/pref_hash_store.h" 27 #include "chrome/browser/prefs/pref_hash_store_transaction.h" 28 #include "chrome/browser/prefs/tracked/hash_store_contents.h" 29 #include "chrome/common/pref_names.h" 30 #include "testing/gtest/include/gtest/gtest.h" 31 32 namespace { 33 34 const char kAtomicPref[] = "atomic_pref"; 35 const char kAtomicPref2[] = "atomic_pref2"; 36 const char kAtomicPref3[] = "pref3"; 37 const char kAtomicPref4[] = "pref4"; 38 const char kReportOnlyPref[] = "report_only"; 39 const char kReportOnlySplitPref[] = "report_only_split_pref"; 40 const char kSplitPref[] = "split_pref"; 41 42 const PrefHashFilter::TrackedPreferenceMetadata kTestTrackedPrefs[] = { 43 { 44 0, kAtomicPref, PrefHashFilter::ENFORCE_ON_LOAD, 45 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 46 }, 47 { 48 1, kReportOnlyPref, PrefHashFilter::NO_ENFORCEMENT, 49 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 50 }, 51 { 52 2, kSplitPref, PrefHashFilter::ENFORCE_ON_LOAD, 53 PrefHashFilter::TRACKING_STRATEGY_SPLIT 54 }, 55 { 56 3, kReportOnlySplitPref, PrefHashFilter::NO_ENFORCEMENT, 57 PrefHashFilter::TRACKING_STRATEGY_SPLIT 58 }, 59 { 60 4, kAtomicPref2, PrefHashFilter::ENFORCE_ON_LOAD, 61 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 62 }, 63 { 64 5, kAtomicPref3, PrefHashFilter::ENFORCE_ON_LOAD, 65 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 66 }, 67 { 68 6, kAtomicPref4, PrefHashFilter::ENFORCE_ON_LOAD, 69 PrefHashFilter::TRACKING_STRATEGY_ATOMIC 70 }, 71 }; 72 73 } // namespace 74 75 // A PrefHashStore that allows simulation of CheckValue results and captures 76 // checked and stored values. 77 class MockPrefHashStore : public PrefHashStore { 78 public: 79 typedef std::pair<const void*, PrefHashFilter::PrefTrackingStrategy> 80 ValuePtrStrategyPair; 81 82 MockPrefHashStore() 83 : stamp_super_mac_result_(false), 84 is_super_mac_valid_result_(false), 85 transactions_performed_(0), 86 transaction_active_(false) {} 87 88 virtual ~MockPrefHashStore() { 89 EXPECT_FALSE(transaction_active_); 90 } 91 92 // Set the result that will be returned when |path| is passed to 93 // |CheckValue/CheckSplitValue|. 94 void SetCheckResult(const std::string& path, 95 PrefHashStoreTransaction::ValueState result); 96 97 // Set the invalid_keys that will be returned when |path| is passed to 98 // |CheckSplitValue|. SetCheckResult should already have been called for 99 // |path| with |result == CHANGED| for this to make any sense. 100 void SetInvalidKeysResult( 101 const std::string& path, 102 const std::vector<std::string>& invalid_keys_result); 103 104 // Sets the value that will be returned from 105 // PrefHashStoreTransaction::StampSuperMAC(). 106 void set_stamp_super_mac_result(bool result) { 107 stamp_super_mac_result_ = result; 108 } 109 110 // Sets the value that will be returned from 111 // PrefHashStoreTransaction::IsSuperMACValid(). 112 void set_is_super_mac_valid_result(bool result) { 113 is_super_mac_valid_result_ = result; 114 } 115 116 // Returns the number of transactions that were performed. 117 size_t transactions_performed() { return transactions_performed_; } 118 119 // Returns the number of paths checked. 120 size_t checked_paths_count() const { 121 return checked_values_.size(); 122 } 123 124 // Returns the number of paths stored. 125 size_t stored_paths_count() const { 126 return stored_values_.size(); 127 } 128 129 // Returns the pointer value and strategy that was passed to 130 // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since 131 // have been freed and is thus not safe to dereference. 132 ValuePtrStrategyPair checked_value(const std::string& path) const { 133 std::map<std::string, ValuePtrStrategyPair>::const_iterator value = 134 checked_values_.find(path); 135 if (value != checked_values_.end()) 136 return value->second; 137 return std::make_pair( 138 reinterpret_cast<void*>(0xBAD), 139 static_cast<PrefHashFilter::PrefTrackingStrategy>(-1)); 140 } 141 142 // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for 143 // |path|. The returned pointer could since have been freed and is thus not 144 // safe to dereference. 145 ValuePtrStrategyPair stored_value(const std::string& path) const { 146 std::map<std::string, ValuePtrStrategyPair>::const_iterator value = 147 stored_values_.find(path); 148 if (value != stored_values_.end()) 149 return value->second; 150 return std::make_pair( 151 reinterpret_cast<void*>(0xBAD), 152 static_cast<PrefHashFilter::PrefTrackingStrategy>(-1)); 153 } 154 155 // PrefHashStore implementation. 156 virtual scoped_ptr<PrefHashStoreTransaction> BeginTransaction( 157 scoped_ptr<HashStoreContents> storage) OVERRIDE; 158 159 private: 160 // A MockPrefHashStoreTransaction is handed to the caller on 161 // MockPrefHashStore::BeginTransaction(). It then stores state in its 162 // underlying MockPrefHashStore about calls it receives from that same caller 163 // which can later be verified in tests. 164 class MockPrefHashStoreTransaction : public PrefHashStoreTransaction { 165 public: 166 explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer) 167 : outer_(outer) {} 168 169 virtual ~MockPrefHashStoreTransaction() { 170 outer_->transaction_active_ = false; 171 ++outer_->transactions_performed_; 172 } 173 174 // PrefHashStoreTransaction implementation. 175 virtual PrefHashStoreTransaction::ValueState CheckValue( 176 const std::string& path, const base::Value* value) const OVERRIDE; 177 virtual void StoreHash(const std::string& path, 178 const base::Value* new_value) OVERRIDE; 179 virtual PrefHashStoreTransaction::ValueState CheckSplitValue( 180 const std::string& path, 181 const base::DictionaryValue* initial_split_value, 182 std::vector<std::string>* invalid_keys) const OVERRIDE; 183 virtual void StoreSplitHash( 184 const std::string& path, 185 const base::DictionaryValue* split_value) OVERRIDE; 186 virtual bool HasHash(const std::string& path) const OVERRIDE; 187 virtual void ImportHash(const std::string& path, 188 const base::Value* hash) OVERRIDE; 189 virtual void ClearHash(const std::string& path) OVERRIDE; 190 virtual bool IsSuperMACValid() const OVERRIDE; 191 virtual bool StampSuperMac() OVERRIDE; 192 193 private: 194 MockPrefHashStore* outer_; 195 196 DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction); 197 }; 198 199 // Records a call to this mock's CheckValue/CheckSplitValue methods. 200 PrefHashStoreTransaction::ValueState RecordCheckValue( 201 const std::string& path, 202 const base::Value* value, 203 PrefHashFilter::PrefTrackingStrategy strategy); 204 205 // Records a call to this mock's StoreHash/StoreSplitHash methods. 206 void RecordStoreHash(const std::string& path, 207 const base::Value* new_value, 208 PrefHashFilter::PrefTrackingStrategy strategy); 209 210 std::map<std::string, PrefHashStoreTransaction::ValueState> check_results_; 211 std::map<std::string, std::vector<std::string> > invalid_keys_results_; 212 213 bool stamp_super_mac_result_; 214 bool is_super_mac_valid_result_; 215 216 std::map<std::string, ValuePtrStrategyPair> checked_values_; 217 std::map<std::string, ValuePtrStrategyPair> stored_values_; 218 219 // Number of transactions that are expected to be performed in the scope of 220 // this test (defaults to 1). 221 size_t transactions_expected_; 222 223 // Number of transactions that were performed via this MockPrefHashStore. 224 // Verified to match |transactions_expected_| when this MockPrefHashStore is 225 // deleted. 226 size_t transactions_performed_; 227 228 // Whether a transaction is currently active (only one transaction should be 229 // active at a time). 230 bool transaction_active_; 231 232 DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore); 233 }; 234 235 void MockPrefHashStore::SetCheckResult( 236 const std::string& path, PrefHashStoreTransaction::ValueState result) { 237 check_results_.insert(std::make_pair(path, result)); 238 } 239 240 void MockPrefHashStore::SetInvalidKeysResult( 241 const std::string& path, 242 const std::vector<std::string>& invalid_keys_result) { 243 // Ensure |check_results_| has a CHANGED entry for |path|. 244 std::map<std::string, 245 PrefHashStoreTransaction::ValueState>::const_iterator result = 246 check_results_.find(path); 247 ASSERT_TRUE(result != check_results_.end()); 248 ASSERT_EQ(PrefHashStoreTransaction::CHANGED, result->second); 249 250 invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result)); 251 } 252 253 scoped_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction( 254 scoped_ptr<HashStoreContents> storage) { 255 EXPECT_FALSE(transaction_active_); 256 return scoped_ptr<PrefHashStoreTransaction>( 257 new MockPrefHashStoreTransaction(this)); 258 } 259 260 PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue( 261 const std::string& path, 262 const base::Value* value, 263 PrefHashFilter::PrefTrackingStrategy strategy) { 264 // Record that |path| was checked and validate that it wasn't previously 265 // checked. 266 EXPECT_TRUE(checked_values_.insert( 267 std::make_pair(path, std::make_pair(value, strategy))).second); 268 std::map<std::string, 269 PrefHashStoreTransaction::ValueState>::const_iterator result = 270 check_results_.find(path); 271 if (result != check_results_.end()) 272 return result->second; 273 return PrefHashStoreTransaction::UNCHANGED; 274 } 275 276 void MockPrefHashStore::RecordStoreHash( 277 const std::string& path, 278 const base::Value* new_value, 279 PrefHashFilter::PrefTrackingStrategy strategy) { 280 EXPECT_TRUE(stored_values_.insert( 281 std::make_pair(path, std::make_pair(new_value, strategy))).second); 282 } 283 284 PrefHashStoreTransaction::ValueState 285 MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue( 286 const std::string& path, const base::Value* value) const { 287 return outer_->RecordCheckValue(path, value, 288 PrefHashFilter::TRACKING_STRATEGY_ATOMIC); 289 } 290 291 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash( 292 const std::string& path, 293 const base::Value* new_value) { 294 outer_->RecordStoreHash(path, new_value, 295 PrefHashFilter::TRACKING_STRATEGY_ATOMIC); 296 } 297 298 PrefHashStoreTransaction::ValueState 299 MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue( 300 const std::string& path, 301 const base::DictionaryValue* initial_split_value, 302 std::vector<std::string>* invalid_keys) const { 303 EXPECT_TRUE(invalid_keys && invalid_keys->empty()); 304 305 std::map<std::string, std::vector<std::string> >::const_iterator 306 invalid_keys_result = outer_->invalid_keys_results_.find(path); 307 if (invalid_keys_result != outer_->invalid_keys_results_.end()) { 308 invalid_keys->insert(invalid_keys->begin(), 309 invalid_keys_result->second.begin(), 310 invalid_keys_result->second.end()); 311 } 312 313 return outer_->RecordCheckValue(path, initial_split_value, 314 PrefHashFilter::TRACKING_STRATEGY_SPLIT); 315 } 316 317 void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash( 318 const std::string& path, 319 const base::DictionaryValue* new_value) { 320 outer_->RecordStoreHash(path, new_value, 321 PrefHashFilter::TRACKING_STRATEGY_SPLIT); 322 } 323 324 bool MockPrefHashStore::MockPrefHashStoreTransaction::HasHash( 325 const std::string& path) const { 326 ADD_FAILURE() << "Unexpected call."; 327 return false; 328 } 329 330 void MockPrefHashStore::MockPrefHashStoreTransaction::ImportHash( 331 const std::string& path, 332 const base::Value* hash) { 333 ADD_FAILURE() << "Unexpected call."; 334 } 335 336 void MockPrefHashStore::MockPrefHashStoreTransaction::ClearHash( 337 const std::string& path) { 338 // Allow this to be called by PrefHashFilter's deprecated tracked prefs 339 // cleanup tasks. 340 } 341 342 bool MockPrefHashStore::MockPrefHashStoreTransaction::IsSuperMACValid() const { 343 return outer_->is_super_mac_valid_result_; 344 } 345 346 bool MockPrefHashStore::MockPrefHashStoreTransaction::StampSuperMac() { 347 return outer_->stamp_super_mac_result_; 348 } 349 350 std::vector<PrefHashFilter::TrackedPreferenceMetadata> GetConfiguration( 351 PrefHashFilter::EnforcementLevel max_enforcement_level) { 352 std::vector<PrefHashFilter::TrackedPreferenceMetadata> configuration( 353 kTestTrackedPrefs, kTestTrackedPrefs + arraysize(kTestTrackedPrefs)); 354 for (std::vector<PrefHashFilter::TrackedPreferenceMetadata>::iterator it = 355 configuration.begin(); 356 it != configuration.end(); 357 ++it) { 358 if (it->enforcement_level > max_enforcement_level) 359 it->enforcement_level = max_enforcement_level; 360 } 361 return configuration; 362 } 363 364 class PrefHashFilterTest 365 : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> { 366 public: 367 PrefHashFilterTest() : mock_pref_hash_store_(NULL), 368 pref_store_contents_(new base::DictionaryValue), 369 last_filter_on_load_modified_prefs_(false), 370 reset_recorded_(false) {} 371 372 virtual void SetUp() OVERRIDE { 373 base::StatisticsRecorder::Initialize(); 374 Reset(); 375 } 376 377 protected: 378 // Reset the PrefHashFilter instance. 379 void Reset() { 380 // Construct a PrefHashFilter and MockPrefHashStore for the test. 381 InitializePrefHashFilter(GetConfiguration(GetParam())); 382 } 383 384 // Initializes |pref_hash_filter_| with a PrefHashFilter that uses a 385 // MockPrefHashStore. The raw pointer to the MockPrefHashStore (owned by the 386 // PrefHashFilter) is stored in |mock_pref_hash_store_|. 387 void InitializePrefHashFilter(const std::vector< 388 PrefHashFilter::TrackedPreferenceMetadata>& configuration) { 389 scoped_ptr<MockPrefHashStore> temp_mock_pref_hash_store( 390 new MockPrefHashStore); 391 mock_pref_hash_store_ = temp_mock_pref_hash_store.get(); 392 pref_hash_filter_.reset(new PrefHashFilter( 393 temp_mock_pref_hash_store.PassAs<PrefHashStore>(), 394 configuration, 395 base::Bind(&PrefHashFilterTest::RecordReset, base::Unretained(this)), 396 &mock_validation_delegate_, 397 arraysize(kTestTrackedPrefs), 398 true)); 399 } 400 401 // Verifies whether a reset was reported by the PrefHashFiler. Also verifies 402 // that kPreferenceResetTime was set (or not) accordingly. 403 void VerifyRecordedReset(bool reset_expected) { 404 EXPECT_EQ(reset_expected, reset_recorded_); 405 EXPECT_EQ(reset_expected, 406 pref_store_contents_->Get(prefs::kPreferenceResetTime, NULL)); 407 } 408 409 // Calls FilterOnLoad() on |pref_hash_Filter_|. |pref_store_contents_| is 410 // handed off, but should be given back to us synchronously through 411 // GetPrefsBack() as there is no FilterOnLoadInterceptor installed on 412 // |pref_hash_filter_|. 413 void DoFilterOnLoad(bool expect_prefs_modifications) { 414 pref_hash_filter_->FilterOnLoad( 415 base::Bind(&PrefHashFilterTest::GetPrefsBack, base::Unretained(this), 416 expect_prefs_modifications), 417 pref_store_contents_.Pass()); 418 } 419 420 MockPrefHashStore* mock_pref_hash_store_; 421 scoped_ptr<base::DictionaryValue> pref_store_contents_; 422 bool last_filter_on_load_modified_prefs_; 423 MockValidationDelegate mock_validation_delegate_; 424 scoped_ptr<PrefHashFilter> pref_hash_filter_; 425 426 private: 427 // Stores |prefs| back in |pref_store_contents| and ensure 428 // |expected_schedule_write| matches the reported |schedule_write|. 429 void GetPrefsBack(bool expected_schedule_write, 430 scoped_ptr<base::DictionaryValue> prefs, 431 bool schedule_write) { 432 pref_store_contents_ = prefs.Pass(); 433 EXPECT_TRUE(pref_store_contents_); 434 EXPECT_EQ(expected_schedule_write, schedule_write); 435 } 436 437 void RecordReset() { 438 // As-is |reset_recorded_| is only designed to remember a single reset, make 439 // sure none was previously recorded. 440 EXPECT_FALSE(reset_recorded_); 441 reset_recorded_ = true; 442 } 443 444 bool reset_recorded_; 445 446 DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest); 447 }; 448 449 TEST_P(PrefHashFilterTest, EmptyAndUnchanged) { 450 DoFilterOnLoad(false); 451 // All paths checked. 452 ASSERT_EQ(arraysize(kTestTrackedPrefs), 453 mock_pref_hash_store_->checked_paths_count()); 454 // No paths stored, since they all return |UNCHANGED|. 455 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 456 // Since there was nothing in |pref_store_contents_| the checked value should 457 // have been NULL for all tracked preferences. 458 for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) { 459 ASSERT_EQ(NULL, mock_pref_hash_store_->checked_value( 460 kTestTrackedPrefs[i].name).first); 461 } 462 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 463 VerifyRecordedReset(false); 464 465 // Delegate saw all paths, and all unchanged. 466 ASSERT_EQ(arraysize(kTestTrackedPrefs), 467 mock_validation_delegate_.recorded_validations_count()); 468 ASSERT_EQ(arraysize(kTestTrackedPrefs), 469 mock_validation_delegate_.CountValidationsOfState( 470 PrefHashStoreTransaction::UNCHANGED)); 471 } 472 473 TEST_P(PrefHashFilterTest, StampSuperMACAltersStore) { 474 mock_pref_hash_store_->set_stamp_super_mac_result(true); 475 DoFilterOnLoad(true); 476 // No paths stored, since they all return |UNCHANGED|. The StampSuperMAC 477 // result is the only reason the prefs were considered altered. 478 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 479 } 480 481 TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) { 482 base::DictionaryValue root_dict; 483 // Ownership of |string_value| is transfered to |root_dict|. 484 base::Value* string_value = new base::StringValue("string value"); 485 root_dict.Set(kAtomicPref, string_value); 486 487 // No path should be stored on FilterUpdate. 488 pref_hash_filter_->FilterUpdate(kAtomicPref); 489 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 490 491 // One path should be stored on FilterSerializeData. 492 pref_hash_filter_->FilterSerializeData(&root_dict); 493 ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count()); 494 MockPrefHashStore::ValuePtrStrategyPair stored_value = 495 mock_pref_hash_store_->stored_value(kAtomicPref); 496 ASSERT_EQ(string_value, stored_value.first); 497 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, stored_value.second); 498 499 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 500 VerifyRecordedReset(false); 501 } 502 503 TEST_P(PrefHashFilterTest, ReportSuperMacValidity) { 504 // Do this once just to force the histogram to be defined. 505 DoFilterOnLoad(false); 506 507 base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram( 508 "Settings.HashesDictionaryTrusted"); 509 ASSERT_TRUE(histogram); 510 511 base::HistogramBase::Count initial_untrusted = 512 histogram->SnapshotSamples()->GetCount(0); 513 base::HistogramBase::Count initial_trusted = 514 histogram->SnapshotSamples()->GetCount(1); 515 516 Reset(); 517 518 // Run with an invalid super MAC. 519 mock_pref_hash_store_->set_is_super_mac_valid_result(false); 520 521 DoFilterOnLoad(false); 522 523 // Verify that the invalidity was reported. 524 ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0)); 525 ASSERT_EQ(initial_trusted, histogram->SnapshotSamples()->GetCount(1)); 526 527 Reset(); 528 529 // Run with a valid super MAC. 530 mock_pref_hash_store_->set_is_super_mac_valid_result(true); 531 532 DoFilterOnLoad(false); 533 534 // Verify that the validity was reported. 535 ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0)); 536 ASSERT_EQ(initial_trusted + 1, histogram->SnapshotSamples()->GetCount(1)); 537 } 538 539 TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) { 540 base::DictionaryValue root_dict; 541 // Ownership of |dict_value| is transfered to |root_dict|. 542 base::DictionaryValue* dict_value = new base::DictionaryValue; 543 dict_value->SetString("a", "foo"); 544 dict_value->SetInteger("b", 1234); 545 root_dict.Set(kSplitPref, dict_value); 546 547 // No path should be stored on FilterUpdate. 548 pref_hash_filter_->FilterUpdate(kSplitPref); 549 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 550 551 // One path should be stored on FilterSerializeData. 552 pref_hash_filter_->FilterSerializeData(&root_dict); 553 ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count()); 554 MockPrefHashStore::ValuePtrStrategyPair stored_value = 555 mock_pref_hash_store_->stored_value(kSplitPref); 556 ASSERT_EQ(dict_value, stored_value.first); 557 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value.second); 558 559 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 560 VerifyRecordedReset(false); 561 } 562 563 TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) { 564 base::DictionaryValue root_dict; 565 root_dict.Set("untracked", new base::StringValue("some value")); 566 pref_hash_filter_->FilterUpdate("untracked"); 567 568 // No paths should be stored on FilterUpdate. 569 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 570 571 // Nor on FilterSerializeData. 572 pref_hash_filter_->FilterSerializeData(&root_dict); 573 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 574 575 // No transaction should even be started on FilterSerializeData() if there are 576 // no updates to perform. 577 ASSERT_EQ(0u, mock_pref_hash_store_->transactions_performed()); 578 } 579 580 TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) { 581 base::DictionaryValue root_dict; 582 // Ownership of the following values is transfered to |root_dict|. 583 base::Value* int_value1 = new base::FundamentalValue(1); 584 base::Value* int_value2 = new base::FundamentalValue(2); 585 base::Value* int_value3 = new base::FundamentalValue(3); 586 base::Value* int_value4 = new base::FundamentalValue(4); 587 base::DictionaryValue* dict_value = new base::DictionaryValue; 588 dict_value->Set("a", new base::FundamentalValue(true)); 589 root_dict.Set(kAtomicPref, int_value1); 590 root_dict.Set(kAtomicPref2, int_value2); 591 root_dict.Set(kAtomicPref3, int_value3); 592 root_dict.Set("untracked", int_value4); 593 root_dict.Set(kSplitPref, dict_value); 594 595 // Only update kAtomicPref, kAtomicPref3, and kSplitPref. 596 pref_hash_filter_->FilterUpdate(kAtomicPref); 597 pref_hash_filter_->FilterUpdate(kAtomicPref3); 598 pref_hash_filter_->FilterUpdate(kSplitPref); 599 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 600 601 // Update kAtomicPref3 again, nothing should be stored still. 602 base::Value* int_value5 = new base::FundamentalValue(5); 603 root_dict.Set(kAtomicPref3, int_value5); 604 ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count()); 605 606 // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref 607 // should get a new hash. 608 pref_hash_filter_->FilterSerializeData(&root_dict); 609 ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count()); 610 MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 = 611 mock_pref_hash_store_->stored_value(kAtomicPref); 612 ASSERT_EQ(int_value1, stored_value_atomic1.first); 613 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 614 stored_value_atomic1.second); 615 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 616 617 MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 = 618 mock_pref_hash_store_->stored_value(kAtomicPref3); 619 ASSERT_EQ(int_value5, stored_value_atomic3.first); 620 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 621 stored_value_atomic3.second); 622 623 MockPrefHashStore::ValuePtrStrategyPair stored_value_split = 624 mock_pref_hash_store_->stored_value(kSplitPref); 625 ASSERT_EQ(dict_value, stored_value_split.first); 626 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, stored_value_split.second); 627 } 628 629 TEST_P(PrefHashFilterTest, EmptyAndUnknown) { 630 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 631 ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL)); 632 // NULL values are always trusted by the PrefHashStore. 633 mock_pref_hash_store_->SetCheckResult( 634 kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE); 635 mock_pref_hash_store_->SetCheckResult( 636 kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE); 637 DoFilterOnLoad(false); 638 ASSERT_EQ(arraysize(kTestTrackedPrefs), 639 mock_pref_hash_store_->checked_paths_count()); 640 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 641 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 642 643 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 644 mock_pref_hash_store_->stored_value(kAtomicPref); 645 ASSERT_EQ(NULL, stored_atomic_value.first); 646 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 647 stored_atomic_value.second); 648 649 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 650 mock_pref_hash_store_->stored_value(kSplitPref); 651 ASSERT_EQ(NULL, stored_split_value.first); 652 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 653 stored_split_value.second); 654 655 // Delegate saw all prefs, two of which had the expected value_state. 656 ASSERT_EQ(arraysize(kTestTrackedPrefs), 657 mock_validation_delegate_.recorded_validations_count()); 658 ASSERT_EQ(2u, 659 mock_validation_delegate_.CountValidationsOfState( 660 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE)); 661 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, 662 mock_validation_delegate_.CountValidationsOfState( 663 PrefHashStoreTransaction::UNCHANGED)); 664 665 const MockValidationDelegate::ValidationEvent* validated_split_pref = 666 mock_validation_delegate_.GetEventForPath(kSplitPref); 667 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 668 validated_split_pref->strategy); 669 EXPECT_EQ(TrackedPreferenceHelper::DONT_RESET, 670 validated_split_pref->reset_action); 671 const MockValidationDelegate::ValidationEvent* validated_atomic_pref = 672 mock_validation_delegate_.GetEventForPath(kAtomicPref); 673 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 674 validated_atomic_pref->strategy); 675 EXPECT_EQ(TrackedPreferenceHelper::DONT_RESET, 676 validated_atomic_pref->reset_action); 677 } 678 679 TEST_P(PrefHashFilterTest, InitialValueUnknown) { 680 // Ownership of these values is transfered to |pref_store_contents_|. 681 base::StringValue* string_value = new base::StringValue("string value"); 682 pref_store_contents_->Set(kAtomicPref, string_value); 683 684 base::DictionaryValue* dict_value = new base::DictionaryValue; 685 dict_value->SetString("a", "foo"); 686 dict_value->SetInteger("b", 1234); 687 pref_store_contents_->Set(kSplitPref, dict_value); 688 689 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL)); 690 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL)); 691 692 mock_pref_hash_store_->SetCheckResult( 693 kAtomicPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE); 694 mock_pref_hash_store_->SetCheckResult( 695 kSplitPref, PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE); 696 // If we are enforcing, expect this to report changes. 697 DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); 698 ASSERT_EQ(arraysize(kTestTrackedPrefs), 699 mock_pref_hash_store_->checked_paths_count()); 700 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 701 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 702 703 // Delegate saw all prefs, two of which had the expected value_state. 704 ASSERT_EQ(arraysize(kTestTrackedPrefs), 705 mock_validation_delegate_.recorded_validations_count()); 706 ASSERT_EQ(2u, 707 mock_validation_delegate_.CountValidationsOfState( 708 PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE)); 709 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, 710 mock_validation_delegate_.CountValidationsOfState( 711 PrefHashStoreTransaction::UNCHANGED)); 712 713 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 714 mock_pref_hash_store_->stored_value(kAtomicPref); 715 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 716 mock_pref_hash_store_->stored_value(kSplitPref); 717 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 718 stored_atomic_value.second); 719 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 720 stored_split_value.second); 721 if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { 722 // Ensure the prefs were cleared and the hashes for NULL were restored if 723 // the current enforcement level denies seeding. 724 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 725 ASSERT_EQ(NULL, stored_atomic_value.first); 726 727 ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL)); 728 ASSERT_EQ(NULL, stored_split_value.first); 729 730 VerifyRecordedReset(true); 731 } else { 732 // Otherwise the values should have remained intact and the hashes should 733 // have been updated to match them. 734 const base::Value* atomic_value_in_store; 735 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store)); 736 ASSERT_EQ(string_value, atomic_value_in_store); 737 ASSERT_EQ(string_value, stored_atomic_value.first); 738 739 const base::Value* split_value_in_store; 740 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); 741 ASSERT_EQ(dict_value, split_value_in_store); 742 ASSERT_EQ(dict_value, stored_split_value.first); 743 744 VerifyRecordedReset(false); 745 } 746 } 747 748 TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) { 749 // Ownership of this value is transfered to |pref_store_contents_|. 750 base::Value* string_value = new base::StringValue("test"); 751 pref_store_contents_->Set(kAtomicPref, string_value); 752 753 base::DictionaryValue* dict_value = new base::DictionaryValue; 754 dict_value->SetString("a", "foo"); 755 dict_value->SetInteger("b", 1234); 756 pref_store_contents_->Set(kSplitPref, dict_value); 757 758 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL)); 759 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL)); 760 761 mock_pref_hash_store_->SetCheckResult( 762 kAtomicPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE); 763 mock_pref_hash_store_->SetCheckResult( 764 kSplitPref, PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE); 765 DoFilterOnLoad(false); 766 ASSERT_EQ(arraysize(kTestTrackedPrefs), 767 mock_pref_hash_store_->checked_paths_count()); 768 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 769 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 770 771 // Delegate saw all prefs, two of which had the expected value_state. 772 ASSERT_EQ(arraysize(kTestTrackedPrefs), 773 mock_validation_delegate_.recorded_validations_count()); 774 ASSERT_EQ(2u, 775 mock_validation_delegate_.CountValidationsOfState( 776 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE)); 777 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, 778 mock_validation_delegate_.CountValidationsOfState( 779 PrefHashStoreTransaction::UNCHANGED)); 780 781 // Seeding is always allowed for trusted unknown values. 782 const base::Value* atomic_value_in_store; 783 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store)); 784 ASSERT_EQ(string_value, atomic_value_in_store); 785 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 786 mock_pref_hash_store_->stored_value(kAtomicPref); 787 ASSERT_EQ(string_value, stored_atomic_value.first); 788 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 789 stored_atomic_value.second); 790 791 const base::Value* split_value_in_store; 792 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); 793 ASSERT_EQ(dict_value, split_value_in_store); 794 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 795 mock_pref_hash_store_->stored_value(kSplitPref); 796 ASSERT_EQ(dict_value, stored_split_value.first); 797 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 798 stored_split_value.second); 799 } 800 801 TEST_P(PrefHashFilterTest, InitialValueChanged) { 802 // Ownership of this value is transfered to |pref_store_contents_|. 803 base::Value* int_value = new base::FundamentalValue(1234); 804 pref_store_contents_->Set(kAtomicPref, int_value); 805 806 base::DictionaryValue* dict_value = new base::DictionaryValue; 807 dict_value->SetString("a", "foo"); 808 dict_value->SetInteger("b", 1234); 809 dict_value->SetInteger("c", 56); 810 dict_value->SetBoolean("d", false); 811 pref_store_contents_->Set(kSplitPref, dict_value); 812 813 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL)); 814 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL)); 815 816 mock_pref_hash_store_->SetCheckResult(kAtomicPref, 817 PrefHashStoreTransaction::CHANGED); 818 mock_pref_hash_store_->SetCheckResult(kSplitPref, 819 PrefHashStoreTransaction::CHANGED); 820 821 std::vector<std::string> mock_invalid_keys; 822 mock_invalid_keys.push_back("a"); 823 mock_invalid_keys.push_back("c"); 824 mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys); 825 826 DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); 827 ASSERT_EQ(arraysize(kTestTrackedPrefs), 828 mock_pref_hash_store_->checked_paths_count()); 829 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 830 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 831 832 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 833 mock_pref_hash_store_->stored_value(kAtomicPref); 834 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 835 mock_pref_hash_store_->stored_value(kSplitPref); 836 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 837 stored_atomic_value.second); 838 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 839 stored_split_value.second); 840 if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { 841 // Ensure the atomic pref was cleared and the hash for NULL was restored if 842 // the current enforcement level prevents changes. 843 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 844 ASSERT_EQ(NULL, stored_atomic_value.first); 845 846 // The split pref on the other hand should only have been stripped of its 847 // invalid keys. 848 const base::Value* split_value_in_store; 849 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); 850 ASSERT_EQ(2U, dict_value->size()); 851 ASSERT_FALSE(dict_value->HasKey("a")); 852 ASSERT_TRUE(dict_value->HasKey("b")); 853 ASSERT_FALSE(dict_value->HasKey("c")); 854 ASSERT_TRUE(dict_value->HasKey("d")); 855 ASSERT_EQ(dict_value, stored_split_value.first); 856 857 VerifyRecordedReset(true); 858 } else { 859 // Otherwise the value should have remained intact and the hash should have 860 // been updated to match it. 861 const base::Value* atomic_value_in_store; 862 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store)); 863 ASSERT_EQ(int_value, atomic_value_in_store); 864 ASSERT_EQ(int_value, stored_atomic_value.first); 865 866 const base::Value* split_value_in_store; 867 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); 868 ASSERT_EQ(dict_value, split_value_in_store); 869 ASSERT_EQ(4U, dict_value->size()); 870 ASSERT_TRUE(dict_value->HasKey("a")); 871 ASSERT_TRUE(dict_value->HasKey("b")); 872 ASSERT_TRUE(dict_value->HasKey("c")); 873 ASSERT_TRUE(dict_value->HasKey("d")); 874 ASSERT_EQ(dict_value, stored_split_value.first); 875 876 VerifyRecordedReset(false); 877 } 878 } 879 880 TEST_P(PrefHashFilterTest, EmptyCleared) { 881 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 882 ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL)); 883 mock_pref_hash_store_->SetCheckResult(kAtomicPref, 884 PrefHashStoreTransaction::CLEARED); 885 mock_pref_hash_store_->SetCheckResult(kSplitPref, 886 PrefHashStoreTransaction::CLEARED); 887 DoFilterOnLoad(false); 888 ASSERT_EQ(arraysize(kTestTrackedPrefs), 889 mock_pref_hash_store_->checked_paths_count()); 890 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 891 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 892 893 // Delegate saw all prefs, two of which had the expected value_state. 894 ASSERT_EQ(arraysize(kTestTrackedPrefs), 895 mock_validation_delegate_.recorded_validations_count()); 896 ASSERT_EQ(2u, 897 mock_validation_delegate_.CountValidationsOfState( 898 PrefHashStoreTransaction::CLEARED)); 899 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, 900 mock_validation_delegate_.CountValidationsOfState( 901 PrefHashStoreTransaction::UNCHANGED)); 902 903 // Regardless of the enforcement level, the only thing that should be done is 904 // to restore the hash for NULL. The value itself should still be NULL. 905 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 906 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 907 mock_pref_hash_store_->stored_value(kAtomicPref); 908 ASSERT_EQ(NULL, stored_atomic_value.first); 909 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 910 stored_atomic_value.second); 911 912 ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL)); 913 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 914 mock_pref_hash_store_->stored_value(kSplitPref); 915 ASSERT_EQ(NULL, stored_split_value.first); 916 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 917 stored_split_value.second); 918 } 919 920 TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) { 921 // Ownership of these values is transfered to |pref_store_contents_|. 922 base::StringValue* string_value = new base::StringValue("string value"); 923 pref_store_contents_->Set(kAtomicPref, string_value); 924 925 base::DictionaryValue* dict_value = new base::DictionaryValue; 926 dict_value->SetString("a", "foo"); 927 dict_value->SetInteger("b", 1234); 928 pref_store_contents_->Set(kSplitPref, dict_value); 929 930 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL)); 931 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL)); 932 933 mock_pref_hash_store_->SetCheckResult( 934 kAtomicPref, PrefHashStoreTransaction::SECURE_LEGACY); 935 mock_pref_hash_store_->SetCheckResult( 936 kSplitPref, PrefHashStoreTransaction::SECURE_LEGACY); 937 DoFilterOnLoad(false); 938 ASSERT_EQ(arraysize(kTestTrackedPrefs), 939 mock_pref_hash_store_->checked_paths_count()); 940 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 941 942 // Delegate saw all prefs, two of which had the expected value_state. 943 ASSERT_EQ(arraysize(kTestTrackedPrefs), 944 mock_validation_delegate_.recorded_validations_count()); 945 ASSERT_EQ(2u, 946 mock_validation_delegate_.CountValidationsOfState( 947 PrefHashStoreTransaction::SECURE_LEGACY)); 948 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, 949 mock_validation_delegate_.CountValidationsOfState( 950 PrefHashStoreTransaction::UNCHANGED)); 951 952 // Ensure that both the atomic and split hashes were restored. 953 ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count()); 954 955 // In all cases, the values should have remained intact and the hashes should 956 // have been updated to match them. 957 958 MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value = 959 mock_pref_hash_store_->stored_value(kAtomicPref); 960 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_ATOMIC, 961 stored_atomic_value.second); 962 const base::Value* atomic_value_in_store; 963 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store)); 964 ASSERT_EQ(string_value, atomic_value_in_store); 965 ASSERT_EQ(string_value, stored_atomic_value.first); 966 967 MockPrefHashStore::ValuePtrStrategyPair stored_split_value = 968 mock_pref_hash_store_->stored_value(kSplitPref); 969 ASSERT_EQ(PrefHashFilter::TRACKING_STRATEGY_SPLIT, 970 stored_split_value.second); 971 const base::Value* split_value_in_store; 972 ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store)); 973 ASSERT_EQ(dict_value, split_value_in_store); 974 ASSERT_EQ(dict_value, stored_split_value.first); 975 976 VerifyRecordedReset(false); 977 } 978 979 TEST_P(PrefHashFilterTest, DontResetReportOnly) { 980 // Ownership of these values is transfered to |pref_store_contents_|. 981 base::Value* int_value1 = new base::FundamentalValue(1); 982 base::Value* int_value2 = new base::FundamentalValue(2); 983 base::Value* report_only_val = new base::FundamentalValue(3); 984 base::DictionaryValue* report_only_split_val = new base::DictionaryValue; 985 report_only_split_val->SetInteger("a", 1234); 986 pref_store_contents_->Set(kAtomicPref, int_value1); 987 pref_store_contents_->Set(kAtomicPref2, int_value2); 988 pref_store_contents_->Set(kReportOnlyPref, report_only_val); 989 pref_store_contents_->Set(kReportOnlySplitPref, report_only_split_val); 990 991 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL)); 992 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL)); 993 ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL)); 994 ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL)); 995 996 mock_pref_hash_store_->SetCheckResult(kAtomicPref, 997 PrefHashStoreTransaction::CHANGED); 998 mock_pref_hash_store_->SetCheckResult(kAtomicPref2, 999 PrefHashStoreTransaction::CHANGED); 1000 mock_pref_hash_store_->SetCheckResult(kReportOnlyPref, 1001 PrefHashStoreTransaction::CHANGED); 1002 mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref, 1003 PrefHashStoreTransaction::CHANGED); 1004 1005 DoFilterOnLoad(GetParam() >= PrefHashFilter::ENFORCE_ON_LOAD); 1006 // All prefs should be checked and a new hash should be stored for each tested 1007 // pref. 1008 ASSERT_EQ(arraysize(kTestTrackedPrefs), 1009 mock_pref_hash_store_->checked_paths_count()); 1010 ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count()); 1011 ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed()); 1012 1013 // Delegate saw all prefs, four of which had the expected value_state. 1014 ASSERT_EQ(arraysize(kTestTrackedPrefs), 1015 mock_validation_delegate_.recorded_validations_count()); 1016 ASSERT_EQ(4u, 1017 mock_validation_delegate_.CountValidationsOfState( 1018 PrefHashStoreTransaction::CHANGED)); 1019 ASSERT_EQ(arraysize(kTestTrackedPrefs) - 4u, 1020 mock_validation_delegate_.CountValidationsOfState( 1021 PrefHashStoreTransaction::UNCHANGED)); 1022 1023 // No matter what the enforcement level is, the report only pref should never 1024 // be reset. 1025 ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL)); 1026 ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL)); 1027 ASSERT_EQ(report_only_val, 1028 mock_pref_hash_store_->stored_value(kReportOnlyPref).first); 1029 ASSERT_EQ(report_only_split_val, 1030 mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first); 1031 1032 // All other prefs should have been reset if the enforcement level allows it. 1033 if (GetParam() == PrefHashFilter::ENFORCE_ON_LOAD) { 1034 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL)); 1035 ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref2, NULL)); 1036 ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first); 1037 ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first); 1038 1039 VerifyRecordedReset(true); 1040 } else { 1041 const base::Value* value_in_store; 1042 const base::Value* value_in_store2; 1043 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &value_in_store)); 1044 ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, &value_in_store2)); 1045 ASSERT_EQ(int_value1, value_in_store); 1046 ASSERT_EQ(int_value1, 1047 mock_pref_hash_store_->stored_value(kAtomicPref).first); 1048 ASSERT_EQ(int_value2, value_in_store2); 1049 ASSERT_EQ(int_value2, 1050 mock_pref_hash_store_->stored_value(kAtomicPref2).first); 1051 1052 VerifyRecordedReset(false); 1053 } 1054 } 1055 1056 INSTANTIATE_TEST_CASE_P( 1057 PrefHashFilterTestInstance, PrefHashFilterTest, 1058 testing::Values(PrefHashFilter::NO_ENFORCEMENT, 1059 PrefHashFilter::ENFORCE_ON_LOAD)); 1060