Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: services/preferences/user_prefs_unittest.cc

Issue 2743563003: Pref service: add persistent pref store frontend and backend. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "services/preferences/user_prefs.h"
6
7 #include "base/macros.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/values.h"
12 #include "components/prefs/in_memory_pref_store.h"
13 #include "mojo/public/cpp/bindings/binding_set.h"
14 #include "services/preferences/public/cpp/persistent_pref_store_client.h"
15 #include "services/preferences/public/cpp/pref_store_client.h"
16 #include "services/preferences/public/interfaces/preferences.mojom.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using testing::Invoke;
21 using testing::WithoutArgs;
22
23 namespace prefs {
24 namespace {
25
26 class PrefStoreObserverMock : public PrefStore::Observer {
27 public:
28 MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
29 MOCK_METHOD1(OnInitializationCompleted, void(bool succeeded));
30 };
31
32 class PersistentPrefStoreMock : public InMemoryPrefStore {
33 public:
34 MOCK_METHOD0(CommitPendingWrite, void());
35 MOCK_METHOD0(SchedulePendingLossyWrites, void());
36 MOCK_METHOD0(ClearMutableValues, void());
37
38 private:
39 ~PersistentPrefStoreMock() override = default;
40 };
41
42 class PrefStoreConnectorMock : public mojom::PrefStoreConnector {
43 public:
44 MOCK_METHOD1(Connect, void(const ConnectCallback&));
45 };
46
47 class InitializationMockPersistentPrefStore : public InMemoryPrefStore {
48 public:
49 bool IsInitializationComplete() const override { return initialized_; }
50
51 void AddObserver(PrefStore::Observer* observer) override {
52 observers_.AddObserver(observer);
53 }
54
55 void RemoveObserver(PrefStore::Observer* observer) override {
56 observers_.RemoveObserver(observer);
57 }
58
59 void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {
60 DCHECK(!error_delegate);
61 }
62
63 PersistentPrefStore::PrefReadError GetReadError() const override {
64 return read_error_;
65 }
66 bool ReadOnly() const override { return read_only_; }
67
68 void Initialize(bool success,
69 PersistentPrefStore::PrefReadError error,
70 bool read_only) {
71 initialized_ = success;
72 read_error_ = error;
73 read_only_ = read_only;
74 for (auto& observer : observers_) {
75 observer.OnInitializationCompleted(initialized_);
76 }
77 }
78
79 private:
80 ~InitializationMockPersistentPrefStore() override = default;
81
82 PersistentPrefStore::PrefReadError read_error_;
83 bool read_only_ = false;
84 bool initialized_ = false;
85 base::ObserverList<PrefStore::Observer, true> observers_;
86 };
87
88 class UserPrefsTest : public testing::Test {
89 public:
90 UserPrefsTest() = default;
91
92 // testing::Test:
93 void TearDown() override {
94 pref_store_ = nullptr;
95 base::RunLoop().RunUntilIdle();
96 bindings_.CloseAllBindings();
97 user_prefs_.reset();
98 base::RunLoop().RunUntilIdle();
99 }
100
101 void CreateUserPrefs(scoped_refptr<PersistentPrefStore> backing_pref_store) {
102 user_prefs_ =
103 base::MakeUnique<UserPrefs>(std::move(backing_pref_store), nullptr);
104 mojo::Binding<mojom::PersistentPrefStoreConnector> binding(
105 user_prefs_.get());
106 pref_store_ = CreateConnection();
107 }
108
109 mojom::PersistentPrefStoreConnectorPtr CreateConnector() {
110 return bindings_.CreateInterfacePtrAndBind(user_prefs_.get());
111 }
112
113 scoped_refptr<PersistentPrefStore> CreateConnection() {
114 return make_scoped_refptr(new PersistentPrefStoreClient(
115 bindings_.CreateInterfacePtrAndBind(user_prefs_.get())));
116 }
117
118 PersistentPrefStore* pref_store() { return pref_store_.get(); }
119
120 private:
121 base::MessageLoop message_loop_;
122
123 std::unique_ptr<UserPrefs> user_prefs_;
124 mojo::BindingSet<mojom::PersistentPrefStoreConnector> bindings_;
125
126 scoped_refptr<PersistentPrefStore> pref_store_;
127
128 DISALLOW_COPY_AND_ASSIGN(UserPrefsTest);
129 };
130
131 TEST_F(UserPrefsTest, InitializationSuccess) {
132 auto backing_pref_store =
133 make_scoped_refptr(new InitializationMockPersistentPrefStore);
134 CreateUserPrefs(backing_pref_store);
135 backing_pref_store->Initialize(
136 true, PersistentPrefStore::PREF_READ_ERROR_NONE, false);
137 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
138 pref_store()->ReadPrefs());
139 EXPECT_TRUE(pref_store()->IsInitializationComplete());
140 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
141 pref_store()->GetReadError());
142 EXPECT_FALSE(pref_store()->ReadOnly());
143 }
144
145 TEST_F(UserPrefsTest, InitializationFailure) {
146 auto backing_pref_store =
147 make_scoped_refptr(new InitializationMockPersistentPrefStore);
148 CreateUserPrefs(backing_pref_store);
149 backing_pref_store->Initialize(
150 false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true);
151 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
152 pref_store()->ReadPrefs());
153 EXPECT_FALSE(pref_store()->IsInitializationComplete());
154 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
155 pref_store()->GetReadError());
156 EXPECT_TRUE(pref_store()->ReadOnly());
157 }
158
159 class TestReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
160 public:
161 TestReadErrorDelegate(PersistentPrefStore::PrefReadError* storage,
162 const base::Closure& quit)
163 : storage_(storage), quit_(quit) {
164 DCHECK(storage_);
165 DCHECK(quit_);
166 }
167
168 void OnError(PersistentPrefStore::PrefReadError error) override {
169 *storage_ = error;
170 quit_.Run();
171 }
172
173 private:
174 PersistentPrefStore::PrefReadError* const storage_;
175 const base::Closure quit_;
176 };
177
178 TEST_F(UserPrefsTest, InitializationFailure_AsyncRead) {
179 auto backing_pref_store =
180 make_scoped_refptr(new InitializationMockPersistentPrefStore);
181 CreateUserPrefs(backing_pref_store);
182 backing_pref_store->Initialize(
183 false, PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, true);
184 PersistentPrefStore::PrefReadError read_error =
185 PersistentPrefStore::PREF_READ_ERROR_NONE;
186 base::RunLoop run_loop;
187 pref_store()->ReadPrefsAsync(
188 new TestReadErrorDelegate(&read_error, run_loop.QuitClosure()));
189 run_loop.Run();
190 EXPECT_FALSE(pref_store()->IsInitializationComplete());
191 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE, read_error);
192 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE,
193 pref_store()->GetReadError());
194 EXPECT_TRUE(pref_store()->ReadOnly());
195 }
196
197 TEST_F(UserPrefsTest, DelayedInitializationSuccess) {
198 auto backing_pref_store =
199 make_scoped_refptr(new InitializationMockPersistentPrefStore);
200
201 CreateUserPrefs(backing_pref_store);
202 auto connector = CreateConnector();
203 base::RunLoop run_loop;
204 connector->Connect(base::Bind(
205 [](const base::Closure& quit,
206 PersistentPrefStore::PrefReadError read_error, bool read_only,
207 std::unique_ptr<base::DictionaryValue> local_prefs,
208 mojom::PersistentPrefStorePtr pref_store,
209 mojom::PrefStoreObserverRequest observer_request) {
210 quit.Run();
211 EXPECT_FALSE(read_only);
212 EXPECT_TRUE(local_prefs);
213 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, read_error);
214 },
215 run_loop.QuitClosure()));
216 connector.FlushForTesting();
217 backing_pref_store->Initialize(
218 true, PersistentPrefStore::PREF_READ_ERROR_NONE, false);
219 run_loop.Run();
220 }
221
222 TEST_F(UserPrefsTest, DelayedInitializationFailure) {
223 auto backing_pref_store =
224 make_scoped_refptr(new InitializationMockPersistentPrefStore);
225
226 CreateUserPrefs(backing_pref_store);
227 auto connector = CreateConnector();
228 base::RunLoop run_loop;
229 connector->Connect(base::Bind(
230 [](const base::Closure& quit,
231 PersistentPrefStore::PrefReadError read_error, bool read_only,
232 std::unique_ptr<base::DictionaryValue> local_prefs,
233 mojom::PersistentPrefStorePtr pref_store,
234 mojom::PrefStoreObserverRequest observer_request) {
235 quit.Run();
236 EXPECT_TRUE(read_only);
237 EXPECT_FALSE(local_prefs);
238 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
239 read_error);
240 },
241 run_loop.QuitClosure()));
242 connector.FlushForTesting();
243 backing_pref_store->Initialize(
244 false, PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED, true);
245 run_loop.Run();
246 }
247
248 constexpr char kKey[] = "path.to.key";
249
250 TEST_F(UserPrefsTest, InitialValue) {
251 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
252 const base::Value value("value");
253 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
254 CreateUserPrefs(backing_pref_store);
255 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
256 pref_store()->ReadPrefs());
257 EXPECT_TRUE(pref_store()->IsInitializationComplete());
258 const base::Value* output = nullptr;
259 ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
260 EXPECT_TRUE(value.Equals(output));
261 }
262
263 TEST_F(UserPrefsTest, InitialValueWithoutPathExpansion) {
264 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
265 base::DictionaryValue dict;
266 dict.SetStringWithoutPathExpansion(kKey, "value");
267 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
268 CreateUserPrefs(backing_pref_store);
269 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
270 pref_store()->ReadPrefs());
271 EXPECT_TRUE(pref_store()->IsInitializationComplete());
272 const base::Value* output = nullptr;
273 ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
274 EXPECT_TRUE(dict.Equals(output));
275 }
276
277 TEST_F(UserPrefsTest, WriteObservedByOtherClient) {
278 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
279 CreateUserPrefs(backing_pref_store);
280 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
281 pref_store()->ReadPrefs());
282 EXPECT_TRUE(pref_store()->IsInitializationComplete());
283
284 auto other_pref_store = CreateConnection();
285 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
286 other_pref_store->ReadPrefs());
287 EXPECT_TRUE(other_pref_store->IsInitializationComplete());
288
289 const base::Value value("value");
290 pref_store()->SetValueSilently(kKey, value.CreateDeepCopy(), 0);
291
292 PrefStoreObserverMock observer;
293 other_pref_store->AddObserver(&observer);
294 base::RunLoop run_loop;
295 EXPECT_CALL(observer, OnPrefValueChanged(kKey))
296 .Times(1)
297 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
298 run_loop.Run();
299 other_pref_store->RemoveObserver(&observer);
300
301 const base::Value* output = nullptr;
302 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
303 EXPECT_TRUE(value.Equals(output));
304 }
305
306 TEST_F(UserPrefsTest, WriteWithoutPathExpansionObservedByOtherClient) {
307 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
308 CreateUserPrefs(backing_pref_store);
309 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
310 pref_store()->ReadPrefs());
311 EXPECT_TRUE(pref_store()->IsInitializationComplete());
312
313 auto other_pref_store = CreateConnection();
314 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
315 other_pref_store->ReadPrefs());
316 EXPECT_TRUE(other_pref_store->IsInitializationComplete());
317
318 base::DictionaryValue dict;
319 dict.SetStringWithoutPathExpansion(kKey, "value");
320 pref_store()->SetValue(kKey, dict.CreateDeepCopy(), 0);
321
322 PrefStoreObserverMock observer;
323 other_pref_store->AddObserver(&observer);
324 base::RunLoop run_loop;
325 EXPECT_CALL(observer, OnPrefValueChanged(kKey))
326 .Times(1)
327 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
328 run_loop.Run();
329 other_pref_store->RemoveObserver(&observer);
330
331 const base::Value* output = nullptr;
332 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
333 EXPECT_TRUE(dict.Equals(output));
334 }
335
336 TEST_F(UserPrefsTest, RemoveObservedByOtherClient) {
337 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
338 const base::Value value("value");
339 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
340 CreateUserPrefs(backing_pref_store);
341 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
342 pref_store()->ReadPrefs());
343 EXPECT_TRUE(pref_store()->IsInitializationComplete());
344
345 auto other_pref_store = CreateConnection();
346 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
347 other_pref_store->ReadPrefs());
348 EXPECT_TRUE(other_pref_store->IsInitializationComplete());
349
350 const base::Value* output = nullptr;
351 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
352 EXPECT_TRUE(value.Equals(output));
353 pref_store()->RemoveValue(kKey, 0);
354
355 // This should be a no-op and shouldn't trigger a notification for the other
356 // client.
357 pref_store()->RemoveValue(kKey, 0);
358
359 PrefStoreObserverMock observer;
360 other_pref_store->AddObserver(&observer);
361 base::RunLoop run_loop;
362 EXPECT_CALL(observer, OnPrefValueChanged(kKey))
363 .Times(1)
364 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
365 run_loop.Run();
366 base::RunLoop().RunUntilIdle();
367 other_pref_store->RemoveObserver(&observer);
368
369 EXPECT_FALSE(other_pref_store->GetValue(kKey, &output));
370 }
371
372 TEST_F(UserPrefsTest, RemoveWithoutPathExpansionObservedByOtherClient) {
373 auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
374 base::DictionaryValue dict;
375 dict.SetStringWithoutPathExpansion(kKey, "value");
376 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
377 CreateUserPrefs(backing_pref_store);
378 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
379 pref_store()->ReadPrefs());
380 EXPECT_TRUE(pref_store()->IsInitializationComplete());
381
382 auto other_pref_store = CreateConnection();
383 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
384 other_pref_store->ReadPrefs());
385 EXPECT_TRUE(other_pref_store->IsInitializationComplete());
386
387 const base::Value* output = nullptr;
388 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
389 EXPECT_TRUE(dict.Equals(output));
390
391 base::Value* mutable_value = nullptr;
392 dict.SetStringWithoutPathExpansion(kKey, "value");
393 ASSERT_TRUE(pref_store()->GetMutableValue(kKey, &mutable_value));
394 base::DictionaryValue* mutable_dict = nullptr;
395 ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict));
396 mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr);
397 pref_store()->ReportValueChanged(kKey, 0);
398
399 PrefStoreObserverMock observer;
400 other_pref_store->AddObserver(&observer);
401 base::RunLoop run_loop;
402 EXPECT_CALL(observer, OnPrefValueChanged(kKey))
403 .Times(1)
404 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
405 run_loop.Run();
406 other_pref_store->RemoveObserver(&observer);
407
408 ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
409 const base::DictionaryValue* dict_value = nullptr;
410 ASSERT_TRUE(output->GetAsDictionary(&dict_value));
411 EXPECT_TRUE(dict_value->empty());
412 }
413
414 TEST_F(UserPrefsTest, CommitPendingWrite) {
415 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
416 CreateUserPrefs(backing_store);
417 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
418 pref_store()->ReadPrefs());
419 base::RunLoop run_loop;
420 EXPECT_CALL(*backing_store, CommitPendingWrite())
421 .Times(2)
422 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
423 pref_store()->CommitPendingWrite();
424 run_loop.Run();
425 }
426
427 TEST_F(UserPrefsTest, SchedulePendingLossyWrites) {
428 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
429 CreateUserPrefs(backing_store);
430 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
431 pref_store()->ReadPrefs());
432 base::RunLoop run_loop;
433 EXPECT_CALL(*backing_store, SchedulePendingLossyWrites())
434 .Times(1)
435 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
436 EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
437 pref_store()->SchedulePendingLossyWrites();
438 run_loop.Run();
439 }
440
441 TEST_F(UserPrefsTest, ClearMutableValues) {
442 auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
443 CreateUserPrefs(backing_store);
444 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
445 pref_store()->ReadPrefs());
446 base::RunLoop run_loop;
447 EXPECT_CALL(*backing_store, ClearMutableValues())
448 .Times(1)
449 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
450 EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
451 pref_store()->ClearMutableValues();
452 run_loop.Run();
453 }
454
455 } // namespace
456 } // namespace prefs
OLDNEW
« services/preferences/user_prefs.cc ('K') | « services/preferences/user_prefs.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698