Home | History | Annotate | Download | only in prefs
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/prefs/leveldb_pref_store.h"
      6 
      7 #include "base/files/file_util.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/path_service.h"
     12 #include "base/run_loop.h"
     13 #include "base/values.h"
     14 #include "chrome/common/chrome_paths.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace {
     19 
     20 class MockPrefStoreObserver : public PrefStore::Observer {
     21  public:
     22   MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
     23   MOCK_METHOD1(OnInitializationCompleted, void(bool));
     24 };
     25 
     26 class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
     27  public:
     28   MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
     29 };
     30 
     31 }  // namespace
     32 
     33 class LevelDBPrefStoreTest : public testing::Test {
     34  protected:
     35   virtual void SetUp() OVERRIDE {
     36     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     37 
     38     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_));
     39     data_dir_ = data_dir_.AppendASCII("prefs");
     40     ASSERT_TRUE(PathExists(data_dir_));
     41   }
     42 
     43   virtual void TearDown() OVERRIDE {
     44     Close();
     45   }
     46 
     47   void Open() {
     48     pref_store_ = new LevelDBPrefStore(
     49         temp_dir_.path(), message_loop_.message_loop_proxy().get());
     50     EXPECT_EQ(LevelDBPrefStore::PREF_READ_ERROR_NONE, pref_store_->ReadPrefs());
     51   }
     52 
     53   void Close() {
     54     pref_store_ = NULL;
     55     base::RunLoop().RunUntilIdle();
     56   }
     57 
     58   void CloseAndReopen() {
     59     Close();
     60     Open();
     61   }
     62 
     63   // The path to temporary directory used to contain the test operations.
     64   base::ScopedTempDir temp_dir_;
     65   // The path to the directory where the test data is stored in the source tree.
     66   base::FilePath data_dir_;
     67   // A message loop that we can use as the file thread message loop.
     68   base::MessageLoop message_loop_;
     69 
     70   scoped_refptr<LevelDBPrefStore> pref_store_;
     71 };
     72 
     73 TEST_F(LevelDBPrefStoreTest, PutAndGet) {
     74   Open();
     75   const std::string key = "some.key";
     76   pref_store_->SetValue(key, new base::FundamentalValue(5));
     77   base::FundamentalValue orig_value(5);
     78   const base::Value* actual_value;
     79   EXPECT_TRUE(pref_store_->GetValue(key, &actual_value));
     80   EXPECT_TRUE(orig_value.Equals(actual_value));
     81 }
     82 
     83 TEST_F(LevelDBPrefStoreTest, PutAndGetPersistent) {
     84   Open();
     85   const std::string key = "some.key";
     86   pref_store_->SetValue(key, new base::FundamentalValue(5));
     87 
     88   CloseAndReopen();
     89   const base::Value* actual_value = NULL;
     90   base::FundamentalValue orig_value(5);
     91   EXPECT_TRUE(pref_store_->GetValue(key, &actual_value));
     92   EXPECT_TRUE(orig_value.Equals(actual_value));
     93 }
     94 
     95 TEST_F(LevelDBPrefStoreTest, BasicObserver) {
     96   scoped_refptr<LevelDBPrefStore> pref_store = new LevelDBPrefStore(
     97       temp_dir_.path(), message_loop_.message_loop_proxy().get());
     98   MockPrefStoreObserver mock_observer;
     99   pref_store->AddObserver(&mock_observer);
    100   EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
    101   EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
    102   testing::Mock::VerifyAndClearExpectations(&mock_observer);
    103 
    104   const std::string key = "some.key";
    105   EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(1);
    106   pref_store->SetValue(key, new base::FundamentalValue(5));
    107 
    108   pref_store->RemoveObserver(&mock_observer);
    109 }
    110 
    111 TEST_F(LevelDBPrefStoreTest, SetValueSilently) {
    112   Open();
    113 
    114   MockPrefStoreObserver mock_observer;
    115   pref_store_->AddObserver(&mock_observer);
    116   const std::string key = "some.key";
    117   EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(0);
    118   pref_store_->SetValueSilently(key, new base::FundamentalValue(30));
    119   pref_store_->RemoveObserver(&mock_observer);
    120 
    121   CloseAndReopen();
    122   base::FundamentalValue value(30);
    123   const base::Value* actual_value = NULL;
    124   EXPECT_TRUE(pref_store_->GetValue(key, &actual_value));
    125   EXPECT_TRUE(base::Value::Equals(&value, actual_value));
    126 }
    127 
    128 TEST_F(LevelDBPrefStoreTest, GetMutableValue) {
    129   Open();
    130 
    131   const std::string key = "some.key";
    132   base::DictionaryValue* orig_value = new base::DictionaryValue;
    133   orig_value->SetInteger("key2", 25);
    134   pref_store_->SetValue(key, orig_value);
    135 
    136   base::Value* actual_value;
    137   EXPECT_TRUE(pref_store_->GetMutableValue(key, &actual_value));
    138   EXPECT_TRUE(orig_value->Equals(actual_value));
    139   base::DictionaryValue* dict_value;
    140   ASSERT_TRUE(actual_value->GetAsDictionary(&dict_value));
    141   dict_value->SetInteger("key2", 30);
    142   pref_store_->ReportValueChanged(key);
    143 
    144   // Ensure the new value is stored in memory.
    145   const base::Value* retrieved_value;
    146   EXPECT_TRUE(pref_store_->GetValue(key, &retrieved_value));
    147   scoped_ptr<base::DictionaryValue> golden_value(new base::DictionaryValue);
    148   golden_value->SetInteger("key2", 30);
    149   EXPECT_TRUE(base::Value::Equals(golden_value.get(), retrieved_value));
    150 
    151   // Ensure the new value is persisted to disk.
    152   CloseAndReopen();
    153   EXPECT_TRUE(pref_store_->GetValue(key, &retrieved_value));
    154   EXPECT_TRUE(base::Value::Equals(golden_value.get(), retrieved_value));
    155 }
    156 
    157 TEST_F(LevelDBPrefStoreTest, RemoveFromMemory) {
    158   Open();
    159   const std::string key = "some.key";
    160   pref_store_->SetValue(key, new base::FundamentalValue(5));
    161 
    162   MockPrefStoreObserver mock_observer;
    163   pref_store_->AddObserver(&mock_observer);
    164   EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(1);
    165   pref_store_->RemoveValue(key);
    166   pref_store_->RemoveObserver(&mock_observer);
    167 
    168   const base::Value* retrieved_value;
    169   EXPECT_FALSE(pref_store_->GetValue(key, &retrieved_value));
    170 }
    171 
    172 TEST_F(LevelDBPrefStoreTest, RemoveFromDisk) {
    173   Open();
    174   const std::string key = "some.key";
    175   pref_store_->SetValue(key, new base::FundamentalValue(5));
    176 
    177   CloseAndReopen();
    178 
    179   pref_store_->RemoveValue(key);
    180 
    181   CloseAndReopen();
    182 
    183   const base::Value* retrieved_value;
    184   EXPECT_FALSE(pref_store_->GetValue(key, &retrieved_value));
    185 }
    186 
    187 TEST_F(LevelDBPrefStoreTest, OpenAsync) {
    188   // First set a key/value with a synchronous connection.
    189   Open();
    190   const std::string key = "some.key";
    191   pref_store_->SetValue(key, new base::FundamentalValue(5));
    192   Close();
    193 
    194   scoped_refptr<LevelDBPrefStore> pref_store(new LevelDBPrefStore(
    195       temp_dir_.path(), message_loop_.message_loop_proxy().get()));
    196   MockReadErrorDelegate* delegate = new MockReadErrorDelegate;
    197   pref_store->ReadPrefsAsync(delegate);
    198 
    199   MockPrefStoreObserver mock_observer;
    200   pref_store->AddObserver(&mock_observer);
    201   EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
    202   base::RunLoop().RunUntilIdle();
    203   pref_store->RemoveObserver(&mock_observer);
    204 
    205   const base::Value* result;
    206   EXPECT_TRUE(pref_store->GetValue("some.key", &result));
    207   int int_value;
    208   EXPECT_TRUE(result->GetAsInteger(&int_value));
    209   EXPECT_EQ(5, int_value);
    210 
    211   pref_store = NULL;
    212 }
    213 
    214 TEST_F(LevelDBPrefStoreTest, OpenAsyncError) {
    215   // Open a connection that will lock the database.
    216   Open();
    217 
    218   // Try to open an async connection to the same database.
    219   scoped_refptr<LevelDBPrefStore> pref_store(new LevelDBPrefStore(
    220       temp_dir_.path(), message_loop_.message_loop_proxy().get()));
    221   MockReadErrorDelegate* delegate = new MockReadErrorDelegate;
    222   pref_store->ReadPrefsAsync(delegate);
    223 
    224   MockPrefStoreObserver mock_observer;
    225   pref_store->AddObserver(&mock_observer);
    226   EXPECT_CALL(*delegate,
    227               OnError(PersistentPrefStore::PREF_READ_ERROR_LEVELDB_IO))
    228       .Times(1);
    229   EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
    230   base::RunLoop().RunUntilIdle();
    231   pref_store->RemoveObserver(&mock_observer);
    232 
    233   EXPECT_TRUE(pref_store->ReadOnly());
    234   EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_LEVELDB_IO,
    235             pref_store->GetReadError());
    236 
    237   // Sync connection to the database will be closed by the destructor.
    238 }
    239 
    240 TEST_F(LevelDBPrefStoreTest, RepairCorrupt) {
    241   // Open a database where CURRENT has no newline. Ensure that repair is called
    242   // and there is no error reading the database.
    243   base::FilePath corrupted_dir = data_dir_.AppendASCII("corrupted_leveldb");
    244   base::FilePath dest = temp_dir_.path().AppendASCII("corrupted_leveldb");
    245   const bool kRecursive = true;
    246   ASSERT_TRUE(CopyDirectory(corrupted_dir, dest, kRecursive));
    247   pref_store_ =
    248       new LevelDBPrefStore(dest, message_loop_.message_loop_proxy().get());
    249   EXPECT_EQ(LevelDBPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION,
    250             pref_store_->ReadPrefs());
    251 }
    252 
    253 TEST_F(LevelDBPrefStoreTest, Values) {
    254   Open();
    255   pref_store_->SetValue("boolean", new base::FundamentalValue(false));
    256   pref_store_->SetValue("integer", new base::FundamentalValue(10));
    257   pref_store_->SetValue("double", new base::FundamentalValue(10.3));
    258   pref_store_->SetValue("string", new base::StringValue("some string"));
    259 
    260   base::DictionaryValue* dict_value = new base::DictionaryValue;
    261   dict_value->Set("boolean", new base::FundamentalValue(true));
    262   scoped_ptr<base::DictionaryValue> golden_dict_value(dict_value->DeepCopy());
    263   pref_store_->SetValue("dictionary", dict_value);
    264 
    265   base::ListValue* list_value = new base::ListValue;
    266   list_value->Set(2, new base::StringValue("string in list"));
    267   scoped_ptr<base::ListValue> golden_list_value(list_value->DeepCopy());
    268   pref_store_->SetValue("list", list_value);
    269 
    270   // Do something nontrivial as well.
    271   base::DictionaryValue* compound_value = new base::DictionaryValue;
    272   base::ListValue* outer_list = new base::ListValue;
    273   base::ListValue* inner_list = new base::ListValue;
    274   inner_list->Set(0, new base::FundamentalValue(5));
    275   outer_list->Set(1, inner_list);
    276   compound_value->Set("compound_lists", outer_list);
    277   scoped_ptr<base::DictionaryValue> golden_compound_value(
    278       compound_value->DeepCopy());
    279   pref_store_->SetValue("compound_value", compound_value);
    280 
    281   CloseAndReopen();
    282 
    283   const base::Value* value;
    284   EXPECT_TRUE(pref_store_->GetValue("boolean", &value));
    285   EXPECT_TRUE(base::FundamentalValue(false).Equals(value));
    286 
    287   EXPECT_TRUE(pref_store_->GetValue("integer", &value));
    288   EXPECT_TRUE(base::FundamentalValue(10).Equals(value));
    289 
    290   EXPECT_TRUE(pref_store_->GetValue("double", &value));
    291   EXPECT_TRUE(base::FundamentalValue(10.3).Equals(value));
    292 
    293   EXPECT_TRUE(pref_store_->GetValue("string", &value));
    294   EXPECT_TRUE(base::StringValue("some string").Equals(value));
    295 
    296   EXPECT_TRUE(pref_store_->GetValue("dictionary", &value));
    297   EXPECT_TRUE(base::Value::Equals(golden_dict_value.get(), value));
    298 
    299   EXPECT_TRUE(pref_store_->GetValue("list", &value));
    300   EXPECT_TRUE(base::Value::Equals(golden_list_value.get(), value));
    301 
    302   EXPECT_TRUE(pref_store_->GetValue("compound_value", &value));
    303   EXPECT_TRUE(base::Value::Equals(golden_compound_value.get(), value));
    304 }
    305