Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / pref_hash_store_impl_unittest.cc
index 67b4148..5a53ef5 100644 (file)
 
 #include <string>
 
-#include "base/prefs/pref_service.h"
-#include "base/prefs/scoped_user_pref_update.h"
-#include "base/prefs/testing_pref_service.h"
+#include "base/macros.h"
 #include "base/values.h"
 #include "chrome/browser/prefs/pref_hash_store_impl.h"
 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
-#include "chrome/common/pref_names.h"
+#include "chrome/browser/prefs/tracked/hash_store_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class PrefHashStoreImplTest : public testing::Test {
+class MockHashStoreContents : public HashStoreContents {
  public:
-  virtual void SetUp() OVERRIDE {
-    PrefHashStoreImpl::RegisterPrefs(local_state_.registry());
+  // Keep the data separate from the API implementation so that it can be owned
+  // by the test and reused. The API implementation is owned by the
+  // PrefHashStoreImpl.
+  struct Data {
+    Data() : commit_performed(false) {}
+
+    // Returns the current value of |commit_performed| and resets it to false
+    // immediately after.
+    bool GetCommitPerformedAndReset() {
+      bool current_commit_performed = commit_performed;
+      commit_performed = false;
+      return current_commit_performed;
+    }
+
+    scoped_ptr<base::DictionaryValue> contents;
+    std::string super_mac;
+    scoped_ptr<int> version;
+    bool commit_performed;
+  };
+
+  explicit MockHashStoreContents(Data* data) : data_(data) {}
+
+  // HashStoreContents implementation
+  virtual std::string hash_store_id() const OVERRIDE { return "store_id"; }
+
+  virtual void Reset() OVERRIDE {
+    data_->contents.reset();
+    data_->super_mac = "";
+    data_->version.reset();
+  }
+
+  virtual bool IsInitialized() const OVERRIDE { return data_->contents; }
+
+  virtual bool GetVersion(int* version) const OVERRIDE {
+    if (data_->version)
+      *version = *data_->version;
+    return data_->version;
+  }
+
+  virtual void SetVersion(int version) OVERRIDE {
+    data_->version.reset(new int(version));
+  }
+
+  virtual const base::DictionaryValue* GetContents() const OVERRIDE {
+    return data_->contents.get();
+  }
+
+  virtual scoped_ptr<MutableDictionary> GetMutableContents() OVERRIDE {
+    return scoped_ptr<MutableDictionary>(new MockMutableDictionary(data_));
   }
 
+  virtual std::string GetSuperMac() const OVERRIDE { return data_->super_mac; }
+
+  virtual void SetSuperMac(const std::string& super_mac) OVERRIDE {
+    data_->super_mac = super_mac;
+  }
+
+  virtual void CommitPendingWrite() OVERRIDE {
+    EXPECT_FALSE(data_->commit_performed);
+    data_->commit_performed = true;
+  }
+
+ private:
+  class MockMutableDictionary : public MutableDictionary {
+   public:
+    explicit MockMutableDictionary(Data* data) : data_(data) {}
+
+    // MutableDictionary implementation
+    virtual base::DictionaryValue* operator->() OVERRIDE {
+      if (!data_->contents)
+        data_->contents.reset(new base::DictionaryValue);
+      return data_->contents.get();
+    }
+
+   private:
+    Data* data_;
+    DISALLOW_COPY_AND_ASSIGN(MockMutableDictionary);
+  };
+
+  Data* data_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents);
+};
+
+class PrefHashStoreImplTest : public testing::Test {
  protected:
-  TestingPrefServiceSimple local_state_;
+  scoped_ptr<HashStoreContents> CreateHashStoreContents() {
+    return scoped_ptr<HashStoreContents>(
+        new MockHashStoreContents(&hash_store_data_));
+  }
+
+  MockHashStoreContents::Data hash_store_data_;
 };
 
 TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
@@ -32,7 +116,7 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
   {
     // 32 NULL bytes is the seed that was used to generate the legacy hash.
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store.BeginTransaction());
 
