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