• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SetUp()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 
TearDown()43   virtual void TearDown() OVERRIDE {
44     Close();
45   }
46 
Open()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 
Close()53   void Close() {
54     pref_store_ = NULL;
55     base::RunLoop().RunUntilIdle();
56   }
57 
CloseAndReopen()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 
TEST_F(LevelDBPrefStoreTest,PutAndGet)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 
TEST_F(LevelDBPrefStoreTest,PutAndGetPersistent)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 
TEST_F(LevelDBPrefStoreTest,BasicObserver)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 
TEST_F(LevelDBPrefStoreTest,SetValueSilently)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 
TEST_F(LevelDBPrefStoreTest,GetMutableValue)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 
TEST_F(LevelDBPrefStoreTest,RemoveFromMemory)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 
TEST_F(LevelDBPrefStoreTest,RemoveFromDisk)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 
TEST_F(LevelDBPrefStoreTest,OpenAsync)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 
TEST_F(LevelDBPrefStoreTest,OpenAsyncError)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 
TEST_F(LevelDBPrefStoreTest,RepairCorrupt)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 
TEST_F(LevelDBPrefStoreTest,Values)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