@@ -59,28 +143,29 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
     dict.Set("b", new base::StringValue("bar"));
     dict.Set("c", new base::StringValue("baz"));
 
-    {
-      // Manually shove in a legacy hash.
-      DictionaryPrefUpdate update(&local_state_,
-                                  prefs::kProfilePreferenceHashes);
-      base::DictionaryValue* child_dictionary = NULL;
-      ASSERT_TRUE(update->GetDictionary("store_id", &child_dictionary));
-      child_dictionary->SetString(
-          "path1",
-          "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2");
-    }
-    EXPECT_EQ(PrefHashStoreTransaction::MIGRATED,
+    // Manually shove in a legacy hash.
+    (*CreateHashStoreContents()->GetMutableContents())->SetString(
+        "path1",
+        "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2");
+
+    EXPECT_EQ(PrefHashStoreTransaction::WEAK_LEGACY,
               transaction->CheckValue("path1", &dict));
     transaction->StoreHash("path1", &dict);
     EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
               transaction->CheckValue("path1", &dict));
+
+    // Test that the |pref_hash_store| flushes its changes on request post
+    // transaction.
+    transaction.reset();
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
   }
 
   {
     // |pref_hash_store2| should trust its initial hashes dictionary and thus
     // trust new unknown values.
     PrefHashStoreImpl pref_hash_store2(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store2.BeginTransaction());
     EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
@@ -89,24 +174,22 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
               transaction->CheckValue("new_path", &string_2));
     EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
               transaction->CheckValue("new_path", NULL));
-  }
 
-  {
-    // Manually corrupt the hash of hashes for "store_id".
-    DictionaryPrefUpdate update(&local_state_, prefs::kProfilePreferenceHashes);
-    base::DictionaryValue* hash_of_hashes_dict = NULL;
-    ASSERT_TRUE(update->GetDictionaryWithoutPathExpansion(
-        internals::kHashOfHashesDict, &hash_of_hashes_dict));
-    hash_of_hashes_dict->SetString("store_id", std::string(64, 'A'));
-    // This shouldn't have increased the number of existing hash of hashes.
-    ASSERT_EQ(1U, hash_of_hashes_dict->size());
+    // Test that |pref_hash_store2| doesn't flush its contents to disk when it
+    // didn't change.
+    transaction.reset();
+    pref_hash_store2.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
 
+  // Manually corrupt the super MAC.
+  hash_store_data_.super_mac = std::string(64, 'A');
+
   {
     // |pref_hash_store3| should no longer trust its initial hashes dictionary
     // and thus shouldn't trust non-NULL unknown values.
     PrefHashStoreImpl pref_hash_store3(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store3.BeginTransaction());
     EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
@@ -115,6 +198,12 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
               transaction->CheckValue("new_path", &string_2));
     EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
               transaction->CheckValue("new_path", NULL));
+
+    // Test that |pref_hash_store3| doesn't flush its contents to disk when it
+    // didn't change.
+    transaction.reset();
+    pref_hash_store3.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
 }
 
@@ -135,7 +224,7 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
 
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store.BeginTransaction());
 
