pref_hash_filter_unittest.cc 55 KB

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