• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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