• 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 "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