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