@@ -161,18 +250,19 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
     EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
               transaction->CheckSplitValue("path1", NULL, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
-    EXPECT_EQ(PrefHashStoreTransaction::CLEARED,
-              transaction->CheckSplitValue("path1", &empty_dict,
-                                              &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::CLEARED,
+        transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
 
     // Verify changes are properly detected.
-    EXPECT_EQ(PrefHashStoreTransaction::CHANGED,
-              transaction->CheckSplitValue("path1", &modified_dict,
-                                              &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::CHANGED,
+        transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
     std::vector<std::string> expected_invalid_keys1;
     expected_invalid_keys1.push_back("a");
     expected_invalid_keys1.push_back("c");
+    expected_invalid_keys1.push_back("o");
     EXPECT_EQ(expected_invalid_keys1, invalid_keys);
     invalid_keys.clear();
 
@@ -185,9 +275,9 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
     transaction->StoreSplitHash("path1", &modified_dict);
 
     // Verify |modified_dict| is now the one that verifies correctly.
-    EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
-              transaction->CheckSplitValue("path1", &modified_dict,
-                                              &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::UNCHANGED,
+        transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
 
     // Verify old dict no longer matches.
@@ -196,43 +286,53 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
     std::vector<std::string> expected_invalid_keys2;
     expected_invalid_keys2.push_back("a");
     expected_invalid_keys2.push_back("o");
+    expected_invalid_keys2.push_back("c");
     EXPECT_EQ(expected_invalid_keys2, invalid_keys);
     invalid_keys.clear();
+
+    // Test that the |pref_hash_store| flushes its changes on request.
+    transaction.reset();
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
   }
 
   {
     // |pref_hash_store2| should trust its initial hashes dictionary and thus
     // trust new unknown values.
     PrefHashStoreImpl pref_hash_store2(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store2.BeginTransaction());
     EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
               transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
-  }
 
-  {
-    // Manually corrupt the hash of hashes for "store_id".
-    DictionaryPrefUpdate update(&local_state_, prefs::kProfilePreferenceHashes);
-    base::DictionaryValue* hash_of_hashes_dict = NULL;
-    ASSERT_TRUE(update->GetDictionaryWithoutPathExpansion(
-        internals::kHashOfHashesDict, &hash_of_hashes_dict));
-    hash_of_hashes_dict->SetString("store_id", std::string(64, 'A'));
-    // This shouldn't have increased the number of existing hash of hashes.
-    ASSERT_EQ(1U, hash_of_hashes_dict->size());
+    // Test that |pref_hash_store2| doesn't flush its contents to disk when it
+    // didn't change.
+    transaction.reset();
+    pref_hash_store2.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
 
+  // Manually corrupt the super MAC.
+  hash_store_data_.super_mac = std::string(64, 'A');
+
   {
     // |pref_hash_store3| should no longer trust its initial hashes dictionary
     // and thus shouldn't trust unknown values.
     PrefHashStoreImpl pref_hash_store3(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store3.BeginTransaction());
     EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
               transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
+
+    // Test that |pref_hash_store3| doesn't flush its contents to disk when it
+    // didn't change.
+    transaction.reset();
+    pref_hash_store3.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
 }
 
@@ -243,7 +343,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
 
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store.BeginTransaction());
 
@@ -257,9 +357,9 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
     EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
               transaction->CheckSplitValue("path1", NULL, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
-    EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
-              transaction->CheckSplitValue("path1", &empty_dict,
-                                              &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::UNCHANGED,
+        transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
 
     // Same when storing NULL directly.
@@ -267,29 +367,29 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
     EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
               transaction->CheckSplitValue("path1", NULL, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
-    EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
-              transaction->CheckSplitValue("path1", &empty_dict,
-                                              &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::UNCHANGED,
+        transaction->CheckSplitValue("path1", &empty_dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
   }
 
   {
     // |pref_hash_store2| should trust its initial hashes dictionary (and thus
-    // trust new unknown values) even though the last action done on local_state
-    // was to clear the hashes for path1 by setting its value to NULL (this is a
-    // regression test ensuring that the internal action of clearing some hashes
-    // does update the stored hash of hashes).
+    // trust new unknown values) even though the last action done was to clear
+    // the hashes for path1 by setting its value to NULL (this is a regression
+    // test ensuring that the internal action of clearing some hashes does
+    // update the stored hash of hashes).
     PrefHashStoreImpl pref_hash_store2(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store2.BeginTransaction());
 
     base::DictionaryValue tested_dict;
     tested_dict.Set("a", new base::StringValue("foo"));
     tested_dict.Set("b", new base::StringValue("bar"));
-    EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
-              transaction->CheckSplitValue("new_path", &tested_dict,
-                                           &invalid_keys));
+    EXPECT_EQ(
+        PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
+        transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
     EXPECT_TRUE(invalid_keys.empty());
   }
 }
@@ -311,7 +411,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
 
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store.BeginTransaction());
 
@@ -323,7 +423,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
   {
     // Load a new |pref_hash_store2| in which the hashes dictionary is trusted.
     PrefHashStoreImpl pref_hash_store2(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store2.BeginTransaction());
     std::vector<std::string> invalid_keys;
@@ -338,7 +438,7 @@ TEST_F(PrefHashStoreImplTest, GetCurrentVersion) {
                  new_versions_should_be_tested_here);
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
 
     // VERSION_UNINITIALIZED when no hashes are stored.
     EXPECT_EQ(PrefHashStoreImpl::VERSION_UNINITIALIZED,
@@ -348,48 +448,64 @@ TEST_F(PrefHashStoreImplTest, GetCurrentVersion) {
         pref_hash_store.BeginTransaction());
     base::StringValue string_value("foo");
     transaction->StoreHash("path1", &string_value);
+
+    // Test that |pref_hash_store| flushes its content to disk when it
+    // initializes its version.
+    transaction.reset();
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
   }
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
 
     // VERSION_LATEST after storing a hash.
     EXPECT_EQ(PrefHashStoreImpl::VERSION_LATEST,
               pref_hash_store.GetCurrentVersion());
+
+    // Test that |pref_hash_store| doesn't flush its contents to disk when it
+    // didn't change.
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
-  {
-    // Manually clear the version number.
-    DictionaryPrefUpdate update(&local_state_, prefs::kProfilePreferenceHashes);
-    base::DictionaryValue* store_versions_dict = NULL;
-    ASSERT_TRUE(update->GetDictionaryWithoutPathExpansion(
-        internals::kStoreVersionsDict, &store_versions_dict));
-    scoped_ptr<base::Value> stored_value;
-    store_versions_dict->Remove("store_id", &stored_value);
-    int stored_version;
-    EXPECT_TRUE(stored_value->GetAsInteger(&stored_version));
-    EXPECT_EQ(PrefHashStoreImpl::VERSION_LATEST, stored_version);
-    // There should be no versions left in the versions dictionary.
-    EXPECT_TRUE(store_versions_dict->empty());
-  }
+
+  // Manually clear the version number.
+  hash_store_data_.version.reset();
+
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
 
-    // VERSION_PRE_MIGRATION when no version is present for "store_id".
+    // VERSION_PRE_MIGRATION when no version is stored.
     EXPECT_EQ(PrefHashStoreImpl::VERSION_PRE_MIGRATION,
               pref_hash_store.GetCurrentVersion());
 
     scoped_ptr<PrefHashStoreTransaction> transaction(
         pref_hash_store.BeginTransaction());
+
+    // Test that |pref_hash_store| flushes its content to disk when it
+    // re-initializes its version.
+    transaction.reset();
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_TRUE(hash_store_data_.GetCommitPerformedAndReset());
   }
   {
     PrefHashStoreImpl pref_hash_store(
-        "store_id", std::string(32, 0), "device_id", &local_state_);
+        std::string(32, 0), "device_id", CreateHashStoreContents());
 
     // Back to VERSION_LATEST after performing a transaction from
     // VERSION_PRE_MIGRATION (the presence of an existing hash should be
     // sufficient, no need for the transaction itself to perform any work).
     EXPECT_EQ(PrefHashStoreImpl::VERSION_LATEST,
               pref_hash_store.GetCurrentVersion());
+
+    // Test that |pref_hash_store| doesn't flush its contents to disk when it
+    // didn't change (i.e., its version was already up-to-date and the only
+    // transaction performed was empty).
+    scoped_ptr<PrefHashStoreTransaction> transaction(
+        pref_hash_store.BeginTransaction());
+    transaction.reset();
+    pref_hash_store.CommitPendingWrite();
+    EXPECT_FALSE(hash_store_data_.GetCommitPerformedAndReset());
   }
 }