Home | History | Annotate | Download | only in prefs
      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