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 18namespace { 19 20class MockPrefStoreObserver : public PrefStore::Observer { 21 public: 22 MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); 23 MOCK_METHOD1(OnInitializationCompleted, void(bool)); 24}; 25 26class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate { 27 public: 28 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError)); 29}; 30 31} // namespace 32 33class 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 73TEST_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 83TEST_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 95TEST_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 111TEST_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 128TEST_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 157TEST_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 172TEST_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 187TEST_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 214TEST_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 240TEST_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 253TEST_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