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