1 // Copyright 2012 The Chromium Authors
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 "components/prefs/json_pref_store.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/compiler_specific.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/location.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/metrics/histogram_samples.h"
20 #include "base/path_service.h"
21 #include "base/run_loop.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/synchronization/waitable_event.h"
26 #include "base/task/sequenced_task_runner.h"
27 #include "base/task/single_thread_task_runner.h"
28 #include "base/test/metrics/histogram_tester.h"
29 #include "base/test/scoped_feature_list.h"
30 #include "base/test/task_environment.h"
31 #include "base/threading/thread.h"
32 #include "base/values.h"
33 #include "components/prefs/persistent_pref_store_unittest.h"
34 #include "components/prefs/pref_filter.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 namespace base {
39 namespace {
40
41 const char kHomePage[] = "homepage";
42
43 const char kReadJson[] =
44 "{\n"
45 " \"homepage\": \"http://www.cnn.com\",\n"
46 " \"some_directory\": \"/usr/local/\",\n"
47 " \"tabs\": {\n"
48 " \"new_windows_in_tabs\": true,\n"
49 " \"max_tabs\": 20\n"
50 " }\n"
51 "}";
52
53 const char kInvalidJson[] = "!@#$%^&";
54
55 // Expected output for tests using RunBasicJsonPrefStoreTest().
56 const char kWriteGolden[] =
57 "{\"homepage\":\"http://www.cnn.com\","
58 "\"long_int\":{\"pref\":\"214748364842\"},"
59 "\"some_directory\":\"/usr/sbin/\","
60 "\"tabs\":{\"max_tabs\":10,\"new_windows_in_tabs\":false}}";
61
62 // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
63 // to the |prefs| until explicitly asked to release them.
64 class InterceptingPrefFilter : public PrefFilter {
65 public:
66 InterceptingPrefFilter();
67 InterceptingPrefFilter(OnWriteCallbackPair callback_pair);
68
69 InterceptingPrefFilter(const InterceptingPrefFilter&) = delete;
70 InterceptingPrefFilter& operator=(const InterceptingPrefFilter&) = delete;
71
72 ~InterceptingPrefFilter() override;
73
74 // PrefFilter implementation:
75 void FilterOnLoad(PostFilterOnLoadCallback post_filter_on_load_callback,
76 base::Value::Dict pref_store_contents) override;
FilterUpdate(std::string_view path)77 void FilterUpdate(std::string_view path) override {}
FilterSerializeData(base::Value::Dict & pref_store_contents)78 OnWriteCallbackPair FilterSerializeData(
79 base::Value::Dict& pref_store_contents) override {
80 return std::move(on_write_callback_pair_);
81 }
OnStoreDeletionFromDisk()82 void OnStoreDeletionFromDisk() override {}
83
has_intercepted_prefs() const84 bool has_intercepted_prefs() const { return intercepted_prefs_ != nullptr; }
85
86 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
87 // JsonPrefStore.
88 void ReleasePrefs();
89
90 private:
91 PostFilterOnLoadCallback post_filter_on_load_callback_;
92 std::unique_ptr<base::Value::Dict> intercepted_prefs_;
93 OnWriteCallbackPair on_write_callback_pair_;
94 };
95
96 InterceptingPrefFilter::InterceptingPrefFilter() = default;
97
InterceptingPrefFilter(OnWriteCallbackPair callback_pair)98 InterceptingPrefFilter::InterceptingPrefFilter(
99 OnWriteCallbackPair callback_pair) {
100 on_write_callback_pair_ = std::move(callback_pair);
101 }
102
103 InterceptingPrefFilter::~InterceptingPrefFilter() = default;
104
FilterOnLoad(PostFilterOnLoadCallback post_filter_on_load_callback,base::Value::Dict pref_store_contents)105 void InterceptingPrefFilter::FilterOnLoad(
106 PostFilterOnLoadCallback post_filter_on_load_callback,
107 base::Value::Dict pref_store_contents) {
108 post_filter_on_load_callback_ = std::move(post_filter_on_load_callback);
109 intercepted_prefs_ =
110 std::make_unique<base::Value::Dict>(std::move(pref_store_contents));
111 }
112
ReleasePrefs()113 void InterceptingPrefFilter::ReleasePrefs() {
114 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
115 std::unique_ptr<base::Value::Dict> prefs = std::move(intercepted_prefs_);
116 std::move(post_filter_on_load_callback_).Run(std::move(*prefs), false);
117 }
118
119 class MockPrefStoreObserver : public PrefStore::Observer {
120 public:
121 MOCK_METHOD(void, OnInitializationCompleted, (bool), (override));
122 };
123
124 class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
125 public:
126 MOCK_METHOD(void, OnError, (PersistentPrefStore::PrefReadError), (override));
127 };
128
129 enum class CommitPendingWriteMode {
130 // Basic mode.
131 WITHOUT_CALLBACK,
132 // With reply callback.
133 WITH_CALLBACK,
134 // With synchronous notify callback (synchronous after the write -- shouldn't
135 // require pumping messages to observe).
136 WITH_SYNCHRONOUS_CALLBACK,
137 };
138
GetExecutionMode(CommitPendingWriteMode commit_mode)139 base::test::TaskEnvironment::ThreadPoolExecutionMode GetExecutionMode(
140 CommitPendingWriteMode commit_mode) {
141 switch (commit_mode) {
142 case CommitPendingWriteMode::WITHOUT_CALLBACK:
143 [[fallthrough]];
144 case CommitPendingWriteMode::WITH_CALLBACK:
145 return base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED;
146 case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK:
147 // Synchronous callbacks require async tasks to run on their own.
148 return base::test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC;
149 }
150 }
151
CommitPendingWrite(JsonPrefStore * pref_store,CommitPendingWriteMode commit_pending_write_mode,base::test::TaskEnvironment * task_environment)152 void CommitPendingWrite(JsonPrefStore* pref_store,
153 CommitPendingWriteMode commit_pending_write_mode,
154 base::test::TaskEnvironment* task_environment) {
155 switch (commit_pending_write_mode) {
156 case CommitPendingWriteMode::WITHOUT_CALLBACK: {
157 pref_store->CommitPendingWrite();
158 task_environment->RunUntilIdle();
159 break;
160 }
161 case CommitPendingWriteMode::WITH_CALLBACK: {
162 TestCommitPendingWriteWithCallback(pref_store, task_environment);
163 break;
164 }
165 case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK: {
166 base::WaitableEvent written;
167 pref_store->CommitPendingWrite(
168 base::OnceClosure(),
169 base::BindOnce(&base::WaitableEvent::Signal, Unretained(&written)));
170 written.Wait();
171 break;
172 }
173 }
174 }
175
176 class JsonPrefStoreTest
177 : public testing::TestWithParam<CommitPendingWriteMode> {
178 public:
JsonPrefStoreTest()179 JsonPrefStoreTest()
180 : task_environment_(base::test::TaskEnvironment::MainThreadType::DEFAULT,
181 GetExecutionMode(GetParam())) {}
182
183 JsonPrefStoreTest(const JsonPrefStoreTest&) = delete;
184 JsonPrefStoreTest& operator=(const JsonPrefStoreTest&) = delete;
185
186 protected:
SetUp()187 void SetUp() override {
188 commit_pending_write_mode_ = GetParam();
189
190 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
191 }
192
193 // The path to temporary directory used to contain the test operations.
194 base::ScopedTempDir temp_dir_;
195
196 base::test::TaskEnvironment task_environment_;
197 CommitPendingWriteMode commit_pending_write_mode_;
198 };
199
200 } // namespace
201
202 // Test fallback behavior for a nonexistent file.
TEST_P(JsonPrefStoreTest,NonExistentFile)203 TEST_P(JsonPrefStoreTest, NonExistentFile) {
204 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
205 ASSERT_FALSE(PathExists(bogus_input_file));
206 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
207 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
208 pref_store->ReadPrefs());
209 EXPECT_FALSE(pref_store->ReadOnly());
210 EXPECT_EQ(0u, pref_store->get_writer().previous_data_size());
211 }
212
213 // Test fallback behavior for an invalid file.
TEST_P(JsonPrefStoreTest,InvalidFile)214 TEST_P(JsonPrefStoreTest, InvalidFile) {
215 base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
216 ASSERT_TRUE(base::WriteFile(invalid_file, kInvalidJson));
217
218 auto pref_store = base::MakeRefCounted<JsonPrefStore>(invalid_file);
219 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
220 pref_store->ReadPrefs());
221 EXPECT_FALSE(pref_store->ReadOnly());
222
223 // The file should have been moved aside.
224 EXPECT_FALSE(PathExists(invalid_file));
225 base::FilePath moved_aside = temp_dir_.GetPath().AppendASCII("invalid.bad");
226 EXPECT_TRUE(PathExists(moved_aside));
227
228 std::string moved_aside_contents;
229 ASSERT_TRUE(base::ReadFileToString(moved_aside, &moved_aside_contents));
230 EXPECT_EQ(kInvalidJson, moved_aside_contents);
231 }
232
233 // This function is used to avoid code duplication while testing synchronous
234 // and asynchronous version of the JsonPrefStore loading. It validates that the
235 // given output file's contents matches kWriteGolden.
RunBasicJsonPrefStoreTest(JsonPrefStore * pref_store,const base::FilePath & output_file,CommitPendingWriteMode commit_pending_write_mode,base::test::TaskEnvironment * task_environment)236 void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
237 const base::FilePath& output_file,
238 CommitPendingWriteMode commit_pending_write_mode,
239 base::test::TaskEnvironment* task_environment) {
240 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
241 const char kMaxTabs[] = "tabs.max_tabs";
242 const char kLongIntPref[] = "long_int.pref";
243
244 std::string cnn("http://www.cnn.com");
245
246 const Value* actual;
247 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
248 EXPECT_TRUE(actual->is_string());
249 EXPECT_EQ(cnn, actual->GetString());
250
251 const char kSomeDirectory[] = "some_directory";
252
253 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
254 EXPECT_TRUE(actual->is_string());
255 EXPECT_EQ("/usr/local/", actual->GetString());
256 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
257
258 pref_store->SetValue(kSomeDirectory, Value(some_path.AsUTF8Unsafe()),
259 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
260 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
261 EXPECT_TRUE(actual->is_string());
262 EXPECT_EQ(some_path.AsUTF8Unsafe(), actual->GetString());
263
264 // Test reading some other data types from sub-dictionaries.
265 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
266 EXPECT_TRUE(actual->is_bool());
267 EXPECT_TRUE(actual->GetBool());
268
269 pref_store->SetValue(kNewWindowsInTabs, Value(false),
270 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
271 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
272 EXPECT_TRUE(actual->is_bool());
273 EXPECT_FALSE(actual->GetBool());
274
275 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
276 ASSERT_TRUE(actual->is_int());
277 EXPECT_EQ(20, actual->GetInt());
278 pref_store->SetValue(kMaxTabs, Value(10),
279 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
280 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
281 ASSERT_TRUE(actual->is_int());
282 EXPECT_EQ(10, actual->GetInt());
283
284 pref_store->SetValue(kLongIntPref,
285 Value(base::NumberToString(214748364842LL)),
286 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
287 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
288 EXPECT_TRUE(actual->is_string());
289 int64_t value;
290 base::StringToInt64(actual->GetString(), &value);
291 EXPECT_EQ(214748364842LL, value);
292
293 // Serialize and compare to expected output.
294 CommitPendingWrite(pref_store, commit_pending_write_mode, task_environment);
295
296 std::string output_contents;
297 ASSERT_TRUE(base::ReadFileToString(output_file, &output_contents));
298 EXPECT_EQ(kWriteGolden, output_contents);
299 ASSERT_TRUE(base::DeleteFile(output_file));
300 }
301
TEST_P(JsonPrefStoreTest,Basic)302 TEST_P(JsonPrefStoreTest, Basic) {
303 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
304 ASSERT_TRUE(base::WriteFile(input_file, kReadJson));
305
306 // Test that the persistent value can be loaded.
307 ASSERT_TRUE(PathExists(input_file));
308 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
309 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
310 EXPECT_FALSE(pref_store->ReadOnly());
311 EXPECT_TRUE(pref_store->IsInitializationComplete());
312 EXPECT_GT(pref_store->get_writer().previous_data_size(), 0u);
313
314 // The JSON file looks like this:
315 // {
316 // "homepage": "http://www.cnn.com",
317 // "some_directory": "/usr/local/",
318 // "tabs": {
319 // "new_windows_in_tabs": true,
320 // "max_tabs": 20
321 // }
322 // }
323
324 RunBasicJsonPrefStoreTest(pref_store.get(), input_file,
325 commit_pending_write_mode_, &task_environment_);
326 }
327
TEST_P(JsonPrefStoreTest,BasicAsync)328 TEST_P(JsonPrefStoreTest, BasicAsync) {
329 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
330 ASSERT_TRUE(base::WriteFile(input_file, kReadJson));
331
332 // Test that the persistent value can be loaded.
333 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
334
335 {
336 MockPrefStoreObserver mock_observer;
337 pref_store->AddObserver(&mock_observer);
338
339 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
340 pref_store->ReadPrefsAsync(mock_error_delegate);
341
342 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
343 EXPECT_CALL(*mock_error_delegate,
344 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
345 task_environment_.RunUntilIdle();
346 pref_store->RemoveObserver(&mock_observer);
347
348 EXPECT_FALSE(pref_store->ReadOnly());
349 EXPECT_TRUE(pref_store->IsInitializationComplete());
350 EXPECT_GT(pref_store->get_writer().previous_data_size(), 0u);
351 }
352
353 // The JSON file looks like this:
354 // {
355 // "homepage": "http://www.cnn.com",
356 // "some_directory": "/usr/local/",
357 // "tabs": {
358 // "new_windows_in_tabs": true,
359 // "max_tabs": 20
360 // }
361 // }
362
363 RunBasicJsonPrefStoreTest(pref_store.get(), input_file,
364 commit_pending_write_mode_, &task_environment_);
365 }
366
TEST_P(JsonPrefStoreTest,PreserveEmptyValues)367 TEST_P(JsonPrefStoreTest, PreserveEmptyValues) {
368 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
369
370 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
371
372 // Set some keys with empty values.
373 pref_store->SetValue("list", base::Value(base::Value::List()),
374 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
375 pref_store->SetValue("dict", base::Value(base::Value::Dict()),
376 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
377
378 // Write to file.
379 CommitPendingWrite(pref_store.get(), commit_pending_write_mode_,
380 &task_environment_);
381
382 // Reload.
383 pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
384 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
385 ASSERT_FALSE(pref_store->ReadOnly());
386
387 // Check values.
388 const Value* result = nullptr;
389 EXPECT_TRUE(pref_store->GetValue("list", &result));
390 EXPECT_EQ(Value::List(), *result);
391 EXPECT_TRUE(pref_store->GetValue("dict", &result));
392 EXPECT_EQ(Value::Dict(), *result);
393 }
394
395 // This test is just documenting some potentially non-obvious behavior. It
396 // shouldn't be taken as normative.
TEST_P(JsonPrefStoreTest,RemoveClearsEmptyParent)397 TEST_P(JsonPrefStoreTest, RemoveClearsEmptyParent) {
398 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
399
400 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
401
402 base::Value::Dict dict;
403 dict.Set("key", "value");
404 pref_store->SetValue("dict", base::Value(std::move(dict)),
405 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
406
407 pref_store->RemoveValue("dict.key",
408 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
409
410 const base::Value* retrieved_dict = nullptr;
411 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
412 EXPECT_FALSE(has_dict);
413 }
414
415 // Tests asynchronous reading of the file when there is no file.
TEST_P(JsonPrefStoreTest,AsyncNonExistingFile)416 TEST_P(JsonPrefStoreTest, AsyncNonExistingFile) {
417 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
418 ASSERT_FALSE(PathExists(bogus_input_file));
419 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
420 MockPrefStoreObserver mock_observer;
421 pref_store->AddObserver(&mock_observer);
422
423 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
424 pref_store->ReadPrefsAsync(mock_error_delegate);
425
426 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
427 EXPECT_CALL(*mock_error_delegate,
428 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
429 task_environment_.RunUntilIdle();
430 pref_store->RemoveObserver(&mock_observer);
431
432 EXPECT_FALSE(pref_store->ReadOnly());
433 }
434
TEST_P(JsonPrefStoreTest,ReadWithInterceptor)435 TEST_P(JsonPrefStoreTest, ReadWithInterceptor) {
436 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
437 ASSERT_TRUE(base::WriteFile(input_file, kReadJson));
438
439 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
440 new InterceptingPrefFilter());
441 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
442 intercepting_pref_filter.get();
443 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
444 input_file, std::move(intercepting_pref_filter));
445
446 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
447 pref_store->ReadPrefs());
448 EXPECT_FALSE(pref_store->ReadOnly());
449
450 // The store shouldn't be considered initialized until the interceptor
451 // returns.
452 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
453 EXPECT_FALSE(pref_store->IsInitializationComplete());
454 EXPECT_FALSE(pref_store->GetValue(kHomePage, nullptr));
455
456 raw_intercepting_pref_filter_->ReleasePrefs();
457
458 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
459 EXPECT_TRUE(pref_store->IsInitializationComplete());
460 EXPECT_TRUE(pref_store->GetValue(kHomePage, nullptr));
461
462 // The JSON file looks like this:
463 // {
464 // "homepage": "http://www.cnn.com",
465 // "some_directory": "/usr/local/",
466 // "tabs": {
467 // "new_windows_in_tabs": true,
468 // "max_tabs": 20
469 // }
470 // }
471
472 RunBasicJsonPrefStoreTest(pref_store.get(), input_file,
473 commit_pending_write_mode_, &task_environment_);
474 }
475
TEST_P(JsonPrefStoreTest,ReadAsyncWithInterceptor)476 TEST_P(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
477 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
478 ASSERT_TRUE(base::WriteFile(input_file, kReadJson));
479
480 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
481 new InterceptingPrefFilter());
482 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
483 intercepting_pref_filter.get();
484 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
485 input_file, std::move(intercepting_pref_filter));
486
487 MockPrefStoreObserver mock_observer;
488 pref_store->AddObserver(&mock_observer);
489
490 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
491 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
492
493 {
494 pref_store->ReadPrefsAsync(mock_error_delegate);
495
496 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
497 // EXPECT_CALL(*mock_error_delegate,
498 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
499 task_environment_.RunUntilIdle();
500
501 EXPECT_FALSE(pref_store->ReadOnly());
502 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
503 EXPECT_FALSE(pref_store->IsInitializationComplete());
504 EXPECT_FALSE(pref_store->GetValue(kHomePage, nullptr));
505 }
506
507 {
508 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
509 // EXPECT_CALL(*mock_error_delegate,
510 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
511
512 raw_intercepting_pref_filter_->ReleasePrefs();
513
514 EXPECT_FALSE(pref_store->ReadOnly());
515 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
516 EXPECT_TRUE(pref_store->IsInitializationComplete());
517 EXPECT_TRUE(pref_store->GetValue(kHomePage, nullptr));
518 }
519
520 pref_store->RemoveObserver(&mock_observer);
521
522 // The JSON file looks like this:
523 // {
524 // "homepage": "http://www.cnn.com",
525 // "some_directory": "/usr/local/",
526 // "tabs": {
527 // "new_windows_in_tabs": true,
528 // "max_tabs": 20
529 // }
530 // }
531
532 RunBasicJsonPrefStoreTest(pref_store.get(), input_file,
533 commit_pending_write_mode_, &task_environment_);
534 }
535
TEST_P(JsonPrefStoreTest,RemoveValuesByPrefix)536 TEST_P(JsonPrefStoreTest, RemoveValuesByPrefix) {
537 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty.json");
538
539 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
540
541 const Value* value;
542 const std::string prefix = "pref";
543 const std::string subpref_name1 = "pref.a";
544 const std::string subpref_name2 = "pref.b";
545 const std::string other_name = "other";
546
547 pref_store->SetValue(subpref_name1, base::Value(42),
548 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
549 pref_store->SetValue(subpref_name2, base::Value(42),
550 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
551 pref_store->SetValue(other_name, base::Value(42),
552 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
553
554 pref_store->RemoveValuesByPrefixSilently(prefix);
555 EXPECT_FALSE(pref_store->GetValue(subpref_name1, &value));
556 EXPECT_FALSE(pref_store->GetValue(subpref_name2, &value));
557 EXPECT_TRUE(pref_store->GetValue(other_name, &value));
558 }
559
TEST_P(JsonPrefStoreTest,HasReadErrorDelegate)560 TEST_P(JsonPrefStoreTest, HasReadErrorDelegate) {
561 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
562 ASSERT_FALSE(PathExists(bogus_input_file));
563 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
564
565 EXPECT_FALSE(pref_store->HasReadErrorDelegate());
566
567 pref_store->ReadPrefsAsync(new MockReadErrorDelegate);
568 EXPECT_TRUE(pref_store->HasReadErrorDelegate());
569 }
570
TEST_P(JsonPrefStoreTest,HasReadErrorDelegateWithNullDelegate)571 TEST_P(JsonPrefStoreTest, HasReadErrorDelegateWithNullDelegate) {
572 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
573 ASSERT_FALSE(PathExists(bogus_input_file));
574 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
575
576 EXPECT_FALSE(pref_store->HasReadErrorDelegate());
577
578 pref_store->ReadPrefsAsync(nullptr);
579 // Returns true even though no instance was passed.
580 EXPECT_TRUE(pref_store->HasReadErrorDelegate());
581 }
582
583 INSTANTIATE_TEST_SUITE_P(
584 JsonPrefStoreTestVariations,
585 JsonPrefStoreTest,
586 ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK,
587 CommitPendingWriteMode::WITH_CALLBACK,
588 CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK));
589
590 class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
591 public:
592 JsonPrefStoreLossyWriteTest() = default;
593
594 JsonPrefStoreLossyWriteTest(const JsonPrefStoreLossyWriteTest&) = delete;
595 JsonPrefStoreLossyWriteTest& operator=(const JsonPrefStoreLossyWriteTest&) =
596 delete;
597
598 protected:
SetUp()599 void SetUp() override {
600 JsonPrefStoreTest::SetUp();
601 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
602 }
603
CreatePrefStore()604 scoped_refptr<JsonPrefStore> CreatePrefStore() {
605 return base::MakeRefCounted<JsonPrefStore>(test_file_);
606 }
607
608 // Return the ImportantFileWriter for a given JsonPrefStore.
GetImportantFileWriter(JsonPrefStore * pref_store)609 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
610 return &(pref_store->writer_);
611 }
612
613 // Get the contents of kTestFile. Pumps the message loop before returning the
614 // result.
GetTestFileContents()615 std::string GetTestFileContents() {
616 task_environment_.RunUntilIdle();
617 std::string file_contents;
618 ReadFileToString(test_file_, &file_contents);
619 return file_contents;
620 }
621
622 private:
623 base::FilePath test_file_;
624 };
625
TEST_P(JsonPrefStoreLossyWriteTest,LossyWriteBasic)626 TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
627 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
628 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
629
630 // Set a normal pref and check that it gets scheduled to be written.
631 ASSERT_FALSE(file_writer->HasPendingWrite());
632 pref_store->SetValue("normal", base::Value("normal"),
633 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
634 ASSERT_TRUE(file_writer->HasPendingWrite());
635 file_writer->DoScheduledWrite();
636 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
637 ASSERT_FALSE(file_writer->HasPendingWrite());
638
639 // Set a lossy pref and check that it is not scheduled to be written.
640 // SetValue/RemoveValue.
641 pref_store->SetValue("lossy", base::Value("lossy"),
642 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
643 ASSERT_FALSE(file_writer->HasPendingWrite());
644 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
645 ASSERT_FALSE(file_writer->HasPendingWrite());
646
647 // SetValueSilently/RemoveValueSilently.
648 pref_store->SetValueSilently("lossy", base::Value("lossy"),
649 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
650 ASSERT_FALSE(file_writer->HasPendingWrite());
651 pref_store->RemoveValueSilently("lossy",
652 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
653 ASSERT_FALSE(file_writer->HasPendingWrite());
654
655 // ReportValueChanged.
656 pref_store->SetValue("lossy", base::Value("lossy"),
657 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
658 ASSERT_FALSE(file_writer->HasPendingWrite());
659 pref_store->ReportValueChanged("lossy",
660 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
661 ASSERT_FALSE(file_writer->HasPendingWrite());
662
663 // Call CommitPendingWrite and check that the lossy pref and the normal pref
664 // are there with the last values set above.
665 pref_store->CommitPendingWrite(base::OnceClosure());
666 ASSERT_FALSE(file_writer->HasPendingWrite());
667 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
668 GetTestFileContents());
669 }
670
TEST_P(JsonPrefStoreLossyWriteTest,LossyWriteMixedLossyFirst)671 TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
672 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
673 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
674
675 // Set a lossy pref and check that it is not scheduled to be written.
676 ASSERT_FALSE(file_writer->HasPendingWrite());
677 pref_store->SetValue("lossy", base::Value("lossy"),
678 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
679 ASSERT_FALSE(file_writer->HasPendingWrite());
680
681 // Set a normal pref and check that it is scheduled to be written.
682 pref_store->SetValue("normal", base::Value("normal"),
683 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
684 ASSERT_TRUE(file_writer->HasPendingWrite());
685
686 // Call DoScheduledWrite and check both prefs get written.
687 file_writer->DoScheduledWrite();
688 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
689 GetTestFileContents());
690 ASSERT_FALSE(file_writer->HasPendingWrite());
691 }
692
TEST_P(JsonPrefStoreLossyWriteTest,LossyWriteMixedLossySecond)693 TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
694 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
695 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
696
697 // Set a normal pref and check that it is scheduled to be written.
698 ASSERT_FALSE(file_writer->HasPendingWrite());
699 pref_store->SetValue("normal", base::Value("normal"),
700 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
701 ASSERT_TRUE(file_writer->HasPendingWrite());
702
703 // Set a lossy pref and check that the write is still scheduled.
704 pref_store->SetValue("lossy", base::Value("lossy"),
705 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
706 ASSERT_TRUE(file_writer->HasPendingWrite());
707
708 // Call DoScheduledWrite and check both prefs get written.
709 file_writer->DoScheduledWrite();
710 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
711 GetTestFileContents());
712 ASSERT_FALSE(file_writer->HasPendingWrite());
713 }
714
TEST_P(JsonPrefStoreLossyWriteTest,ScheduleLossyWrite)715 TEST_P(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
716 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
717 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
718
719 // Set a lossy pref and check that it is not scheduled to be written.
720 pref_store->SetValue("lossy", base::Value("lossy"),
721 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
722 ASSERT_FALSE(file_writer->HasPendingWrite());
723
724 // Schedule pending lossy writes and check that it is scheduled.
725 pref_store->SchedulePendingLossyWrites();
726 ASSERT_TRUE(file_writer->HasPendingWrite());
727
728 // Call CommitPendingWrite and check that the lossy pref is there with the
729 // last value set above.
730 pref_store->CommitPendingWrite(base::OnceClosure());
731 ASSERT_FALSE(file_writer->HasPendingWrite());
732 ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
733 }
734
735 INSTANTIATE_TEST_SUITE_P(
736 JsonPrefStoreLossyWriteTestVariations,
737 JsonPrefStoreLossyWriteTest,
738 ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK,
739 CommitPendingWriteMode::WITH_CALLBACK,
740 CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK));
741
742 class SuccessfulWriteReplyObserver {
743 public:
744 SuccessfulWriteReplyObserver() = default;
745
746 SuccessfulWriteReplyObserver(const SuccessfulWriteReplyObserver&) = delete;
747 SuccessfulWriteReplyObserver& operator=(const SuccessfulWriteReplyObserver&) =
748 delete;
749
750 // Returns true if a successful write was observed via on_successful_write()
751 // and resets the observation state to false regardless.
GetAndResetObservationState()752 bool GetAndResetObservationState() {
753 bool was_successful_write_observed = successful_write_reply_observed_;
754 successful_write_reply_observed_ = false;
755 return was_successful_write_observed;
756 }
757
758 // Register OnWrite() to be called on the next write of |json_pref_store|.
759 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
760
OnSuccessfulWrite()761 void OnSuccessfulWrite() {
762 EXPECT_FALSE(successful_write_reply_observed_);
763 successful_write_reply_observed_ = true;
764 }
765
766 private:
767 bool successful_write_reply_observed_ = false;
768 };
769
ObserveNextWriteCallback(JsonPrefStore * json_pref_store)770 void SuccessfulWriteReplyObserver::ObserveNextWriteCallback(
771 JsonPrefStore* json_pref_store) {
772 json_pref_store->RegisterOnNextSuccessfulWriteReply(
773 base::BindOnce(&SuccessfulWriteReplyObserver::OnSuccessfulWrite,
774 base::Unretained(this)));
775 }
776
777 enum WriteCallbackObservationState {
778 NOT_CALLED,
779 CALLED_WITH_ERROR,
780 CALLED_WITH_SUCCESS,
781 };
782
783 class WriteCallbacksObserver {
784 public:
785 WriteCallbacksObserver() = default;
786
787 WriteCallbacksObserver(const WriteCallbacksObserver&) = delete;
788 WriteCallbacksObserver& operator=(const WriteCallbacksObserver&) = delete;
789
790 // Register OnWrite() to be called on the next write of |json_pref_store|.
791 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
792
793 // Returns whether OnPreWrite() was called, and resets the observation state
794 // to false.
795 bool GetAndResetPreWriteObservationState();
796
797 // Returns the |WriteCallbackObservationState| which was observed, then resets
798 // it to |NOT_CALLED|.
799 WriteCallbackObservationState GetAndResetPostWriteObservationState();
800
GetCallbackPair()801 JsonPrefStore::OnWriteCallbackPair GetCallbackPair() {
802 return std::make_pair(base::BindOnce(&WriteCallbacksObserver::OnPreWrite,
803 base::Unretained(this)),
804 base::BindOnce(&WriteCallbacksObserver::OnPostWrite,
805 base::Unretained(this)));
806 }
807
OnPreWrite()808 void OnPreWrite() {
809 EXPECT_FALSE(pre_write_called_);
810 pre_write_called_ = true;
811 }
812
OnPostWrite(bool success)813 void OnPostWrite(bool success) {
814 EXPECT_EQ(NOT_CALLED, post_write_observation_state_);
815 post_write_observation_state_ =
816 success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
817 }
818
819 private:
820 bool pre_write_called_ = false;
821 WriteCallbackObservationState post_write_observation_state_ = NOT_CALLED;
822 };
823
ObserveNextWriteCallback(JsonPrefStore * writer)824 void WriteCallbacksObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
825 writer->RegisterOnNextWriteSynchronousCallbacks(GetCallbackPair());
826 }
827
GetAndResetPreWriteObservationState()828 bool WriteCallbacksObserver::GetAndResetPreWriteObservationState() {
829 bool observation_state = pre_write_called_;
830 pre_write_called_ = false;
831 return observation_state;
832 }
833
834 WriteCallbackObservationState
GetAndResetPostWriteObservationState()835 WriteCallbacksObserver::GetAndResetPostWriteObservationState() {
836 WriteCallbackObservationState state = post_write_observation_state_;
837 pre_write_called_ = false;
838 post_write_observation_state_ = NOT_CALLED;
839 return state;
840 }
841
842 class JsonPrefStoreCallbackTest : public testing::Test {
843 public:
844 JsonPrefStoreCallbackTest() = default;
845
846 JsonPrefStoreCallbackTest(const JsonPrefStoreCallbackTest&) = delete;
847 JsonPrefStoreCallbackTest& operator=(const JsonPrefStoreCallbackTest&) =
848 delete;
849
850 protected:
SetUp()851 void SetUp() override {
852 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
853 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
854 }
855
CreatePrefStore()856 scoped_refptr<JsonPrefStore> CreatePrefStore() {
857 return base::MakeRefCounted<JsonPrefStore>(test_file_);
858 }
859
860 // Return the ImportantFileWriter for a given JsonPrefStore.
GetImportantFileWriter(JsonPrefStore * pref_store)861 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
862 return &(pref_store->writer_);
863 }
864
TriggerFakeWriteForCallback(JsonPrefStore * pref_store,bool success)865 void TriggerFakeWriteForCallback(JsonPrefStore* pref_store, bool success) {
866 JsonPrefStore::PostWriteCallback(
867 base::BindOnce(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
868 pref_store->AsWeakPtr()),
869 base::BindOnce(&WriteCallbacksObserver::OnPostWrite,
870 base::Unretained(&write_callback_observer_)),
871 base::SequencedTaskRunner::GetCurrentDefault(), success);
872 }
873
874 SuccessfulWriteReplyObserver successful_write_reply_observer_;
875 WriteCallbacksObserver write_callback_observer_;
876
877 protected:
878 base::test::TaskEnvironment task_environment_{
879 base::test::TaskEnvironment::MainThreadType::DEFAULT,
880 base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED};
881
882 base::ScopedTempDir temp_dir_;
883
884 private:
885 base::FilePath test_file_;
886 };
887
TEST_F(JsonPrefStoreCallbackTest,TestSerializeDataCallbacks)888 TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
889 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
890 ASSERT_TRUE(base::WriteFile(input_file, kReadJson));
891
892 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
893 new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
894 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
895 input_file, std::move(intercepting_pref_filter));
896 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
897
898 EXPECT_EQ(NOT_CALLED,
899 write_callback_observer_.GetAndResetPostWriteObservationState());
900 pref_store->SetValue("normal", base::Value("normal"),
901 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
902 file_writer->DoScheduledWrite();
903
904 // The observer should not be invoked right away.
905 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
906 EXPECT_EQ(NOT_CALLED,
907 write_callback_observer_.GetAndResetPostWriteObservationState());
908
909 task_environment_.RunUntilIdle();
910
911 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
912 EXPECT_EQ(CALLED_WITH_SUCCESS,
913 write_callback_observer_.GetAndResetPostWriteObservationState());
914 }
915
TEST_F(JsonPrefStoreCallbackTest,TestPostWriteCallbacks)916 TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacks) {
917 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
918 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
919
920 // Test RegisterOnNextWriteSynchronousCallbacks after
921 // RegisterOnNextSuccessfulWriteReply.
922 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
923 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
924 file_writer->WriteNow("foo");
925 task_environment_.RunUntilIdle();
926 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
927 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
928 EXPECT_EQ(CALLED_WITH_SUCCESS,
929 write_callback_observer_.GetAndResetPostWriteObservationState());
930
931 // Test RegisterOnNextSuccessfulWriteReply after
932 // RegisterOnNextWriteSynchronousCallbacks.
933 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
934 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
935 file_writer->WriteNow("foo");
936 task_environment_.RunUntilIdle();
937 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
938 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
939 EXPECT_EQ(CALLED_WITH_SUCCESS,
940 write_callback_observer_.GetAndResetPostWriteObservationState());
941
942 // Test RegisterOnNextSuccessfulWriteReply only.
943 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
944 file_writer->WriteNow("foo");
945 task_environment_.RunUntilIdle();
946 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
947 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
948 EXPECT_EQ(NOT_CALLED,
949 write_callback_observer_.GetAndResetPostWriteObservationState());
950
951 // Test RegisterOnNextWriteSynchronousCallbacks only.
952 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
953 file_writer->WriteNow("foo");
954 task_environment_.RunUntilIdle();
955 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
956 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
957 EXPECT_EQ(CALLED_WITH_SUCCESS,
958 write_callback_observer_.GetAndResetPostWriteObservationState());
959 }
960
TEST_F(JsonPrefStoreCallbackTest,TestPostWriteCallbacksWithFakeFailure)961 TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksWithFakeFailure) {
962 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
963
964 // Confirm that the observers are invoked.
965 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
966 TriggerFakeWriteForCallback(pref_store.get(), true);
967 task_environment_.RunUntilIdle();
968 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
969 EXPECT_EQ(CALLED_WITH_SUCCESS,
970 write_callback_observer_.GetAndResetPostWriteObservationState());
971
972 // Confirm that the observation states were reset.
973 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
974 EXPECT_EQ(NOT_CALLED,
975 write_callback_observer_.GetAndResetPostWriteObservationState());
976
977 // Confirm that re-installing the observers works for another write.
978 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
979 TriggerFakeWriteForCallback(pref_store.get(), true);
980 task_environment_.RunUntilIdle();
981 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
982 EXPECT_EQ(CALLED_WITH_SUCCESS,
983 write_callback_observer_.GetAndResetPostWriteObservationState());
984
985 // Confirm that the successful observer is not invoked by an unsuccessful
986 // write, and that the synchronous observer is invoked.
987 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
988 TriggerFakeWriteForCallback(pref_store.get(), false);
989 task_environment_.RunUntilIdle();
990 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
991 EXPECT_EQ(CALLED_WITH_ERROR,
992 write_callback_observer_.GetAndResetPostWriteObservationState());
993
994 // Do a real write, and confirm that the successful observer was invoked after
995 // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
996 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
997 file_writer->WriteNow("foo");
998 task_environment_.RunUntilIdle();
999 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1000 EXPECT_EQ(NOT_CALLED,
1001 write_callback_observer_.GetAndResetPostWriteObservationState());
1002 }
1003
TEST_F(JsonPrefStoreCallbackTest,TestPostWriteCallbacksDuringProfileDeath)1004 TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksDuringProfileDeath) {
1005 // Create a JsonPrefStore and attach observers to it, then delete it by making
1006 // it go out of scope to simulate profile switch or Chrome shutdown.
1007 {
1008 scoped_refptr<JsonPrefStore> soon_out_of_scope_pref_store =
1009 CreatePrefStore();
1010 ImportantFileWriter* file_writer =
1011 GetImportantFileWriter(soon_out_of_scope_pref_store.get());
1012 successful_write_reply_observer_.ObserveNextWriteCallback(
1013 soon_out_of_scope_pref_store.get());
1014 write_callback_observer_.ObserveNextWriteCallback(
1015 soon_out_of_scope_pref_store.get());
1016 file_writer->WriteNow("foo");
1017 }
1018 task_environment_.RunUntilIdle();
1019 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1020 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
1021 EXPECT_EQ(CALLED_WITH_SUCCESS,
1022 write_callback_observer_.GetAndResetPostWriteObservationState());
1023 }
1024
1025 } // namespace base
1026