pref_hash_store_impl_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  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_store_impl.h"
  5. #include <string>
  6. #include "base/values.h"
  7. #include "services/preferences/tracked/dictionary_hash_store_contents.h"
  8. #include "services/preferences/tracked/hash_store_contents.h"
  9. #include "services/preferences/tracked/pref_hash_store_transaction.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. using ValueState =
  12. prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
  13. class PrefHashStoreImplTest : public testing::Test {
  14. public:
  15. PrefHashStoreImplTest() : contents_(&pref_store_contents_) {}
  16. PrefHashStoreImplTest(const PrefHashStoreImplTest&) = delete;
  17. PrefHashStoreImplTest& operator=(const PrefHashStoreImplTest&) = delete;
  18. protected:
  19. HashStoreContents* GetHashStoreContents() { return &contents_; }
  20. private:
  21. base::DictionaryValue pref_store_contents_;
  22. // Must be declared after |pref_store_contents_| as it needs to be outlived
  23. // by it.
  24. DictionaryHashStoreContents contents_;
  25. };
  26. TEST_F(PrefHashStoreImplTest, ComputeMac) {
  27. base::Value string_1("string1");
  28. base::Value string_2("string2");
  29. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  30. std::string computed_mac_1 = pref_hash_store.ComputeMac("path1", &string_1);
  31. std::string computed_mac_2 = pref_hash_store.ComputeMac("path1", &string_2);
  32. std::string computed_mac_3 = pref_hash_store.ComputeMac("path2", &string_1);
  33. // Quick sanity checks here, see pref_hash_calculator_unittest.cc for more
  34. // complete tests.
  35. EXPECT_EQ(computed_mac_1, pref_hash_store.ComputeMac("path1", &string_1));
  36. EXPECT_NE(computed_mac_1, computed_mac_2);
  37. EXPECT_NE(computed_mac_1, computed_mac_3);
  38. EXPECT_EQ(64U, computed_mac_1.size());
  39. }
  40. TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) {
  41. base::DictionaryValue dict;
  42. dict.SetKey("a", base::Value("string1"));
  43. dict.SetKey("b", base::Value("string2"));
  44. // Verify that dictionary keys can contain a '.' delimiter.
  45. dict.SetKey("http://www.example.com", base::Value("string3"));
  46. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  47. std::unique_ptr<base::DictionaryValue> computed_macs =
  48. pref_hash_store.ComputeSplitMacs("foo.bar", &dict);
  49. const std::string mac_1 = computed_macs->FindKey("a")->GetString();
  50. const std::string mac_2 = computed_macs->FindKey("b")->GetString();
  51. const std::string mac_3 =
  52. computed_macs->FindKey("http://www.example.com")->GetString();
  53. EXPECT_EQ(3U, computed_macs->DictSize());
  54. base::Value string_1("string1");
  55. base::Value string_2("string2");
  56. base::Value string_3("string3");
  57. EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.a", &string_1), mac_1);
  58. EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.b", &string_2), mac_2);
  59. EXPECT_EQ(
  60. pref_hash_store.ComputeMac("foo.bar.http://www.example.com", &string_3),
  61. mac_3);
  62. }
  63. TEST_F(PrefHashStoreImplTest, ComputeNullSplitMacs) {
  64. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  65. std::unique_ptr<base::DictionaryValue> computed_macs =
  66. pref_hash_store.ComputeSplitMacs("foo.bar", nullptr);
  67. ASSERT_TRUE(computed_macs);
  68. EXPECT_TRUE(computed_macs->DictEmpty());
  69. }
  70. TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
  71. base::Value string_1("string1");
  72. base::Value string_2("string2");
  73. {
  74. // 32 NULL bytes is the seed that was used to generate the legacy hash.
  75. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  76. std::unique_ptr<PrefHashStoreTransaction> transaction(
  77. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  78. // Only NULL should be trusted in the absence of a hash.
  79. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  80. transaction->CheckValue("path1", &string_1));
  81. EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
  82. transaction->CheckValue("path1", NULL));
  83. transaction->StoreHash("path1", &string_1);
  84. EXPECT_EQ(ValueState::UNCHANGED,
  85. transaction->CheckValue("path1", &string_1));
  86. EXPECT_EQ(ValueState::CLEARED, transaction->CheckValue("path1", NULL));
  87. transaction->StoreHash("path1", NULL);
  88. EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", NULL));
  89. EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
  90. base::DictionaryValue dict;
  91. dict.SetString("a", "foo");
  92. dict.SetString("d", "bad");
  93. dict.SetString("b", "bar");
  94. dict.SetString("c", "baz");
  95. transaction->StoreHash("path1", &dict);
  96. EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", &dict));
  97. }
  98. ASSERT_FALSE(GetHashStoreContents()->GetSuperMac().empty());
  99. {
  100. // |pref_hash_store| should trust its initial hashes dictionary and thus
  101. // trust new unknown values.
  102. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  103. std::unique_ptr<PrefHashStoreTransaction> transaction(
  104. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  105. EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
  106. transaction->CheckValue("new_path", &string_1));
  107. EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
  108. transaction->CheckValue("new_path", &string_2));
  109. EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
  110. transaction->CheckValue("new_path", NULL));
  111. }
  112. // Manually corrupt the super MAC.
  113. GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
  114. {
  115. // |pref_hash_store| should no longer trust its initial hashes dictionary
  116. // and thus shouldn't trust non-NULL unknown values.
  117. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  118. std::unique_ptr<PrefHashStoreTransaction> transaction(
  119. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  120. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  121. transaction->CheckValue("new_path", &string_1));
  122. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  123. transaction->CheckValue("new_path", &string_2));
  124. EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
  125. transaction->CheckValue("new_path", NULL));
  126. }
  127. }
  128. TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
  129. base::Value string_1("string1");
  130. base::Value string_2("string2");
  131. // Initial state: no super MAC.
  132. {
  133. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  134. std::unique_ptr<PrefHashStoreTransaction> transaction(
  135. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  136. ASSERT_FALSE(transaction->IsSuperMACValid());
  137. ASSERT_FALSE(transaction->HasHash("path1"));
  138. // Storing a hash will stamp the super MAC.
  139. transaction->StoreHash("path1", &string_1);
  140. ASSERT_TRUE(transaction->HasHash("path1"));
  141. EXPECT_EQ(ValueState::UNCHANGED,
  142. transaction->CheckValue("path1", &string_1));
  143. EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
  144. }
  145. // Make a copy of the stored hash for future use.
  146. const base::Value* hash =
  147. GetHashStoreContents()->GetContents()->FindKey("path1");
  148. ASSERT_TRUE(hash);
  149. base::Value path_1_string_1_hash_copy(hash->Clone());
  150. hash = nullptr;
  151. // Verify that the super MAC was stamped.
  152. {
  153. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  154. std::unique_ptr<PrefHashStoreTransaction> transaction(
  155. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  156. ASSERT_TRUE(transaction->IsSuperMACValid());
  157. ASSERT_TRUE(transaction->HasHash("path1"));
  158. // Clearing the hash should preserve validity.
  159. transaction->ClearHash("path1");
  160. // The effects of the clear should be immediately visible.
  161. ASSERT_FALSE(transaction->HasHash("path1"));
  162. EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
  163. transaction->CheckValue("path1", NULL));
  164. EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
  165. transaction->CheckValue("path1", &string_1));
  166. }
  167. // Verify that validity was preserved and that the clear took effect.
  168. {
  169. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  170. std::unique_ptr<PrefHashStoreTransaction> transaction(
  171. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  172. ASSERT_TRUE(transaction->IsSuperMACValid());
  173. ASSERT_FALSE(transaction->HasHash("path1"));
  174. }
  175. // Invalidate the super MAC.
  176. GetHashStoreContents()->SetSuperMac(std::string());
  177. {
  178. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  179. std::unique_ptr<PrefHashStoreTransaction> transaction(
  180. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  181. ASSERT_FALSE(transaction->IsSuperMACValid());
  182. ASSERT_FALSE(transaction->HasHash("path1"));
  183. // An import should preserve invalidity.
  184. transaction->ImportHash("path1", &path_1_string_1_hash_copy);
  185. ASSERT_TRUE(transaction->HasHash("path1"));
  186. // The imported hash should be usable for validating the original value.
  187. EXPECT_EQ(ValueState::UNCHANGED,
  188. transaction->CheckValue("path1", &string_1));
  189. }
  190. // Verify that invalidity was preserved and that the import took effect.
  191. {
  192. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  193. std::unique_ptr<PrefHashStoreTransaction> transaction(
  194. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  195. ASSERT_FALSE(transaction->IsSuperMACValid());
  196. ASSERT_TRUE(transaction->HasHash("path1"));
  197. EXPECT_EQ(ValueState::UNCHANGED,
  198. transaction->CheckValue("path1", &string_1));
  199. // After clearing the hash, non-null values are UNTRUSTED_UNKNOWN.
  200. transaction->ClearHash("path1");
  201. EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
  202. transaction->CheckValue("path1", NULL));
  203. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  204. transaction->CheckValue("path1", &string_1));
  205. }
  206. {
  207. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  208. std::unique_ptr<PrefHashStoreTransaction> transaction(
  209. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  210. ASSERT_FALSE(transaction->IsSuperMACValid());
  211. // Test StampSuperMac.
  212. transaction->StampSuperMac();
  213. }
  214. // Verify that the store is now valid.
  215. {
  216. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  217. std::unique_ptr<PrefHashStoreTransaction> transaction(
  218. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  219. ASSERT_TRUE(transaction->IsSuperMACValid());
  220. // Store the hash of a different value to test an "over-import".
  221. transaction->StoreHash("path1", &string_2);
  222. EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_1));
  223. EXPECT_EQ(ValueState::UNCHANGED,
  224. transaction->CheckValue("path1", &string_2));
  225. }
  226. {
  227. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  228. std::unique_ptr<PrefHashStoreTransaction> transaction(
  229. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  230. ASSERT_TRUE(transaction->IsSuperMACValid());
  231. // "Over-import". An import should preserve validity.
  232. transaction->ImportHash("path1", &path_1_string_1_hash_copy);
  233. EXPECT_EQ(ValueState::UNCHANGED,
  234. transaction->CheckValue("path1", &string_1));
  235. EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
  236. }
  237. // Verify that validity was preserved and the "over-import" took effect.
  238. {
  239. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  240. std::unique_ptr<PrefHashStoreTransaction> transaction(
  241. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  242. ASSERT_TRUE(transaction->IsSuperMACValid());
  243. EXPECT_EQ(ValueState::UNCHANGED,
  244. transaction->CheckValue("path1", &string_1));
  245. EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
  246. }
  247. }
  248. TEST_F(PrefHashStoreImplTest, SuperMACDisabled) {
  249. base::Value string_1("string1");
  250. base::Value string_2("string2");
  251. {
  252. // Pass |use_super_mac| => false.
  253. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false);
  254. std::unique_ptr<PrefHashStoreTransaction> transaction(
  255. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  256. transaction->StoreHash("path1", &string_2);
  257. EXPECT_EQ(ValueState::UNCHANGED,
  258. transaction->CheckValue("path1", &string_2));
  259. }
  260. ASSERT_TRUE(GetHashStoreContents()->GetSuperMac().empty());
  261. {
  262. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false);
  263. std::unique_ptr<PrefHashStoreTransaction> transaction(
  264. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  265. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  266. transaction->CheckValue("new_path", &string_1));
  267. }
  268. }
  269. TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
  270. base::DictionaryValue dict;
  271. dict.SetKey("a", base::Value("to be replaced"));
  272. dict.SetKey("unchanged.path.with.dots", base::Value("same"));
  273. dict.SetKey("o", base::Value("old"));
  274. base::DictionaryValue modified_dict;
  275. modified_dict.SetKey("a", base::Value("replaced"));
  276. modified_dict.SetKey("unchanged.path.with.dots", base::Value("same"));
  277. modified_dict.SetKey("c", base::Value("new"));
  278. base::DictionaryValue empty_dict;
  279. std::vector<std::string> invalid_keys;
  280. {
  281. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  282. std::unique_ptr<PrefHashStoreTransaction> transaction(
  283. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  284. // No hashes stored yet and hashes dictionary is empty (and thus not
  285. // trusted).
  286. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  287. transaction->CheckSplitValue("path1", &dict, &invalid_keys));
  288. EXPECT_TRUE(invalid_keys.empty());
  289. transaction->StoreSplitHash("path1", &dict);
  290. // Verify match post storage.
  291. EXPECT_EQ(ValueState::UNCHANGED,
  292. transaction->CheckSplitValue("path1", &dict, &invalid_keys));
  293. EXPECT_TRUE(invalid_keys.empty());
  294. // Verify new path is still unknown.
  295. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  296. transaction->CheckSplitValue("path2", &dict, &invalid_keys));
  297. EXPECT_TRUE(invalid_keys.empty());
  298. // Verify NULL or empty dicts are declared as having been cleared.
  299. EXPECT_EQ(ValueState::CLEARED,
  300. transaction->CheckSplitValue("path1", NULL, &invalid_keys));
  301. EXPECT_TRUE(invalid_keys.empty());
  302. EXPECT_EQ(ValueState::CLEARED, transaction->CheckSplitValue(
  303. "path1", &empty_dict, &invalid_keys));
  304. EXPECT_TRUE(invalid_keys.empty());
  305. // Verify changes are properly detected.
  306. EXPECT_EQ(ValueState::CHANGED, transaction->CheckSplitValue(
  307. "path1", &modified_dict, &invalid_keys));
  308. std::vector<std::string> expected_invalid_keys1;
  309. expected_invalid_keys1.push_back("a");
  310. expected_invalid_keys1.push_back("c");
  311. expected_invalid_keys1.push_back("o");
  312. EXPECT_EQ(expected_invalid_keys1, invalid_keys);
  313. invalid_keys.clear();
  314. // Verify |dict| still matches post check.
  315. EXPECT_EQ(ValueState::UNCHANGED,
  316. transaction->CheckSplitValue("path1", &dict, &invalid_keys));
  317. EXPECT_TRUE(invalid_keys.empty());
  318. // Store hash for |modified_dict|.
  319. transaction->StoreSplitHash("path1", &modified_dict);
  320. // Verify |modified_dict| is now the one that verifies correctly.
  321. EXPECT_EQ(
  322. ValueState::UNCHANGED,
  323. transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
  324. EXPECT_TRUE(invalid_keys.empty());
  325. // Verify old dict no longer matches.
  326. EXPECT_EQ(ValueState::CHANGED,
  327. transaction->CheckSplitValue("path1", &dict, &invalid_keys));
  328. std::vector<std::string> expected_invalid_keys2;
  329. expected_invalid_keys2.push_back("a");
  330. expected_invalid_keys2.push_back("o");
  331. expected_invalid_keys2.push_back("c");
  332. EXPECT_EQ(expected_invalid_keys2, invalid_keys);
  333. invalid_keys.clear();
  334. }
  335. {
  336. // |pref_hash_store| should trust its initial hashes dictionary and thus
  337. // trust new unknown values.
  338. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  339. std::unique_ptr<PrefHashStoreTransaction> transaction(
  340. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  341. EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
  342. transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
  343. EXPECT_TRUE(invalid_keys.empty());
  344. }
  345. {
  346. // Check the same as above for a path with dots.
  347. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  348. std::unique_ptr<PrefHashStoreTransaction> transaction(
  349. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  350. EXPECT_EQ(
  351. ValueState::TRUSTED_UNKNOWN_VALUE,
  352. transaction->CheckSplitValue("path.with.dots", &dict, &invalid_keys));
  353. EXPECT_TRUE(invalid_keys.empty());
  354. }
  355. // Manually corrupt the super MAC.
  356. GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
  357. {
  358. // |pref_hash_store| should no longer trust its initial hashes dictionary
  359. // and thus shouldn't trust unknown values.
  360. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  361. std::unique_ptr<PrefHashStoreTransaction> transaction(
  362. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  363. EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
  364. transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
  365. EXPECT_TRUE(invalid_keys.empty());
  366. }
  367. {
  368. // Check the same as above for a path with dots.
  369. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  370. std::unique_ptr<PrefHashStoreTransaction> transaction(
  371. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  372. EXPECT_EQ(
  373. ValueState::UNTRUSTED_UNKNOWN_VALUE,
  374. transaction->CheckSplitValue("path.with.dots", &dict, &invalid_keys));
  375. EXPECT_TRUE(invalid_keys.empty());
  376. }
  377. }
  378. TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
  379. base::DictionaryValue empty_dict;
  380. std::vector<std::string> invalid_keys;
  381. {
  382. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  383. std::unique_ptr<PrefHashStoreTransaction> transaction(
  384. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  385. // Store hashes for a random dict to be overwritten below.
  386. base::DictionaryValue initial_dict;
  387. initial_dict.SetString("a", "foo");
  388. transaction->StoreSplitHash("path1", &initial_dict);
  389. // Verify stored empty dictionary matches NULL and empty dictionary back.
  390. transaction->StoreSplitHash("path1", &empty_dict);
  391. EXPECT_EQ(ValueState::UNCHANGED,
  392. transaction->CheckSplitValue("path1", NULL, &invalid_keys));
  393. EXPECT_TRUE(invalid_keys.empty());
  394. EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckSplitValue(
  395. "path1", &empty_dict, &invalid_keys));
  396. EXPECT_TRUE(invalid_keys.empty());
  397. // Same when storing NULL directly.
  398. transaction->StoreSplitHash("path1", NULL);
  399. EXPECT_EQ(ValueState::UNCHANGED,
  400. transaction->CheckSplitValue("path1", NULL, &invalid_keys));
  401. EXPECT_TRUE(invalid_keys.empty());
  402. EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckSplitValue(
  403. "path1", &empty_dict, &invalid_keys));
  404. EXPECT_TRUE(invalid_keys.empty());
  405. }
  406. {
  407. // |pref_hash_store| should trust its initial hashes dictionary (and thus
  408. // trust new unknown values) even though the last action done was to clear
  409. // the hashes for path1 by setting its value to NULL (this is a regression
  410. // test ensuring that the internal action of clearing some hashes does
  411. // update the stored hash of hashes).
  412. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  413. std::unique_ptr<PrefHashStoreTransaction> transaction(
  414. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  415. base::DictionaryValue tested_dict;
  416. tested_dict.SetString("a", "foo");
  417. tested_dict.SetString("b", "bar");
  418. EXPECT_EQ(
  419. ValueState::TRUSTED_UNKNOWN_VALUE,
  420. transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
  421. EXPECT_TRUE(invalid_keys.empty());
  422. }
  423. }
  424. // Test that the PrefHashStore returns TRUSTED_UNKNOWN_VALUE when checking for
  425. // a split preference even if there is an existing atomic preference's hash
  426. // stored. There is no point providing a migration path for preferences
  427. // switching strategies after their initial release as split preferences are
  428. // turned into split preferences specifically because the atomic hash isn't
  429. // considered useful.
  430. TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
  431. base::Value string("string1");
  432. base::DictionaryValue dict;
  433. dict.SetString("a", "foo");
  434. dict.SetString("d", "bad");
  435. dict.SetString("b", "bar");
  436. dict.SetString("c", "baz");
  437. {
  438. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  439. std::unique_ptr<PrefHashStoreTransaction> transaction(
  440. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  441. transaction->StoreHash("path1", &string);
  442. EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", &string));
  443. }
  444. {
  445. // Load a new |pref_hash_store| in which the hashes dictionary is trusted.
  446. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
  447. std::unique_ptr<PrefHashStoreTransaction> transaction(
  448. pref_hash_store.BeginTransaction(GetHashStoreContents()));
  449. std::vector<std::string> invalid_keys;
  450. EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
  451. transaction->CheckSplitValue("path1", &dict, &invalid_keys));
  452. EXPECT_TRUE(invalid_keys.empty());
  453. }
  454. }