blob: fcb28f506b3a6c440f7a5c9d4f2ecc984df5a88c [file] [log] [blame]
[email protected]ea3e4972012-04-12 03:41:371// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]277404c22010-04-22 13:09:452// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
brettwf00b9b42016-02-01 22:11:385#include "components/prefs/json_pref_store.h"
[email protected]00c87822012-11-27 19:09:176
avi9ef8bb02015-12-24 05:29:367#include <stdint.h>
8
dcheng5f043bc2016-04-22 19:09:069#include <memory>
danakj0c8d4aa2015-11-25 05:29:5810#include <utility>
11
[email protected]e33c9512014-05-12 02:24:1312#include "base/bind.h"
[email protected]e3177dd52014-08-13 20:22:1413#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2314#include "base/files/scoped_temp_dir.h"
skyostil054861d2015-04-30 19:06:1515#include "base/location.h"
avi9ef8bb02015-12-24 05:29:3616#include "base/macros.h"
dcheng5f043bc2016-04-22 19:09:0617#include "base/memory/ptr_util.h"
[email protected]3b63f8f42011-03-28 01:54:1518#include "base/memory/ref_counted.h"
raymesbfb910a2015-04-29 07:43:0919#include "base/metrics/histogram_samples.h"
[email protected]277404c22010-04-22 13:09:4520#include "base/path_service.h"
[email protected]f7b98b32013-02-05 08:14:1521#include "base/run_loop.h"
skyostil054861d2015-04-30 19:06:1522#include "base/single_thread_task_runner.h"
[email protected]dfa049e2013-02-07 02:57:2223#include "base/strings/string_number_conversions.h"
[email protected]d529cb02013-06-10 19:06:5724#include "base/strings/string_util.h"
[email protected]a4ea1f12013-06-07 18:37:0725#include "base/strings/utf_string_conversions.h"
brettw58cd1f12016-01-30 05:56:0526#include "base/test/histogram_tester.h"
Francois Doray405dd2d2017-06-09 15:23:3327#include "base/test/scoped_task_environment.h"
raymesbfb910a2015-04-29 07:43:0928#include "base/test/simple_test_clock.h"
probergefc46ac12016-09-21 18:03:0029#include "base/threading/sequenced_task_runner_handle.h"
[email protected]0de615a2012-11-08 04:40:5930#include "base/threading/sequenced_worker_pool.h"
[email protected]34b99632011-01-01 01:01:0631#include "base/threading/thread.h"
[email protected]277404c22010-04-22 13:09:4532#include "base/values.h"
Francois Doray405dd2d2017-06-09 15:23:3333#include "components/prefs/persistent_pref_store_unittest.h"
brettwf00b9b42016-02-01 22:11:3834#include "components/prefs/pref_filter.h"
[email protected]845b43a82011-05-11 10:14:4335#include "testing/gmock/include/gmock/gmock.h"
[email protected]277404c22010-04-22 13:09:4536#include "testing/gtest/include/gtest/gtest.h"
37
[email protected]7e3ec42c2012-12-16 05:13:2138namespace base {
[email protected]845b43a82011-05-11 10:14:4339namespace {
40
[email protected]5bfdcfd2012-11-22 22:08:2441const char kHomePage[] = "homepage";
42
brettw58cd1f12016-01-30 05:56:0543const 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
53const char kInvalidJson[] = "!@#$%^&";
54
55// Expected output for tests using RunBasicJsonPrefStoreTest().
56const 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
raymesbfb910a2015-04-29 07:43:0962// Set the time on the given SimpleTestClock to the given time in minutes.
63void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
64 const int32_t kBaseTimeMins = 100;
65 clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
66}
67
[email protected]e33c9512014-05-12 02:24:1368// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
69// to the |prefs| until explicitly asked to release them.
70class InterceptingPrefFilter : public PrefFilter {
71 public:
72 InterceptingPrefFilter();
probergec503d692016-09-28 19:51:0573 InterceptingPrefFilter(OnWriteCallbackPair callback_pair);
dcheng56488182014-10-21 10:54:5174 ~InterceptingPrefFilter() override;
[email protected]e33c9512014-05-12 02:24:1375
76 // PrefFilter implementation:
dcheng56488182014-10-21 10:54:5177 void FilterOnLoad(
[email protected]e33c9512014-05-12 02:24:1378 const PostFilterOnLoadCallback& post_filter_on_load_callback,
dcheng5f043bc2016-04-22 19:09:0679 std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
dcheng56488182014-10-21 10:54:5180 void FilterUpdate(const std::string& path) override {}
probergec503d692016-09-28 19:51:0581 OnWriteCallbackPair FilterSerializeData(
82 base::DictionaryValue* pref_store_contents) override {
83 return on_write_callback_pair_;
84 }
proberge45e347282017-08-16 21:24:0585 void OnStoreDeletionFromDisk() override {}
[email protected]e33c9512014-05-12 02:24:1386
Ivan Kotenkov75b1c3a2017-10-24 14:47:2487 bool has_intercepted_prefs() const { return intercepted_prefs_ != nullptr; }
[email protected]e33c9512014-05-12 02:24:1388
[email protected]cfcf0e52014-06-20 18:29:4789 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
[email protected]e33c9512014-05-12 02:24:1390 // JsonPrefStore.
91 void ReleasePrefs();
92
93 private:
94 PostFilterOnLoadCallback post_filter_on_load_callback_;
dcheng5f043bc2016-04-22 19:09:0695 std::unique_ptr<base::DictionaryValue> intercepted_prefs_;
probergec503d692016-09-28 19:51:0596 OnWriteCallbackPair on_write_callback_pair_;
[email protected]e33c9512014-05-12 02:24:1397
98 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
99};
100
101InterceptingPrefFilter::InterceptingPrefFilter() {}
probergec503d692016-09-28 19:51:05102
103InterceptingPrefFilter::InterceptingPrefFilter(
104 OnWriteCallbackPair callback_pair) {
105 on_write_callback_pair_ = callback_pair;
106}
107
[email protected]e33c9512014-05-12 02:24:13108InterceptingPrefFilter::~InterceptingPrefFilter() {}
109
110void InterceptingPrefFilter::FilterOnLoad(
111 const PostFilterOnLoadCallback& post_filter_on_load_callback,
dcheng5f043bc2016-04-22 19:09:06112 std::unique_ptr<base::DictionaryValue> pref_store_contents) {
[email protected]e33c9512014-05-12 02:24:13113 post_filter_on_load_callback_ = post_filter_on_load_callback;
danakj0c8d4aa2015-11-25 05:29:58114 intercepted_prefs_ = std::move(pref_store_contents);
[email protected]e33c9512014-05-12 02:24:13115}
116
117void InterceptingPrefFilter::ReleasePrefs() {
118 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
danakj0c8d4aa2015-11-25 05:29:58119 post_filter_on_load_callback_.Run(std::move(intercepted_prefs_), false);
[email protected]e33c9512014-05-12 02:24:13120 post_filter_on_load_callback_.Reset();
121}
122
[email protected]845b43a82011-05-11 10:14:43123class MockPrefStoreObserver : public PrefStore::Observer {
124 public:
125 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
126 MOCK_METHOD1(OnInitializationCompleted, void (bool));
127};
128
129class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
130 public:
131 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
132};
133
Francois Doray405dd2d2017-06-09 15:23:33134enum class CommitPendingWriteMode {
135 WITHOUT_CALLBACK,
136 WITH_CALLBACK,
137};
[email protected]845b43a82011-05-11 10:14:43138
Francois Doray405dd2d2017-06-09 15:23:33139void CommitPendingWrite(
140 JsonPrefStore* pref_store,
141 CommitPendingWriteMode commit_pending_write_mode,
142 base::test::ScopedTaskEnvironment* scoped_task_environment) {
143 if (commit_pending_write_mode == CommitPendingWriteMode::WITHOUT_CALLBACK) {
144 pref_store->CommitPendingWrite(OnceClosure());
145 scoped_task_environment->RunUntilIdle();
146 } else {
Francois Doray5f547952017-07-25 21:02:05147 TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment);
Francois Doray405dd2d2017-06-09 15:23:33148 }
149}
150
151class JsonPrefStoreTest
152 : public testing::TestWithParam<CommitPendingWriteMode> {
probergefc46ac12016-09-21 18:03:00153 public:
Francois Doray5f547952017-07-25 21:02:05154 JsonPrefStoreTest()
155 : scoped_task_environment_(
156 base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
157 base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
probergefc46ac12016-09-21 18:03:00158
[email protected]277404c22010-04-22 13:09:45159 protected:
dcheng8aef37612014-12-23 02:56:47160 void SetUp() override {
[email protected]3a305db2011-04-12 13:40:53161 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]277404c22010-04-22 13:09:45162 }
163
Francois Doray405dd2d2017-06-09 15:23:33164 base::test::ScopedTaskEnvironment scoped_task_environment_;
[email protected]e33c9512014-05-12 02:24:13165
[email protected]3a305db2011-04-12 13:40:53166 // The path to temporary directory used to contain the test operations.
[email protected]ea1a3f62012-11-16 20:34:23167 base::ScopedTempDir temp_dir_;
probergefc46ac12016-09-21 18:03:00168
169 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreTest);
[email protected]277404c22010-04-22 13:09:45170};
171
Francois Doray405dd2d2017-06-09 15:23:33172} // namespace
173
[email protected]277404c22010-04-22 13:09:45174// Test fallback behavior for a nonexistent file.
175TEST_F(JsonPrefStoreTest, NonExistentFile) {
vabr8023d872016-09-15 08:12:22176 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07177 ASSERT_FALSE(PathExists(bogus_input_file));
Francois Doray405dd2d2017-06-09 15:23:33178 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
[email protected]f2d1f612010-12-09 15:10:17179 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
[email protected]9a8c4022011-01-25 14:25:33180 pref_store->ReadPrefs());
181 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45182}
183
184// Test fallback behavior for an invalid file.
185TEST_F(JsonPrefStoreTest, InvalidFile) {
vabr8023d872016-09-15 08:12:22186 base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
brettw58cd1f12016-01-30 05:56:05187 ASSERT_LT(0, base::WriteFile(invalid_file,
188 kInvalidJson, arraysize(kInvalidJson) - 1));
189
Francois Doray405dd2d2017-06-09 15:23:33190 auto pref_store = base::MakeRefCounted<JsonPrefStore>(invalid_file);
[email protected]f2d1f612010-12-09 15:10:17191 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
[email protected]9a8c4022011-01-25 14:25:33192 pref_store->ReadPrefs());
193 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45194
195 // The file should have been moved aside.
[email protected]7567484142013-07-11 17:36:07196 EXPECT_FALSE(PathExists(invalid_file));
vabr8023d872016-09-15 08:12:22197 base::FilePath moved_aside = temp_dir_.GetPath().AppendASCII("invalid.bad");
[email protected]7567484142013-07-11 17:36:07198 EXPECT_TRUE(PathExists(moved_aside));
brettw58cd1f12016-01-30 05:56:05199
200 std::string moved_aside_contents;
201 ASSERT_TRUE(base::ReadFileToString(moved_aside, &moved_aside_contents));
202 EXPECT_EQ(kInvalidJson, moved_aside_contents);
[email protected]277404c22010-04-22 13:09:45203}
204
brettw58cd1f12016-01-30 05:56:05205// This function is used to avoid code duplication while testing synchronous
206// and asynchronous version of the JsonPrefStore loading. It validates that the
207// given output file's contents matches kWriteGolden.
Francois Doray405dd2d2017-06-09 15:23:33208void RunBasicJsonPrefStoreTest(
209 JsonPrefStore* pref_store,
210 const base::FilePath& output_file,
211 CommitPendingWriteMode commit_pending_write_mode,
212 base::test::ScopedTaskEnvironment* scoped_task_environment) {
[email protected]57ecc4b2010-08-11 03:02:51213 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
214 const char kMaxTabs[] = "tabs.max_tabs";
215 const char kLongIntPref[] = "long_int.pref";
[email protected]277404c22010-04-22 13:09:45216
[email protected]57ecc4b2010-08-11 03:02:51217 std::string cnn("http://www.cnn.com");
[email protected]277404c22010-04-22 13:09:45218
[email protected]68bf41a2011-03-25 16:38:31219 const Value* actual;
[email protected]5bfdcfd2012-11-22 22:08:24220 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
[email protected]57ecc4b2010-08-11 03:02:51221 std::string string_value;
[email protected]f2d1f612010-12-09 15:10:17222 EXPECT_TRUE(actual->GetAsString(&string_value));
[email protected]277404c22010-04-22 13:09:45223 EXPECT_EQ(cnn, string_value);
224
[email protected]57ecc4b2010-08-11 03:02:51225 const char kSomeDirectory[] = "some_directory";
[email protected]277404c22010-04-22 13:09:45226
[email protected]892f1d62012-11-08 18:24:34227 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]023ad6ab2013-02-17 05:07:23228 base::FilePath::StringType path;
[email protected]f2d1f612010-12-09 15:10:17229 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]023ad6ab2013-02-17 05:07:23230 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
231 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
[email protected]f2d1f612010-12-09 15:10:17232
estade0bd407f2015-06-26 18:16:18233 pref_store->SetValue(kSomeDirectory,
jdoerrie122c4da2017-03-06 11:12:04234 base::MakeUnique<Value>(some_path.value()),
raymes76de1af2015-05-06 03:22:21235 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34236 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]f2d1f612010-12-09 15:10:17237 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]277404c22010-04-22 13:09:45238 EXPECT_EQ(some_path.value(), path);
239
240 // Test reading some other data types from sub-dictionaries.
[email protected]892f1d62012-11-08 18:24:34241 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17242 bool boolean = false;
243 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45244 EXPECT_TRUE(boolean);
245
jdoerrie239723572017-03-02 12:09:19246 pref_store->SetValue(kNewWindowsInTabs, base::MakeUnique<Value>(false),
raymes76de1af2015-05-06 03:22:21247 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34248 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17249 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45250 EXPECT_FALSE(boolean);
251
[email protected]892f1d62012-11-08 18:24:34252 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17253 int integer = 0;
254 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45255 EXPECT_EQ(20, integer);
jdoerrie239723572017-03-02 12:09:19256 pref_store->SetValue(kMaxTabs, base::MakeUnique<Value>(10),
raymes76de1af2015-05-06 03:22:21257 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34258 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17259 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45260 EXPECT_EQ(10, integer);
261
jdoerrie122c4da2017-03-06 11:12:04262 pref_store->SetValue(
263 kLongIntPref,
264 base::MakeUnique<Value>(base::Int64ToString(214748364842LL)),
265 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34266 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
[email protected]f2d1f612010-12-09 15:10:17267 EXPECT_TRUE(actual->GetAsString(&string_value));
avi9ef8bb02015-12-24 05:29:36268 int64_t value;
[email protected]57ecc4b2010-08-11 03:02:51269 base::StringToInt64(string_value, &value);
[email protected]e83326f2010-07-31 17:29:25270 EXPECT_EQ(214748364842LL, value);
[email protected]277404c22010-04-22 13:09:45271
272 // Serialize and compare to expected output.
Francois Doray405dd2d2017-06-09 15:23:33273 CommitPendingWrite(pref_store, commit_pending_write_mode,
274 scoped_task_environment);
brettw58cd1f12016-01-30 05:56:05275
276 std::string output_contents;
277 ASSERT_TRUE(base::ReadFileToString(output_file, &output_contents));
278 EXPECT_EQ(kWriteGolden, output_contents);
[email protected]dd3aa792013-07-16 19:10:23279 ASSERT_TRUE(base::DeleteFile(output_file, false));
[email protected]277404c22010-04-22 13:09:45280}
[email protected]845b43a82011-05-11 10:14:43281
Francois Doray405dd2d2017-06-09 15:23:33282TEST_P(JsonPrefStoreTest, Basic) {
vabr8023d872016-09-15 08:12:22283 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05284 ASSERT_LT(0, base::WriteFile(input_file,
285 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43286
287 // Test that the persistent value can be loaded.
[email protected]7567484142013-07-11 17:36:07288 ASSERT_TRUE(PathExists(input_file));
Francois Doray405dd2d2017-06-09 15:23:33289 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
[email protected]845b43a82011-05-11 10:14:43290 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
[email protected]e33c9512014-05-12 02:24:13291 EXPECT_FALSE(pref_store->ReadOnly());
292 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]845b43a82011-05-11 10:14:43293
294 // The JSON file looks like this:
295 // {
296 // "homepage": "http://www.cnn.com",
297 // "some_directory": "/usr/local/",
298 // "tabs": {
299 // "new_windows_in_tabs": true,
300 // "max_tabs": 20
301 // }
302 // }
303
Francois Doray405dd2d2017-06-09 15:23:33304 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
305 &scoped_task_environment_);
[email protected]845b43a82011-05-11 10:14:43306}
307
Francois Doray405dd2d2017-06-09 15:23:33308TEST_P(JsonPrefStoreTest, BasicAsync) {
vabr8023d872016-09-15 08:12:22309 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05310 ASSERT_LT(0, base::WriteFile(input_file,
311 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43312
313 // Test that the persistent value can be loaded.
Francois Doray405dd2d2017-06-09 15:23:33314 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
[email protected]845b43a82011-05-11 10:14:43315
[email protected]0de615a2012-11-08 04:40:59316 {
317 MockPrefStoreObserver mock_observer;
318 pref_store->AddObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43319
[email protected]0de615a2012-11-08 04:40:59320 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
321 pref_store->ReadPrefsAsync(mock_error_delegate);
[email protected]845b43a82011-05-11 10:14:43322
[email protected]0de615a2012-11-08 04:40:59323 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
324 EXPECT_CALL(*mock_error_delegate,
325 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
Francois Doray405dd2d2017-06-09 15:23:33326 scoped_task_environment_.RunUntilIdle();
[email protected]0de615a2012-11-08 04:40:59327 pref_store->RemoveObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43328
[email protected]e33c9512014-05-12 02:24:13329 EXPECT_FALSE(pref_store->ReadOnly());
330 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]0de615a2012-11-08 04:40:59331 }
[email protected]845b43a82011-05-11 10:14:43332
333 // The JSON file looks like this:
334 // {
335 // "homepage": "http://www.cnn.com",
336 // "some_directory": "/usr/local/",
337 // "tabs": {
338 // "new_windows_in_tabs": true,
339 // "max_tabs": 20
340 // }
341 // }
342
Francois Doray405dd2d2017-06-09 15:23:33343 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
344 &scoped_task_environment_);
[email protected]845b43a82011-05-11 10:14:43345}
346
Francois Doray405dd2d2017-06-09 15:23:33347TEST_P(JsonPrefStoreTest, PreserveEmptyValues) {
vabr8023d872016-09-15 08:12:22348 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]aa3283392013-11-27 01:38:24349
Francois Doray405dd2d2017-06-09 15:23:33350 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]aa3283392013-11-27 01:38:24351
352 // Set some keys with empty values.
jdoerrie3a7275f82017-05-31 05:58:33353 pref_store->SetValue("list", base::MakeUnique<base::ListValue>(),
raymes76de1af2015-05-06 03:22:21354 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
jdoerrie3a7275f82017-05-31 05:58:33355 pref_store->SetValue("dict", base::MakeUnique<base::DictionaryValue>(),
raymes76de1af2015-05-06 03:22:21356 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]aa3283392013-11-27 01:38:24357
358 // Write to file.
Francois Doray405dd2d2017-06-09 15:23:33359 CommitPendingWrite(pref_store.get(), GetParam(), &scoped_task_environment_);
[email protected]aa3283392013-11-27 01:38:24360
361 // Reload.
Francois Doray405dd2d2017-06-09 15:23:33362 pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]aa3283392013-11-27 01:38:24363 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
364 ASSERT_FALSE(pref_store->ReadOnly());
365
366 // Check values.
Ivan Kotenkov75b1c3a2017-10-24 14:47:24367 const Value* result = nullptr;
[email protected]aa3283392013-11-27 01:38:24368 EXPECT_TRUE(pref_store->GetValue("list", &result));
369 EXPECT_TRUE(ListValue().Equals(result));
370 EXPECT_TRUE(pref_store->GetValue("dict", &result));
371 EXPECT_TRUE(DictionaryValue().Equals(result));
372}
373
[email protected]eeedaa692014-01-30 09:22:27374// This test is just documenting some potentially non-obvious behavior. It
375// shouldn't be taken as normative.
376TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
vabr8023d872016-09-15 08:12:22377 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]eeedaa692014-01-30 09:22:27378
Francois Doray405dd2d2017-06-09 15:23:33379 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]eeedaa692014-01-30 09:22:27380
dcheng5f043bc2016-04-22 19:09:06381 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]eeedaa692014-01-30 09:22:27382 dict->SetString("key", "value");
danakj0c8d4aa2015-11-25 05:29:58383 pref_store->SetValue("dict", std::move(dict),
raymes76de1af2015-05-06 03:22:21384 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27385
raymes76de1af2015-05-06 03:22:21386 pref_store->RemoveValue("dict.key",
387 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27388
Ivan Kotenkov75b1c3a2017-10-24 14:47:24389 const base::Value* retrieved_dict = nullptr;
[email protected]eeedaa692014-01-30 09:22:27390 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
391 EXPECT_FALSE(has_dict);
392}
393
[email protected]845b43a82011-05-11 10:14:43394// Tests asynchronous reading of the file when there is no file.
395TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
vabr8023d872016-09-15 08:12:22396 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07397 ASSERT_FALSE(PathExists(bogus_input_file));
Francois Doray405dd2d2017-06-09 15:23:33398 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
[email protected]845b43a82011-05-11 10:14:43399 MockPrefStoreObserver mock_observer;
400 pref_store->AddObserver(&mock_observer);
401
402 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
403 pref_store->ReadPrefsAsync(mock_error_delegate);
404
405 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
406 EXPECT_CALL(*mock_error_delegate,
407 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
Francois Doray405dd2d2017-06-09 15:23:33408 scoped_task_environment_.RunUntilIdle();
[email protected]845b43a82011-05-11 10:14:43409 pref_store->RemoveObserver(&mock_observer);
410
411 EXPECT_FALSE(pref_store->ReadOnly());
412}
[email protected]ea3e4972012-04-12 03:41:37413
Francois Doray405dd2d2017-06-09 15:23:33414TEST_P(JsonPrefStoreTest, ReadWithInterceptor) {
vabr8023d872016-09-15 08:12:22415 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05416 ASSERT_LT(0, base::WriteFile(input_file,
417 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13418
dcheng5f043bc2016-04-22 19:09:06419 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13420 new InterceptingPrefFilter());
421 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
422 intercepting_pref_filter.get();
Francois Doray405dd2d2017-06-09 15:23:33423 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
424 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
425 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13426
427 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
428 pref_store->ReadPrefs());
429 EXPECT_FALSE(pref_store->ReadOnly());
430
431 // The store shouldn't be considered initialized until the interceptor
432 // returns.
433 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
434 EXPECT_FALSE(pref_store->IsInitializationComplete());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24435 EXPECT_FALSE(pref_store->GetValue(kHomePage, nullptr));
[email protected]e33c9512014-05-12 02:24:13436
437 raw_intercepting_pref_filter_->ReleasePrefs();
438
439 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
440 EXPECT_TRUE(pref_store->IsInitializationComplete());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24441 EXPECT_TRUE(pref_store->GetValue(kHomePage, nullptr));
[email protected]e33c9512014-05-12 02:24:13442
443 // The JSON file looks like this:
444 // {
445 // "homepage": "http://www.cnn.com",
446 // "some_directory": "/usr/local/",
447 // "tabs": {
448 // "new_windows_in_tabs": true,
449 // "max_tabs": 20
450 // }
451 // }
452
Francois Doray405dd2d2017-06-09 15:23:33453 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
454 &scoped_task_environment_);
[email protected]e33c9512014-05-12 02:24:13455}
456
Francois Doray405dd2d2017-06-09 15:23:33457TEST_P(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
vabr8023d872016-09-15 08:12:22458 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05459 ASSERT_LT(0, base::WriteFile(input_file,
460 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13461
dcheng5f043bc2016-04-22 19:09:06462 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13463 new InterceptingPrefFilter());
464 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
465 intercepting_pref_filter.get();
Francois Doray405dd2d2017-06-09 15:23:33466 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
467 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
468 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13469
470 MockPrefStoreObserver mock_observer;
471 pref_store->AddObserver(&mock_observer);
472
473 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
474 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
475
476 {
477 pref_store->ReadPrefsAsync(mock_error_delegate);
478
479 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
480 // EXPECT_CALL(*mock_error_delegate,
481 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
Francois Doray405dd2d2017-06-09 15:23:33482 scoped_task_environment_.RunUntilIdle();
[email protected]e33c9512014-05-12 02:24:13483
484 EXPECT_FALSE(pref_store->ReadOnly());
485 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
486 EXPECT_FALSE(pref_store->IsInitializationComplete());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24487 EXPECT_FALSE(pref_store->GetValue(kHomePage, nullptr));
[email protected]e33c9512014-05-12 02:24:13488 }
489
490 {
491 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
492 // EXPECT_CALL(*mock_error_delegate,
493 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
494
495 raw_intercepting_pref_filter_->ReleasePrefs();
496
497 EXPECT_FALSE(pref_store->ReadOnly());
498 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
499 EXPECT_TRUE(pref_store->IsInitializationComplete());
Ivan Kotenkov75b1c3a2017-10-24 14:47:24500 EXPECT_TRUE(pref_store->GetValue(kHomePage, nullptr));
[email protected]e33c9512014-05-12 02:24:13501 }
502
503 pref_store->RemoveObserver(&mock_observer);
504
505 // The JSON file looks like this:
506 // {
507 // "homepage": "http://www.cnn.com",
508 // "some_directory": "/usr/local/",
509 // "tabs": {
510 // "new_windows_in_tabs": true,
511 // "max_tabs": 20
512 // }
513 // }
514
Francois Doray405dd2d2017-06-09 15:23:33515 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
516 &scoped_task_environment_);
[email protected]e33c9512014-05-12 02:24:13517}
518
raymesbfb910a2015-04-29 07:43:09519TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
brettw58cd1f12016-01-30 05:56:05520 base::HistogramTester histogram_tester;
521
raymesbfb910a2015-04-29 07:43:09522 SimpleTestClock* test_clock = new SimpleTestClock;
523 SetCurrentTimeInMinutes(0, test_clock);
524 JsonPrefStore::WriteCountHistogram histogram(
525 base::TimeDelta::FromSeconds(10),
526 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06527 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36528 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09529 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
530
531 histogram.RecordWriteOccured();
532
533 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
534 histogram.ReportOutstandingWrites();
dcheng5f043bc2016-04-22 19:09:06535 std::unique_ptr<HistogramSamples> samples =
raymesbfb910a2015-04-29 07:43:09536 histogram.GetHistogram()->SnapshotSamples();
brettw58cd1f12016-01-30 05:56:05537
538 std::string histogram_name = histogram.GetHistogram()->histogram_name();
539 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
540 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09541
542 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
Brian Whited1c91082017-11-03 14:46:42543 std::string(histogram.GetHistogram()->histogram_name()));
raymesbfb910a2015-04-29 07:43:09544 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
545}
546
547TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
brettw58cd1f12016-01-30 05:56:05548 base::HistogramTester histogram_tester;
549
raymesbfb910a2015-04-29 07:43:09550 SimpleTestClock* test_clock = new SimpleTestClock;
551 SetCurrentTimeInMinutes(0, test_clock);
552 JsonPrefStore::WriteCountHistogram histogram(
553 base::TimeDelta::FromSeconds(10),
554 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06555 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36556 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09557 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
558
559 histogram.RecordWriteOccured();
560 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
561 histogram.RecordWriteOccured();
562 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
563 histogram.RecordWriteOccured();
564
565 // Nothing should be recorded until the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05566 std::string histogram_name = histogram.GetHistogram()->histogram_name();
567 histogram_tester.ExpectTotalCount(histogram_name, 0);
raymesbfb910a2015-04-29 07:43:09568
569 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
570 histogram.RecordWriteOccured();
571
572 // Now the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05573 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
574 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09575
576 // The last write won't be recorded because the second count period hasn't
577 // fully elapsed.
578 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
579 histogram.ReportOutstandingWrites();
580
brettw58cd1f12016-01-30 05:56:05581 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
582 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09583}
584
585TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
brettw58cd1f12016-01-30 05:56:05586 base::HistogramTester histogram_tester;
587
raymesbfb910a2015-04-29 07:43:09588 SimpleTestClock* test_clock = new SimpleTestClock;
589 SetCurrentTimeInMinutes(0, test_clock);
590 JsonPrefStore::WriteCountHistogram histogram(
591 base::TimeDelta::FromSeconds(10),
592 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06593 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36594 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09595 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
596
597 histogram.RecordWriteOccured();
598 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
599 histogram.RecordWriteOccured();
600 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
601 histogram.RecordWriteOccured();
602 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
603 histogram.RecordWriteOccured();
604 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
605 histogram.RecordWriteOccured();
606 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
607 histogram.RecordWriteOccured();
608 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
609 histogram.RecordWriteOccured();
610 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
611 histogram.RecordWriteOccured();
612 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
613 histogram.RecordWriteOccured();
614
615 // The last write won't be recorded because the second count period hasn't
616 // fully elapsed
617 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
618 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05619 std::string histogram_name = histogram.GetHistogram()->histogram_name();
620 histogram_tester.ExpectBucketCount(histogram_name, 3, 2);
621 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
622 histogram_tester.ExpectTotalCount(histogram_name, 3);
raymesbfb910a2015-04-29 07:43:09623}
624
625TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
brettw58cd1f12016-01-30 05:56:05626 base::HistogramTester histogram_tester;
627
raymesbfb910a2015-04-29 07:43:09628 SimpleTestClock* test_clock = new SimpleTestClock;
629 SetCurrentTimeInMinutes(0, test_clock);
630 JsonPrefStore::WriteCountHistogram histogram(
631 base::TimeDelta::FromSeconds(10),
632 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06633 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36634 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09635 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
636
637 // 1 write in the first period.
638 histogram.RecordWriteOccured();
639
640 // No writes in the second and third periods.
641
642 // 2 writes in the fourth period.
643 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
644 histogram.RecordWriteOccured();
645 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
646 histogram.RecordWriteOccured();
647
648 // No writes in the fifth period.
649
650 // 3 writes in the sixth period.
651 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
652 histogram.RecordWriteOccured();
653 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
654 histogram.RecordWriteOccured();
655 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
656 histogram.RecordWriteOccured();
657
658 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
659 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05660 std::string histogram_name = histogram.GetHistogram()->histogram_name();
661 histogram_tester.ExpectBucketCount(histogram_name, 0, 3);
662 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
663 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
664 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
665 histogram_tester.ExpectTotalCount(histogram_name, 6);
raymesbfb910a2015-04-29 07:43:09666}
667
Francois Doray405dd2d2017-06-09 15:23:33668INSTANTIATE_TEST_CASE_P(
669 WithoutCallback,
670 JsonPrefStoreTest,
671 ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK));
672INSTANTIATE_TEST_CASE_P(
673 WithCallback,
674 JsonPrefStoreTest,
675 ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
676
raymes4b6e14e2015-05-12 00:10:30677class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
probergefc46ac12016-09-21 18:03:00678 public:
679 JsonPrefStoreLossyWriteTest() = default;
680
raymes4b6e14e2015-05-12 00:10:30681 protected:
682 void SetUp() override {
683 JsonPrefStoreTest::SetUp();
vabr8023d872016-09-15 08:12:22684 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
raymes4b6e14e2015-05-12 00:10:30685 }
686
raymes4b6e14e2015-05-12 00:10:30687 scoped_refptr<JsonPrefStore> CreatePrefStore() {
Francois Doray405dd2d2017-06-09 15:23:33688 return base::MakeRefCounted<JsonPrefStore>(test_file_);
raymes4b6e14e2015-05-12 00:10:30689 }
690
691 // Return the ImportantFileWriter for a given JsonPrefStore.
probergefc46ac12016-09-21 18:03:00692 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
raymes4b6e14e2015-05-12 00:10:30693 return &(pref_store->writer_);
694 }
695
696 // Get the contents of kTestFile. Pumps the message loop before returning the
697 // result.
698 std::string GetTestFileContents() {
Francois Doray405dd2d2017-06-09 15:23:33699 scoped_task_environment_.RunUntilIdle();
raymes4b6e14e2015-05-12 00:10:30700 std::string file_contents;
701 ReadFileToString(test_file_, &file_contents);
702 return file_contents;
703 }
704
705 private:
706 base::FilePath test_file_;
probergefc46ac12016-09-21 18:03:00707
708 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreLossyWriteTest);
raymes4b6e14e2015-05-12 00:10:30709};
710
711TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
712 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00713 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30714
715 // Set a normal pref and check that it gets scheduled to be written.
716 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04717 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30718 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
719 ASSERT_TRUE(file_writer->HasPendingWrite());
720 file_writer->DoScheduledWrite();
721 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
722 ASSERT_FALSE(file_writer->HasPendingWrite());
723
724 // Set a lossy pref and check that it is not scheduled to be written.
725 // SetValue/RemoveValue.
jdoerrie122c4da2017-03-06 11:12:04726 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30727 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
728 ASSERT_FALSE(file_writer->HasPendingWrite());
729 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
730 ASSERT_FALSE(file_writer->HasPendingWrite());
731
732 // SetValueSilently/RemoveValueSilently.
jdoerrie122c4da2017-03-06 11:12:04733 pref_store->SetValueSilently("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30734 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
735 ASSERT_FALSE(file_writer->HasPendingWrite());
736 pref_store->RemoveValueSilently("lossy",
737 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
738 ASSERT_FALSE(file_writer->HasPendingWrite());
739
740 // ReportValueChanged.
jdoerrie122c4da2017-03-06 11:12:04741 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30742 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
743 ASSERT_FALSE(file_writer->HasPendingWrite());
744 pref_store->ReportValueChanged("lossy",
745 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
746 ASSERT_FALSE(file_writer->HasPendingWrite());
747
748 // Call CommitPendingWrite and check that the lossy pref and the normal pref
749 // are there with the last values set above.
Francois Doray405dd2d2017-06-09 15:23:33750 pref_store->CommitPendingWrite(base::OnceClosure());
raymes4b6e14e2015-05-12 00:10:30751 ASSERT_FALSE(file_writer->HasPendingWrite());
752 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
753 GetTestFileContents());
754}
755
756TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
757 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00758 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30759
760 // Set a lossy pref and check that it is not scheduled to be written.
761 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04762 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30763 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
764 ASSERT_FALSE(file_writer->HasPendingWrite());
765
766 // Set a normal pref and check that it is scheduled to be written.
jdoerrie122c4da2017-03-06 11:12:04767 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30768 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
769 ASSERT_TRUE(file_writer->HasPendingWrite());
770
771 // Call DoScheduledWrite and check both prefs get written.
772 file_writer->DoScheduledWrite();
773 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
774 GetTestFileContents());
775 ASSERT_FALSE(file_writer->HasPendingWrite());
776}
777
778TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
779 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00780 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30781
782 // Set a normal pref and check that it is scheduled to be written.
783 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04784 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30785 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
786 ASSERT_TRUE(file_writer->HasPendingWrite());
787
788 // Set a lossy pref and check that the write is still scheduled.
jdoerrie122c4da2017-03-06 11:12:04789 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30790 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
791 ASSERT_TRUE(file_writer->HasPendingWrite());
792
793 // Call DoScheduledWrite and check both prefs get written.
794 file_writer->DoScheduledWrite();
795 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
796 GetTestFileContents());
797 ASSERT_FALSE(file_writer->HasPendingWrite());
798}
799
benwells26730592015-05-28 13:08:08800TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
801 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00802 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
benwells26730592015-05-28 13:08:08803
804 // Set a lossy pref and check that it is not scheduled to be written.
jdoerrie122c4da2017-03-06 11:12:04805 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
benwells26730592015-05-28 13:08:08806 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
807 ASSERT_FALSE(file_writer->HasPendingWrite());
808
809 // Schedule pending lossy writes and check that it is scheduled.
810 pref_store->SchedulePendingLossyWrites();
811 ASSERT_TRUE(file_writer->HasPendingWrite());
812
813 // Call CommitPendingWrite and check that the lossy pref is there with the
814 // last value set above.
Francois Doray405dd2d2017-06-09 15:23:33815 pref_store->CommitPendingWrite(base::OnceClosure());
benwells26730592015-05-28 13:08:08816 ASSERT_FALSE(file_writer->HasPendingWrite());
817 ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
818}
819
probergefc46ac12016-09-21 18:03:00820class SuccessfulWriteReplyObserver {
821 public:
822 SuccessfulWriteReplyObserver() = default;
823
824 // Returns true if a successful write was observed via on_successful_write()
825 // and resets the observation state to false regardless.
826 bool GetAndResetObservationState() {
827 bool was_successful_write_observed = successful_write_reply_observed_;
828 successful_write_reply_observed_ = false;
829 return was_successful_write_observed;
830 }
831
832 // Register OnWrite() to be called on the next write of |json_pref_store|.
833 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
834
835 void OnSuccessfulWrite() {
836 EXPECT_FALSE(successful_write_reply_observed_);
837 successful_write_reply_observed_ = true;
838 }
839
840 private:
841 bool successful_write_reply_observed_ = false;
842
843 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteReplyObserver);
844};
845
846void SuccessfulWriteReplyObserver::ObserveNextWriteCallback(
847 JsonPrefStore* json_pref_store) {
848 json_pref_store->RegisterOnNextSuccessfulWriteReply(
849 base::Bind(&SuccessfulWriteReplyObserver::OnSuccessfulWrite,
850 base::Unretained(this)));
851}
852
853enum WriteCallbackObservationState {
854 NOT_CALLED,
855 CALLED_WITH_ERROR,
856 CALLED_WITH_SUCCESS,
857};
858
probergec503d692016-09-28 19:51:05859class WriteCallbacksObserver {
probergefc46ac12016-09-21 18:03:00860 public:
probergec503d692016-09-28 19:51:05861 WriteCallbacksObserver() = default;
probergefc46ac12016-09-21 18:03:00862
863 // Register OnWrite() to be called on the next write of |json_pref_store|.
864 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
865
probergec503d692016-09-28 19:51:05866 // Returns whether OnPreWrite() was called, and resets the observation state
867 // to false.
868 bool GetAndResetPreWriteObservationState();
probergefc46ac12016-09-21 18:03:00869
probergec503d692016-09-28 19:51:05870 // Returns the |WriteCallbackObservationState| which was observed, then resets
871 // it to |NOT_CALLED|.
872 WriteCallbackObservationState GetAndResetPostWriteObservationState();
873
874 JsonPrefStore::OnWriteCallbackPair GetCallbackPair() {
875 return std::make_pair(
876 base::Bind(&WriteCallbacksObserver::OnPreWrite, base::Unretained(this)),
877 base::Bind(&WriteCallbacksObserver::OnPostWrite,
878 base::Unretained(this)));
879 }
880
881 void OnPreWrite() {
882 EXPECT_FALSE(pre_write_called_);
883 pre_write_called_ = true;
884 }
885
886 void OnPostWrite(bool success) {
887 EXPECT_EQ(NOT_CALLED, post_write_observation_state_);
888 post_write_observation_state_ =
889 success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
probergefc46ac12016-09-21 18:03:00890 }
891
892 private:
probergec503d692016-09-28 19:51:05893 bool pre_write_called_ = false;
894 WriteCallbackObservationState post_write_observation_state_ = NOT_CALLED;
probergefc46ac12016-09-21 18:03:00895
probergec503d692016-09-28 19:51:05896 DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
probergefc46ac12016-09-21 18:03:00897};
898
probergec503d692016-09-28 19:51:05899void WriteCallbacksObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
900 writer->RegisterOnNextWriteSynchronousCallbacks(GetCallbackPair());
901}
902
903bool WriteCallbacksObserver::GetAndResetPreWriteObservationState() {
904 bool observation_state = pre_write_called_;
905 pre_write_called_ = false;
906 return observation_state;
probergefc46ac12016-09-21 18:03:00907}
908
909WriteCallbackObservationState
probergec503d692016-09-28 19:51:05910WriteCallbacksObserver::GetAndResetPostWriteObservationState() {
911 WriteCallbackObservationState state = post_write_observation_state_;
912 pre_write_called_ = false;
913 post_write_observation_state_ = NOT_CALLED;
probergefc46ac12016-09-21 18:03:00914 return state;
915}
916
917class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
918 public:
919 JsonPrefStoreCallbackTest() = default;
920
921 protected:
922 void SetUp() override {
923 JsonPrefStoreTest::SetUp();
vabr5d919d62016-09-30 08:55:36924 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
probergefc46ac12016-09-21 18:03:00925 }
926
927 scoped_refptr<JsonPrefStore> CreatePrefStore() {
Francois Doray405dd2d2017-06-09 15:23:33928 return base::MakeRefCounted<JsonPrefStore>(test_file_);
probergefc46ac12016-09-21 18:03:00929 }
930
931 // Return the ImportantFileWriter for a given JsonPrefStore.
932 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
933 return &(pref_store->writer_);
934 }
935
936 void TriggerFakeWriteForCallback(JsonPrefStore* pref_store, bool success) {
937 JsonPrefStore::PostWriteCallback(
938 base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
939 pref_store->AsWeakPtr()),
probergec503d692016-09-28 19:51:05940 base::Bind(&WriteCallbacksObserver::OnPostWrite,
probergefc46ac12016-09-21 18:03:00941 base::Unretained(&write_callback_observer_)),
942 base::SequencedTaskRunnerHandle::Get(), success);
943 }
944
945 SuccessfulWriteReplyObserver successful_write_reply_observer_;
probergec503d692016-09-28 19:51:05946 WriteCallbacksObserver write_callback_observer_;
probergefc46ac12016-09-21 18:03:00947
948 private:
949 base::FilePath test_file_;
950
951 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
952};
953
Francois Doray5f547952017-07-25 21:02:05954TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
probergec503d692016-09-28 19:51:05955 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
956 ASSERT_LT(0,
957 base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
958
959 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
960 new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
Francois Doray405dd2d2017-06-09 15:23:33961 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
962 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
963 std::move(intercepting_pref_filter));
probergec503d692016-09-28 19:51:05964 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
965
966 EXPECT_EQ(NOT_CALLED,
967 write_callback_observer_.GetAndResetPostWriteObservationState());
jdoerrie122c4da2017-03-06 11:12:04968 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
probergec503d692016-09-28 19:51:05969 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
970 file_writer->DoScheduledWrite();
971
972 // The observer should not be invoked right away.
973 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
974 EXPECT_EQ(NOT_CALLED,
975 write_callback_observer_.GetAndResetPostWriteObservationState());
976
Francois Doray405dd2d2017-06-09 15:23:33977 scoped_task_environment_.RunUntilIdle();
probergec503d692016-09-28 19:51:05978
979 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
980 EXPECT_EQ(CALLED_WITH_SUCCESS,
981 write_callback_observer_.GetAndResetPostWriteObservationState());
982}
983
984TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacks) {
probergefc46ac12016-09-21 18:03:00985 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
986 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
987
probergec503d692016-09-28 19:51:05988 // Test RegisterOnNextWriteSynchronousCallbacks after
probergefc46ac12016-09-21 18:03:00989 // RegisterOnNextSuccessfulWriteReply.
990 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
991 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
992 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:33993 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:00994 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:05995 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
996 EXPECT_EQ(CALLED_WITH_SUCCESS,
997 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:00998
999 // Test RegisterOnNextSuccessfulWriteReply after
probergec503d692016-09-28 19:51:051000 // RegisterOnNextWriteSynchronousCallbacks.
probergefc46ac12016-09-21 18:03:001001 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1002 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1003 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331004 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001005 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051006 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
1007 EXPECT_EQ(CALLED_WITH_SUCCESS,
1008 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001009
1010 // Test RegisterOnNextSuccessfulWriteReply only.
1011 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1012 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331013 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001014 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051015 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
1016 EXPECT_EQ(NOT_CALLED,
1017 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001018
probergec503d692016-09-28 19:51:051019 // Test RegisterOnNextWriteSynchronousCallbacks only.
probergefc46ac12016-09-21 18:03:001020 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1021 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331022 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001023 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051024 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
1025 EXPECT_EQ(CALLED_WITH_SUCCESS,
1026 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001027}
1028
probergec503d692016-09-28 19:51:051029TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksWithFakeFailure) {
probergefc46ac12016-09-21 18:03:001030 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
1031
1032 // Confirm that the observers are invoked.
1033 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1034 TriggerFakeWriteForCallback(pref_store.get(), true);
Francois Doray405dd2d2017-06-09 15:23:331035 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001036 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1037 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051038 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001039
1040 // Confirm that the observation states were reset.
1041 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051042 EXPECT_EQ(NOT_CALLED,
1043 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001044
1045 // Confirm that re-installing the observers works for another write.
1046 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1047 TriggerFakeWriteForCallback(pref_store.get(), true);
Francois Doray405dd2d2017-06-09 15:23:331048 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001049 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1050 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051051 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001052
1053 // Confirm that the successful observer is not invoked by an unsuccessful
1054 // write, and that the synchronous observer is invoked.
1055 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1056 TriggerFakeWriteForCallback(pref_store.get(), false);
Francois Doray405dd2d2017-06-09 15:23:331057 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001058 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1059 EXPECT_EQ(CALLED_WITH_ERROR,
probergec503d692016-09-28 19:51:051060 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001061
1062 // Do a real write, and confirm that the successful observer was invoked after
1063 // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
1064 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
1065 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331066 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001067 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051068 EXPECT_EQ(NOT_CALLED,
1069 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001070}
1071
probergec503d692016-09-28 19:51:051072TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksDuringProfileDeath) {
probergefc46ac12016-09-21 18:03:001073 // Create a JsonPrefStore and attach observers to it, then delete it by making
1074 // it go out of scope to simulate profile switch or Chrome shutdown.
1075 {
1076 scoped_refptr<JsonPrefStore> soon_out_of_scope_pref_store =
1077 CreatePrefStore();
1078 ImportantFileWriter* file_writer =
1079 GetImportantFileWriter(soon_out_of_scope_pref_store.get());
1080 successful_write_reply_observer_.ObserveNextWriteCallback(
1081 soon_out_of_scope_pref_store.get());
1082 write_callback_observer_.ObserveNextWriteCallback(
1083 soon_out_of_scope_pref_store.get());
1084 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1085 }
Francois Doray405dd2d2017-06-09 15:23:331086 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001087 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051088 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
probergefc46ac12016-09-21 18:03:001089 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051090 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001091}
1092
vabr5d919d62016-09-30 08:55:361093} // namespace base