Revert 271602 "Implementation of leveldb-backed PrefStore."
[chromium-blink-merge.git] / chrome / browser / prefs / pref_hash_store_impl_unittest.cc
blob5a53ef5b10a4425dc0e7499656a7a938562ca568
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.
5 #include "chrome/browser/prefs/pref_hash_store_impl.h"
7 #include <string>
9 #include "base/macros.h"
10 #include "base/values.h"
11 #include "chrome/browser/prefs/pref_hash_store_impl.h"
12 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
13 #include "chrome/browser/prefs/tracked/hash_store_contents.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 class MockHashStoreContents : public HashStoreContents {
17 public:
18 // Keep the data separate from the API implementation so that it can be owned
19 // by the test and reused. The API implementation is owned by the
20 // PrefHashStoreImpl.
21 struct Data {
22 Data() : commit_performed(false) {}
24 // Returns the current value of |commit_performed| and resets it to false
25 // immediately after.
26 bool GetCommitPerformedAndReset() {
27 bool current_commit_performed = commit_performed;
28 commit_performed = false;
29 return current_commit_performed;
32 scoped_ptr<base::DictionaryValue> contents;
33 std::string super_mac;
34 scoped_ptr<int> version;
35 bool commit_performed;
38 explicit MockHashStoreContents(Data* data) : data_(data) {}
40 // HashStoreContents implementation
41 virtual std::string hash_store_id() const OVERRIDE { return "store_id"; }
43 virtual void Reset() OVERRIDE {
44 data_->contents.reset();
45 data_->super_mac = "";
46 data_->version.reset();
49 virtual bool IsInitialized() const OVERRIDE { return data_->contents; }
51 virtual bool GetVersion(int* version) const OVERRIDE {
52 if (data_->version)
53 *version = *data_->version;
54 return data_->version;
57 virtual void SetVersion(int version) OVERRIDE {
58 data_->version.reset(new int(version));
61 virtual const base::DictionaryValue* GetContents() const OVERRIDE {
62 return data_->contents.get();
65 virtual scoped_ptr<MutableDictionary> GetMutableContents() OVERRIDE {
66 return scoped_ptr<MutableDictionary>(new MockMutableDictionary(data_));
69 virtual std::string GetSuperMac() const OVERRIDE { return data_->super_mac; }
71 virtual void SetSuperMac(const std::string& super_mac) OVERRIDE {
72 data_->super_mac = super_mac;
75 virtual void CommitPendingWrite() OVERRIDE {
76 EXPECT_FALSE(data_->commit_performed);
77 data_->commit_performed = true;
80 private:
81 class MockMutableDictionary : public MutableDictionary {
82 public:
83 explicit MockMutableDictionary(Data* data) : data_(data) {}
85 // MutableDictionary implementation
86 virtual base::DictionaryValue* operator->() OVERRIDE {
87 if (!data_->contents)
88 data_->contents.reset(new base::DictionaryValue);
89 return data_->contents.get();
92 private:
93 Data* data_;
94 DISALLOW_COPY_AND_ASSIGN(MockMutableDictionary);
97 Data* data_;
99 DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents);
102 class PrefHashStoreImplTest : public testing::Test {
103 protected:
104 scoped_ptr<HashStoreContents> CreateHashStoreContents() {
105 return scoped_ptr<HashStoreContents>(
106 new MockHashStoreContents(&hash_store_data_));
109 MockHashStoreContents::Data hash_store_data_;
112 TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
113 base::StringValue string_1("string1");
114 base::StringValue string_2("string2");
117 // 32 NULL bytes is the seed that was used to generate the legacy hash.
118 PrefHashStoreImpl pref_hash_store(
119 std::string(32, 0), "device_id", CreateHashStoreContents());
120 scoped_ptr<PrefHashStoreTransaction> transaction(
121 pref_hash_store.BeginTransaction());
123 // Only NULL should be trusted in the absence of a hash.
124 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
125 transaction->CheckValue("path1", &string_1));
126 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
127 transaction->CheckValue("path1", NULL));
129 transaction->StoreHash("path1", &string_1);
130 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
131 transaction->CheckValue("path1", &string_1));
132 EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
133 transaction->CheckValue("path1", NULL));
134 transaction->StoreHash("path1", NULL);
135 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
136 transaction->CheckValue("path1", NULL));
137 EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
138 transaction->CheckValue("path1", &string_2));
140 base::DictionaryValue dict;
141 dict.Set("a", new base::StringValue("foo"));
142 dict.Set("d", new base::StringValue("bad"));
143 dict.Set("b", new base::StringValue("bar"));
144 dict.Set("c", new base::StringValue("baz"));
146 // Manually shove in a legacy hash.
147 (*CreateHashStoreContents()->GetMutableContents())->SetString(
148 "path1",
149 "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2");
151 EXPECT_EQ(PrefHashStoreTransaction::WEAK_LEGACY,
152 transaction->CheckValue("path1", &dict));
153 transaction->StoreHash("path1", &dict);
154 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
155 transaction->CheckValue("path1", &dict));
157 // Test that the |pref_hash_store| flushes its changes on request post
158 // transaction.
159 transaction.reset();
160 pref_hash_store.CommitPendingWrite();
161 EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
165 // |pref_hash_store2| should trust its initial hashes dictionary and thus
166 // trust new unknown values.
167 PrefHashStoreImpl pref_hash_store2(
168 std::string(32, 0), "device_id", CreateHashStoreContents());
169 scoped_ptr<PrefHashStoreTransaction> transaction(
170 pref_hash_store2.BeginTransaction());
171 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
172 transaction->CheckValue("new_path", &string_1));
173 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
174 transaction->CheckValue("new_path", &string_2));
175 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
176 transaction->CheckValue("new_path", NULL));
178 // Test that |pref_hash_store2| doesn't flush its contents to disk when it
179 // didn't change.
180 transaction.reset();
181 pref_hash_store2.CommitPendingWrite();
182 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
185 // Manually corrupt the super MAC.
186 hash_store_data_.super_mac = std::string(64, 'A');
189 // |pref_hash_store3| should no longer trust its initial hashes dictionary
190 // and thus shouldn't trust non-NULL unknown values.
191 PrefHashStoreImpl pref_hash_store3(
192 std::string(32, 0), "device_id", CreateHashStoreContents());
193 scoped_ptr<PrefHashStoreTransaction> transaction(
194 pref_hash_store3.BeginTransaction());
195 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
196 transaction->CheckValue("new_path", &string_1));
197 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
198 transaction->CheckValue("new_path", &string_2));
199 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
200 transaction->CheckValue("new_path", NULL));
202 // Test that |pref_hash_store3| doesn't flush its contents to disk when it
203 // didn't change.
204 transaction.reset();
205 pref_hash_store3.CommitPendingWrite();
206 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
210 TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
211 base::DictionaryValue dict;
212 dict.Set("a", new base::StringValue("to be replaced"));
213 dict.Set("b", new base::StringValue("same"));
214 dict.Set("o", new base::StringValue("old"));
216 base::DictionaryValue modified_dict;
217 modified_dict.Set("a", new base::StringValue("replaced"));
218 modified_dict.Set("b", new base::StringValue("same"));
219 modified_dict.Set("c", new base::StringValue("new"));
221 base::DictionaryValue empty_dict;
223 std::vector<std::string> invalid_keys;
226 PrefHashStoreImpl pref_hash_store(
227 std::string(32, 0), "device_id", CreateHashStoreContents());
228 scoped_ptr<PrefHashStoreTransaction> transaction(
229 pref_hash_store.BeginTransaction());
231 // No hashes stored yet and hashes dictionary is empty (and thus not
232 // trusted).
233 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
234 transaction->CheckSplitValue("path1", &dict, &invalid_keys));
235 EXPECT_TRUE(invalid_keys.empty());
237 transaction->StoreSplitHash("path1", &dict);
239 // Verify match post storage.
240 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
241 transaction->CheckSplitValue("path1", &dict, &invalid_keys));
242 EXPECT_TRUE(invalid_keys.empty());
244 // Verify new path is still unknown.
245 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
246 transaction->CheckSplitValue("path2", &dict, &invalid_keys));
247 EXPECT_TRUE(invalid_keys.empty());
249 // Verify NULL or empty dicts are declared as having been cleared.
250 EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
251 transaction->CheckSplitValue("path1", NULL, &invalid_keys));
252 EXPECT_TRUE(invalid_keys.empty());
253 EXPECT_EQ(
254 PrefHashStoreTransaction::CLEARED,
255 transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
256 EXPECT_TRUE(invalid_keys.empty());
258 // Verify changes are properly detected.
259 EXPECT_EQ(
260 PrefHashStoreTransaction::CHANGED,
261 transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
262 std::vector<std::string> expected_invalid_keys1;
263 expected_invalid_keys1.push_back("a");
264 expected_invalid_keys1.push_back("c");
265 expected_invalid_keys1.push_back("o");
266 EXPECT_EQ(expected_invalid_keys1, invalid_keys);
267 invalid_keys.clear();
269 // Verify |dict| still matches post check.
270 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
271 transaction->CheckSplitValue("path1", &dict, &invalid_keys));
272 EXPECT_TRUE(invalid_keys.empty());
274 // Store hash for |modified_dict|.
275 transaction->StoreSplitHash("path1", &modified_dict);
277 // Verify |modified_dict| is now the one that verifies correctly.
278 EXPECT_EQ(
279 PrefHashStoreTransaction::UNCHANGED,
280 transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
281 EXPECT_TRUE(invalid_keys.empty());
283 // Verify old dict no longer matches.
284 EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
285 transaction->CheckSplitValue("path1", &dict, &invalid_keys));
286 std::vector<std::string> expected_invalid_keys2;
287 expected_invalid_keys2.push_back("a");
288 expected_invalid_keys2.push_back("o");
289 expected_invalid_keys2.push_back("c");
290 EXPECT_EQ(expected_invalid_keys2, invalid_keys);
291 invalid_keys.clear();
293 // Test that the |pref_hash_store| flushes its changes on request.
294 transaction.reset();
295 pref_hash_store.CommitPendingWrite();
296 EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
300 // |pref_hash_store2| should trust its initial hashes dictionary and thus
301 // trust new unknown values.
302 PrefHashStoreImpl pref_hash_store2(
303 std::string(32, 0), "device_id", CreateHashStoreContents());
304 scoped_ptr<PrefHashStoreTransaction> transaction(
305 pref_hash_store2.BeginTransaction());
306 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
307 transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
308 EXPECT_TRUE(invalid_keys.empty());
310 // Test that |pref_hash_store2| doesn't flush its contents to disk when it
311 // didn't change.
312 transaction.reset();
313 pref_hash_store2.CommitPendingWrite();
314 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
317 // Manually corrupt the super MAC.
318 hash_store_data_.super_mac = std::string(64, 'A');
321 // |pref_hash_store3| should no longer trust its initial hashes dictionary
322 // and thus shouldn't trust unknown values.
323 PrefHashStoreImpl pref_hash_store3(
324 std::string(32, 0), "device_id", CreateHashStoreContents());
325 scoped_ptr<PrefHashStoreTransaction> transaction(
326 pref_hash_store3.BeginTransaction());
327 EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
328 transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
329 EXPECT_TRUE(invalid_keys.empty());
331 // Test that |pref_hash_store3| doesn't flush its contents to disk when it
332 // didn't change.
333 transaction.reset();
334 pref_hash_store3.CommitPendingWrite();
335 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
339 TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
340 base::DictionaryValue empty_dict;
342 std::vector<std::string> invalid_keys;
345 PrefHashStoreImpl pref_hash_store(
346 std::string(32, 0), "device_id", CreateHashStoreContents());
347 scoped_ptr<PrefHashStoreTransaction> transaction(
348 pref_hash_store.BeginTransaction());
350 // Store hashes for a random dict to be overwritten below.
351 base::DictionaryValue initial_dict;
352 initial_dict.Set("a", new base::StringValue("foo"));
353 transaction->StoreSplitHash("path1", &initial_dict);
355 // Verify stored empty dictionary matches NULL and empty dictionary back.
356 transaction->StoreSplitHash("path1", &empty_dict);
357 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
358 transaction->CheckSplitValue("path1", NULL, &invalid_keys));
359 EXPECT_TRUE(invalid_keys.empty());
360 EXPECT_EQ(
361 PrefHashStoreTransaction::UNCHANGED,
362 transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
363 EXPECT_TRUE(invalid_keys.empty());
365 // Same when storing NULL directly.
366 transaction->StoreSplitHash("path1", NULL);
367 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
368 transaction->CheckSplitValue("path1", NULL, &invalid_keys));
369 EXPECT_TRUE(invalid_keys.empty());
370 EXPECT_EQ(
371 PrefHashStoreTransaction::UNCHANGED,
372 transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
373 EXPECT_TRUE(invalid_keys.empty());
377 // |pref_hash_store2| should trust its initial hashes dictionary (and thus
378 // trust new unknown values) even though the last action done was to clear
379 // the hashes for path1 by setting its value to NULL (this is a regression
380 // test ensuring that the internal action of clearing some hashes does
381 // update the stored hash of hashes).
382 PrefHashStoreImpl pref_hash_store2(
383 std::string(32, 0), "device_id", CreateHashStoreContents());
384 scoped_ptr<PrefHashStoreTransaction> transaction(
385 pref_hash_store2.BeginTransaction());
387 base::DictionaryValue tested_dict;
388 tested_dict.Set("a", new base::StringValue("foo"));
389 tested_dict.Set("b", new base::StringValue("bar"));
390 EXPECT_EQ(
391 PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
392 transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
393 EXPECT_TRUE(invalid_keys.empty());
397 // Test that the PrefHashStore returns TRUSTED_UNKNOWN_VALUE when checking for
398 // a split preference even if there is an existing atomic preference's hash
399 // stored. There is no point providing a migration path for preferences
400 // switching strategies after their initial release as split preferences are
401 // turned into split preferences specifically because the atomic hash isn't
402 // considered useful.
403 TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
404 base::StringValue string("string1");
406 base::DictionaryValue dict;
407 dict.Set("a", new base::StringValue("foo"));
408 dict.Set("d", new base::StringValue("bad"));
409 dict.Set("b", new base::StringValue("bar"));
410 dict.Set("c", new base::StringValue("baz"));
413 PrefHashStoreImpl pref_hash_store(
414 std::string(32, 0), "device_id", CreateHashStoreContents());
415 scoped_ptr<PrefHashStoreTransaction> transaction(
416 pref_hash_store.BeginTransaction());
418 transaction->StoreHash("path1", &string);
419 EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
420 transaction->CheckValue("path1", &string));
424 // Load a new |pref_hash_store2| in which the hashes dictionary is trusted.
425 PrefHashStoreImpl pref_hash_store2(
426 std::string(32, 0), "device_id", CreateHashStoreContents());
427 scoped_ptr<PrefHashStoreTransaction> transaction(
428 pref_hash_store2.BeginTransaction());
429 std::vector<std::string> invalid_keys;
430 EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
431 transaction->CheckSplitValue("path1", &dict, &invalid_keys));
432 EXPECT_TRUE(invalid_keys.empty());
436 TEST_F(PrefHashStoreImplTest, GetCurrentVersion) {
437 COMPILE_ASSERT(PrefHashStoreImpl::VERSION_LATEST == 2,
438 new_versions_should_be_tested_here);
440 PrefHashStoreImpl pref_hash_store(
441 std::string(32, 0), "device_id", CreateHashStoreContents());
443 // VERSION_UNINITIALIZED when no hashes are stored.
444 EXPECT_EQ(PrefHashStoreImpl::VERSION_UNINITIALIZED,
445 pref_hash_store.GetCurrentVersion());
447 scoped_ptr<PrefHashStoreTransaction> transaction(
448 pref_hash_store.BeginTransaction());
449 base::StringValue string_value("foo");
450 transaction->StoreHash("path1", &string_value);
452 // Test that |pref_hash_store| flushes its content to disk when it
453 // initializes its version.
454 transaction.reset();
455 pref_hash_store.CommitPendingWrite();
456 EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
459 PrefHashStoreImpl pref_hash_store(
460 std::string(32, 0), "device_id", CreateHashStoreContents());
462 // VERSION_LATEST after storing a hash.
463 EXPECT_EQ(PrefHashStoreImpl::VERSION_LATEST,
464 pref_hash_store.GetCurrentVersion());
466 // Test that |pref_hash_store| doesn't flush its contents to disk when it
467 // didn't change.
468 pref_hash_store.CommitPendingWrite();
469 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
472 // Manually clear the version number.
473 hash_store_data_.version.reset();
476 PrefHashStoreImpl pref_hash_store(
477 std::string(32, 0), "device_id", CreateHashStoreContents());
479 // VERSION_PRE_MIGRATION when no version is stored.
480 EXPECT_EQ(PrefHashStoreImpl::VERSION_PRE_MIGRATION,
481 pref_hash_store.GetCurrentVersion());
483 scoped_ptr<PrefHashStoreTransaction> transaction(
484 pref_hash_store.BeginTransaction());
486 // Test that |pref_hash_store| flushes its content to disk when it
487 // re-initializes its version.
488 transaction.reset();
489 pref_hash_store.CommitPendingWrite();
490 EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
493 PrefHashStoreImpl pref_hash_store(
494 std::string(32, 0), "device_id", CreateHashStoreContents());
496 // Back to VERSION_LATEST after performing a transaction from
497 // VERSION_PRE_MIGRATION (the presence of an existing hash should be
498 // sufficient, no need for the transaction itself to perform any work).
499 EXPECT_EQ(PrefHashStoreImpl::VERSION_LATEST,
500 pref_hash_store.GetCurrentVersion());
502 // Test that |pref_hash_store| doesn't flush its contents to disk when it
503 // didn't change (i.e., its version was already up-to-date and the only
504 // transaction performed was empty).
505 scoped_ptr<PrefHashStoreTransaction> transaction(
506 pref_hash_store.BeginTransaction());
507 transaction.reset();
508 pref_hash_store.CommitPendingWrite();
509 EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());