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