blob: e9f2c9f37868f7c6fb4a663182dd348e062e2e55 [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 }
[email protected]e33c9512014-05-12 02:24:1385
86 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
87
[email protected]cfcf0e52014-06-20 18:29:4788 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
[email protected]e33c9512014-05-12 02:24:1389 // JsonPrefStore.
90 void ReleasePrefs();
91
92 private:
93 PostFilterOnLoadCallback post_filter_on_load_callback_;
dcheng5f043bc2016-04-22 19:09:0694 std::unique_ptr<base::DictionaryValue> intercepted_prefs_;
probergec503d692016-09-28 19:51:0595 OnWriteCallbackPair on_write_callback_pair_;
[email protected]e33c9512014-05-12 02:24:1396
97 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
98};
99
100InterceptingPrefFilter::InterceptingPrefFilter() {}
probergec503d692016-09-28 19:51:05101
102InterceptingPrefFilter::InterceptingPrefFilter(
103 OnWriteCallbackPair callback_pair) {
104 on_write_callback_pair_ = callback_pair;
105}
106
[email protected]e33c9512014-05-12 02:24:13107InterceptingPrefFilter::~InterceptingPrefFilter() {}
108
109void InterceptingPrefFilter::FilterOnLoad(
110 const PostFilterOnLoadCallback& post_filter_on_load_callback,
dcheng5f043bc2016-04-22 19:09:06111 std::unique_ptr<base::DictionaryValue> pref_store_contents) {
[email protected]e33c9512014-05-12 02:24:13112 post_filter_on_load_callback_ = post_filter_on_load_callback;
danakj0c8d4aa2015-11-25 05:29:58113 intercepted_prefs_ = std::move(pref_store_contents);
[email protected]e33c9512014-05-12 02:24:13114}
115
116void InterceptingPrefFilter::ReleasePrefs() {
117 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
danakj0c8d4aa2015-11-25 05:29:58118 post_filter_on_load_callback_.Run(std::move(intercepted_prefs_), false);
[email protected]e33c9512014-05-12 02:24:13119 post_filter_on_load_callback_.Reset();
120}
121
[email protected]845b43a82011-05-11 10:14:43122class MockPrefStoreObserver : public PrefStore::Observer {
123 public:
124 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
125 MOCK_METHOD1(OnInitializationCompleted, void (bool));
126};
127
128class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
129 public:
130 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
131};
132
Francois Doray405dd2d2017-06-09 15:23:33133enum class CommitPendingWriteMode {
134 WITHOUT_CALLBACK,
135 WITH_CALLBACK,
136};
[email protected]845b43a82011-05-11 10:14:43137
Francois Doray405dd2d2017-06-09 15:23:33138void CommitPendingWrite(
139 JsonPrefStore* pref_store,
140 CommitPendingWriteMode commit_pending_write_mode,
141 base::test::ScopedTaskEnvironment* scoped_task_environment) {
142 if (commit_pending_write_mode == CommitPendingWriteMode::WITHOUT_CALLBACK) {
143 pref_store->CommitPendingWrite(OnceClosure());
144 scoped_task_environment->RunUntilIdle();
145 } else {
Francois Doray5f547952017-07-25 21:02:05146 TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment);
Francois Doray405dd2d2017-06-09 15:23:33147 }
148}
149
150class JsonPrefStoreTest
151 : public testing::TestWithParam<CommitPendingWriteMode> {
probergefc46ac12016-09-21 18:03:00152 public:
Francois Doray5f547952017-07-25 21:02:05153 JsonPrefStoreTest()
154 : scoped_task_environment_(
155 base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
156 base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
probergefc46ac12016-09-21 18:03:00157
[email protected]277404c22010-04-22 13:09:45158 protected:
dcheng8aef37612014-12-23 02:56:47159 void SetUp() override {
[email protected]3a305db2011-04-12 13:40:53160 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]277404c22010-04-22 13:09:45161 }
162
Francois Doray405dd2d2017-06-09 15:23:33163 base::test::ScopedTaskEnvironment scoped_task_environment_;
[email protected]e33c9512014-05-12 02:24:13164
[email protected]3a305db2011-04-12 13:40:53165 // The path to temporary directory used to contain the test operations.
[email protected]ea1a3f62012-11-16 20:34:23166 base::ScopedTempDir temp_dir_;
probergefc46ac12016-09-21 18:03:00167
168 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreTest);
[email protected]277404c22010-04-22 13:09:45169};
170
Francois Doray405dd2d2017-06-09 15:23:33171} // namespace
172
[email protected]277404c22010-04-22 13:09:45173// Test fallback behavior for a nonexistent file.
174TEST_F(JsonPrefStoreTest, NonExistentFile) {
vabr8023d872016-09-15 08:12:22175 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07176 ASSERT_FALSE(PathExists(bogus_input_file));
Francois Doray405dd2d2017-06-09 15:23:33177 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
[email protected]f2d1f612010-12-09 15:10:17178 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
[email protected]9a8c4022011-01-25 14:25:33179 pref_store->ReadPrefs());
180 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45181}
182
183// Test fallback behavior for an invalid file.
184TEST_F(JsonPrefStoreTest, InvalidFile) {
vabr8023d872016-09-15 08:12:22185 base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
brettw58cd1f12016-01-30 05:56:05186 ASSERT_LT(0, base::WriteFile(invalid_file,
187 kInvalidJson, arraysize(kInvalidJson) - 1));
188
Francois Doray405dd2d2017-06-09 15:23:33189 auto pref_store = base::MakeRefCounted<JsonPrefStore>(invalid_file);
[email protected]f2d1f612010-12-09 15:10:17190 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
[email protected]9a8c4022011-01-25 14:25:33191 pref_store->ReadPrefs());
192 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45193
194 // The file should have been moved aside.
[email protected]7567484142013-07-11 17:36:07195 EXPECT_FALSE(PathExists(invalid_file));
vabr8023d872016-09-15 08:12:22196 base::FilePath moved_aside = temp_dir_.GetPath().AppendASCII("invalid.bad");
[email protected]7567484142013-07-11 17:36:07197 EXPECT_TRUE(PathExists(moved_aside));
brettw58cd1f12016-01-30 05:56:05198
199 std::string moved_aside_contents;
200 ASSERT_TRUE(base::ReadFileToString(moved_aside, &moved_aside_contents));
201 EXPECT_EQ(kInvalidJson, moved_aside_contents);
[email protected]277404c22010-04-22 13:09:45202}
203
brettw58cd1f12016-01-30 05:56:05204// This function is used to avoid code duplication while testing synchronous
205// and asynchronous version of the JsonPrefStore loading. It validates that the
206// given output file's contents matches kWriteGolden.
Francois Doray405dd2d2017-06-09 15:23:33207void RunBasicJsonPrefStoreTest(
208 JsonPrefStore* pref_store,
209 const base::FilePath& output_file,
210 CommitPendingWriteMode commit_pending_write_mode,
211 base::test::ScopedTaskEnvironment* scoped_task_environment) {
[email protected]57ecc4b2010-08-11 03:02:51212 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
213 const char kMaxTabs[] = "tabs.max_tabs";
214 const char kLongIntPref[] = "long_int.pref";
[email protected]277404c22010-04-22 13:09:45215
[email protected]57ecc4b2010-08-11 03:02:51216 std::string cnn("http://www.cnn.com");
[email protected]277404c22010-04-22 13:09:45217
[email protected]68bf41a2011-03-25 16:38:31218 const Value* actual;
[email protected]5bfdcfd2012-11-22 22:08:24219 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
[email protected]57ecc4b2010-08-11 03:02:51220 std::string string_value;
[email protected]f2d1f612010-12-09 15:10:17221 EXPECT_TRUE(actual->GetAsString(&string_value));
[email protected]277404c22010-04-22 13:09:45222 EXPECT_EQ(cnn, string_value);
223
[email protected]57ecc4b2010-08-11 03:02:51224 const char kSomeDirectory[] = "some_directory";
[email protected]277404c22010-04-22 13:09:45225
[email protected]892f1d62012-11-08 18:24:34226 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]023ad6ab2013-02-17 05:07:23227 base::FilePath::StringType path;
[email protected]f2d1f612010-12-09 15:10:17228 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]023ad6ab2013-02-17 05:07:23229 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
230 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
[email protected]f2d1f612010-12-09 15:10:17231
estade0bd407f2015-06-26 18:16:18232 pref_store->SetValue(kSomeDirectory,
jdoerrie122c4da2017-03-06 11:12:04233 base::MakeUnique<Value>(some_path.value()),
raymes76de1af2015-05-06 03:22:21234 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34235 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]f2d1f612010-12-09 15:10:17236 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]277404c22010-04-22 13:09:45237 EXPECT_EQ(some_path.value(), path);
238
239 // Test reading some other data types from sub-dictionaries.
[email protected]892f1d62012-11-08 18:24:34240 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17241 bool boolean = false;
242 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45243 EXPECT_TRUE(boolean);
244
jdoerrie239723572017-03-02 12:09:19245 pref_store->SetValue(kNewWindowsInTabs, base::MakeUnique<Value>(false),
raymes76de1af2015-05-06 03:22:21246 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34247 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17248 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45249 EXPECT_FALSE(boolean);
250
[email protected]892f1d62012-11-08 18:24:34251 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17252 int integer = 0;
253 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45254 EXPECT_EQ(20, integer);
jdoerrie239723572017-03-02 12:09:19255 pref_store->SetValue(kMaxTabs, base::MakeUnique<Value>(10),
raymes76de1af2015-05-06 03:22:21256 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34257 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17258 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45259 EXPECT_EQ(10, integer);
260
jdoerrie122c4da2017-03-06 11:12:04261 pref_store->SetValue(
262 kLongIntPref,
263 base::MakeUnique<Value>(base::Int64ToString(214748364842LL)),
264 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34265 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
[email protected]f2d1f612010-12-09 15:10:17266 EXPECT_TRUE(actual->GetAsString(&string_value));
avi9ef8bb02015-12-24 05:29:36267 int64_t value;
[email protected]57ecc4b2010-08-11 03:02:51268 base::StringToInt64(string_value, &value);
[email protected]e83326f2010-07-31 17:29:25269 EXPECT_EQ(214748364842LL, value);
[email protected]277404c22010-04-22 13:09:45270
271 // Serialize and compare to expected output.
Francois Doray405dd2d2017-06-09 15:23:33272 CommitPendingWrite(pref_store, commit_pending_write_mode,
273 scoped_task_environment);
brettw58cd1f12016-01-30 05:56:05274
275 std::string output_contents;
276 ASSERT_TRUE(base::ReadFileToString(output_file, &output_contents));
277 EXPECT_EQ(kWriteGolden, output_contents);
[email protected]dd3aa792013-07-16 19:10:23278 ASSERT_TRUE(base::DeleteFile(output_file, false));
[email protected]277404c22010-04-22 13:09:45279}
[email protected]845b43a82011-05-11 10:14:43280
Francois Doray405dd2d2017-06-09 15:23:33281TEST_P(JsonPrefStoreTest, Basic) {
vabr8023d872016-09-15 08:12:22282 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05283 ASSERT_LT(0, base::WriteFile(input_file,
284 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43285
286 // Test that the persistent value can be loaded.
[email protected]7567484142013-07-11 17:36:07287 ASSERT_TRUE(PathExists(input_file));
Francois Doray405dd2d2017-06-09 15:23:33288 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
[email protected]845b43a82011-05-11 10:14:43289 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
[email protected]e33c9512014-05-12 02:24:13290 EXPECT_FALSE(pref_store->ReadOnly());
291 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]845b43a82011-05-11 10:14:43292
293 // The JSON file looks like this:
294 // {
295 // "homepage": "http://www.cnn.com",
296 // "some_directory": "/usr/local/",
297 // "tabs": {
298 // "new_windows_in_tabs": true,
299 // "max_tabs": 20
300 // }
301 // }
302
Francois Doray405dd2d2017-06-09 15:23:33303 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
304 &scoped_task_environment_);
[email protected]845b43a82011-05-11 10:14:43305}
306
Francois Doray405dd2d2017-06-09 15:23:33307TEST_P(JsonPrefStoreTest, BasicAsync) {
vabr8023d872016-09-15 08:12:22308 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05309 ASSERT_LT(0, base::WriteFile(input_file,
310 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43311
312 // Test that the persistent value can be loaded.
Francois Doray405dd2d2017-06-09 15:23:33313 auto pref_store = base::MakeRefCounted<JsonPrefStore>(input_file);
[email protected]845b43a82011-05-11 10:14:43314
[email protected]0de615a2012-11-08 04:40:59315 {
316 MockPrefStoreObserver mock_observer;
317 pref_store->AddObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43318
[email protected]0de615a2012-11-08 04:40:59319 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
320 pref_store->ReadPrefsAsync(mock_error_delegate);
[email protected]845b43a82011-05-11 10:14:43321
[email protected]0de615a2012-11-08 04:40:59322 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
323 EXPECT_CALL(*mock_error_delegate,
324 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
Francois Doray405dd2d2017-06-09 15:23:33325 scoped_task_environment_.RunUntilIdle();
[email protected]0de615a2012-11-08 04:40:59326 pref_store->RemoveObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43327
[email protected]e33c9512014-05-12 02:24:13328 EXPECT_FALSE(pref_store->ReadOnly());
329 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]0de615a2012-11-08 04:40:59330 }
[email protected]845b43a82011-05-11 10:14:43331
332 // The JSON file looks like this:
333 // {
334 // "homepage": "http://www.cnn.com",
335 // "some_directory": "/usr/local/",
336 // "tabs": {
337 // "new_windows_in_tabs": true,
338 // "max_tabs": 20
339 // }
340 // }
341
Francois Doray405dd2d2017-06-09 15:23:33342 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
343 &scoped_task_environment_);
[email protected]845b43a82011-05-11 10:14:43344}
345
Francois Doray405dd2d2017-06-09 15:23:33346TEST_P(JsonPrefStoreTest, PreserveEmptyValues) {
vabr8023d872016-09-15 08:12:22347 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]aa3283392013-11-27 01:38:24348
Francois Doray405dd2d2017-06-09 15:23:33349 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]aa3283392013-11-27 01:38:24350
351 // Set some keys with empty values.
jdoerrie3a7275f82017-05-31 05:58:33352 pref_store->SetValue("list", base::MakeUnique<base::ListValue>(),
raymes76de1af2015-05-06 03:22:21353 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
jdoerrie3a7275f82017-05-31 05:58:33354 pref_store->SetValue("dict", base::MakeUnique<base::DictionaryValue>(),
raymes76de1af2015-05-06 03:22:21355 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]aa3283392013-11-27 01:38:24356
357 // Write to file.
Francois Doray405dd2d2017-06-09 15:23:33358 CommitPendingWrite(pref_store.get(), GetParam(), &scoped_task_environment_);
[email protected]aa3283392013-11-27 01:38:24359
360 // Reload.
Francois Doray405dd2d2017-06-09 15:23:33361 pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]aa3283392013-11-27 01:38:24362 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
363 ASSERT_FALSE(pref_store->ReadOnly());
364
365 // Check values.
366 const Value* result = NULL;
367 EXPECT_TRUE(pref_store->GetValue("list", &result));
368 EXPECT_TRUE(ListValue().Equals(result));
369 EXPECT_TRUE(pref_store->GetValue("dict", &result));
370 EXPECT_TRUE(DictionaryValue().Equals(result));
371}
372
[email protected]eeedaa692014-01-30 09:22:27373// This test is just documenting some potentially non-obvious behavior. It
374// shouldn't be taken as normative.
375TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
vabr8023d872016-09-15 08:12:22376 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]eeedaa692014-01-30 09:22:27377
Francois Doray405dd2d2017-06-09 15:23:33378 auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
[email protected]eeedaa692014-01-30 09:22:27379
dcheng5f043bc2016-04-22 19:09:06380 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]eeedaa692014-01-30 09:22:27381 dict->SetString("key", "value");
danakj0c8d4aa2015-11-25 05:29:58382 pref_store->SetValue("dict", std::move(dict),
raymes76de1af2015-05-06 03:22:21383 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27384
raymes76de1af2015-05-06 03:22:21385 pref_store->RemoveValue("dict.key",
386 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27387
388 const base::Value* retrieved_dict = NULL;
389 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
390 EXPECT_FALSE(has_dict);
391}
392
[email protected]845b43a82011-05-11 10:14:43393// Tests asynchronous reading of the file when there is no file.
394TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
vabr8023d872016-09-15 08:12:22395 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07396 ASSERT_FALSE(PathExists(bogus_input_file));
Francois Doray405dd2d2017-06-09 15:23:33397 auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
[email protected]845b43a82011-05-11 10:14:43398 MockPrefStoreObserver mock_observer;
399 pref_store->AddObserver(&mock_observer);
400
401 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
402 pref_store->ReadPrefsAsync(mock_error_delegate);
403
404 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
405 EXPECT_CALL(*mock_error_delegate,
406 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
Francois Doray405dd2d2017-06-09 15:23:33407 scoped_task_environment_.RunUntilIdle();
[email protected]845b43a82011-05-11 10:14:43408 pref_store->RemoveObserver(&mock_observer);
409
410 EXPECT_FALSE(pref_store->ReadOnly());
411}
[email protected]ea3e4972012-04-12 03:41:37412
Francois Doray405dd2d2017-06-09 15:23:33413TEST_P(JsonPrefStoreTest, ReadWithInterceptor) {
vabr8023d872016-09-15 08:12:22414 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05415 ASSERT_LT(0, base::WriteFile(input_file,
416 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13417
dcheng5f043bc2016-04-22 19:09:06418 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13419 new InterceptingPrefFilter());
420 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
421 intercepting_pref_filter.get();
Francois Doray405dd2d2017-06-09 15:23:33422 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
423 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
424 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13425
426 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
427 pref_store->ReadPrefs());
428 EXPECT_FALSE(pref_store->ReadOnly());
429
430 // The store shouldn't be considered initialized until the interceptor
431 // returns.
432 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
433 EXPECT_FALSE(pref_store->IsInitializationComplete());
434 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
435
436 raw_intercepting_pref_filter_->ReleasePrefs();
437
438 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
439 EXPECT_TRUE(pref_store->IsInitializationComplete());
440 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
441
442 // The JSON file looks like this:
443 // {
444 // "homepage": "http://www.cnn.com",
445 // "some_directory": "/usr/local/",
446 // "tabs": {
447 // "new_windows_in_tabs": true,
448 // "max_tabs": 20
449 // }
450 // }
451
Francois Doray405dd2d2017-06-09 15:23:33452 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
453 &scoped_task_environment_);
[email protected]e33c9512014-05-12 02:24:13454}
455
Francois Doray405dd2d2017-06-09 15:23:33456TEST_P(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
vabr8023d872016-09-15 08:12:22457 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05458 ASSERT_LT(0, base::WriteFile(input_file,
459 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13460
dcheng5f043bc2016-04-22 19:09:06461 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13462 new InterceptingPrefFilter());
463 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
464 intercepting_pref_filter.get();
Francois Doray405dd2d2017-06-09 15:23:33465 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
466 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
467 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13468
469 MockPrefStoreObserver mock_observer;
470 pref_store->AddObserver(&mock_observer);
471
472 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
473 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
474
475 {
476 pref_store->ReadPrefsAsync(mock_error_delegate);
477
478 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
479 // EXPECT_CALL(*mock_error_delegate,
480 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
Francois Doray405dd2d2017-06-09 15:23:33481 scoped_task_environment_.RunUntilIdle();
[email protected]e33c9512014-05-12 02:24:13482
483 EXPECT_FALSE(pref_store->ReadOnly());
484 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
485 EXPECT_FALSE(pref_store->IsInitializationComplete());
486 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
487 }
488
489 {
490 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
491 // EXPECT_CALL(*mock_error_delegate,
492 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
493
494 raw_intercepting_pref_filter_->ReleasePrefs();
495
496 EXPECT_FALSE(pref_store->ReadOnly());
497 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
498 EXPECT_TRUE(pref_store->IsInitializationComplete());
499 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
500 }
501
502 pref_store->RemoveObserver(&mock_observer);
503
504 // The JSON file looks like this:
505 // {
506 // "homepage": "http://www.cnn.com",
507 // "some_directory": "/usr/local/",
508 // "tabs": {
509 // "new_windows_in_tabs": true,
510 // "max_tabs": 20
511 // }
512 // }
513
Francois Doray405dd2d2017-06-09 15:23:33514 RunBasicJsonPrefStoreTest(pref_store.get(), input_file, GetParam(),
515 &scoped_task_environment_);
[email protected]e33c9512014-05-12 02:24:13516}
517
raymesbfb910a2015-04-29 07:43:09518TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
brettw58cd1f12016-01-30 05:56:05519 base::HistogramTester histogram_tester;
520
raymesbfb910a2015-04-29 07:43:09521 SimpleTestClock* test_clock = new SimpleTestClock;
522 SetCurrentTimeInMinutes(0, test_clock);
523 JsonPrefStore::WriteCountHistogram histogram(
524 base::TimeDelta::FromSeconds(10),
525 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06526 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36527 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09528 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
529
530 histogram.RecordWriteOccured();
531
532 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
533 histogram.ReportOutstandingWrites();
dcheng5f043bc2016-04-22 19:09:06534 std::unique_ptr<HistogramSamples> samples =
raymesbfb910a2015-04-29 07:43:09535 histogram.GetHistogram()->SnapshotSamples();
brettw58cd1f12016-01-30 05:56:05536
537 std::string histogram_name = histogram.GetHistogram()->histogram_name();
538 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
539 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09540
541 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
542 histogram.GetHistogram()->histogram_name());
543 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
544}
545
546TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
brettw58cd1f12016-01-30 05:56:05547 base::HistogramTester histogram_tester;
548
raymesbfb910a2015-04-29 07:43:09549 SimpleTestClock* test_clock = new SimpleTestClock;
550 SetCurrentTimeInMinutes(0, test_clock);
551 JsonPrefStore::WriteCountHistogram histogram(
552 base::TimeDelta::FromSeconds(10),
553 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06554 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36555 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09556 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
557
558 histogram.RecordWriteOccured();
559 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
560 histogram.RecordWriteOccured();
561 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
562 histogram.RecordWriteOccured();
563
564 // Nothing should be recorded until the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05565 std::string histogram_name = histogram.GetHistogram()->histogram_name();
566 histogram_tester.ExpectTotalCount(histogram_name, 0);
raymesbfb910a2015-04-29 07:43:09567
568 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
569 histogram.RecordWriteOccured();
570
571 // Now the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05572 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
573 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09574
575 // The last write won't be recorded because the second count period hasn't
576 // fully elapsed.
577 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
578 histogram.ReportOutstandingWrites();
579
brettw58cd1f12016-01-30 05:56:05580 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
581 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09582}
583
584TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
brettw58cd1f12016-01-30 05:56:05585 base::HistogramTester histogram_tester;
586
raymesbfb910a2015-04-29 07:43:09587 SimpleTestClock* test_clock = new SimpleTestClock;
588 SetCurrentTimeInMinutes(0, test_clock);
589 JsonPrefStore::WriteCountHistogram histogram(
590 base::TimeDelta::FromSeconds(10),
591 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06592 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36593 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09594 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
595
596 histogram.RecordWriteOccured();
597 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
598 histogram.RecordWriteOccured();
599 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
600 histogram.RecordWriteOccured();
601 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
602 histogram.RecordWriteOccured();
603 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
604 histogram.RecordWriteOccured();
605 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
606 histogram.RecordWriteOccured();
607 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
608 histogram.RecordWriteOccured();
609 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
610 histogram.RecordWriteOccured();
611 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
612 histogram.RecordWriteOccured();
613
614 // The last write won't be recorded because the second count period hasn't
615 // fully elapsed
616 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
617 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05618 std::string histogram_name = histogram.GetHistogram()->histogram_name();
619 histogram_tester.ExpectBucketCount(histogram_name, 3, 2);
620 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
621 histogram_tester.ExpectTotalCount(histogram_name, 3);
raymesbfb910a2015-04-29 07:43:09622}
623
624TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
brettw58cd1f12016-01-30 05:56:05625 base::HistogramTester histogram_tester;
626
raymesbfb910a2015-04-29 07:43:09627 SimpleTestClock* test_clock = new SimpleTestClock;
628 SetCurrentTimeInMinutes(0, test_clock);
629 JsonPrefStore::WriteCountHistogram histogram(
630 base::TimeDelta::FromSeconds(10),
631 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06632 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36633 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09634 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
635
636 // 1 write in the first period.
637 histogram.RecordWriteOccured();
638
639 // No writes in the second and third periods.
640
641 // 2 writes in the fourth period.
642 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
643 histogram.RecordWriteOccured();
644 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
645 histogram.RecordWriteOccured();
646
647 // No writes in the fifth period.
648
649 // 3 writes in the sixth period.
650 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
651 histogram.RecordWriteOccured();
652 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
653 histogram.RecordWriteOccured();
654 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
655 histogram.RecordWriteOccured();
656
657 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
658 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05659 std::string histogram_name = histogram.GetHistogram()->histogram_name();
660 histogram_tester.ExpectBucketCount(histogram_name, 0, 3);
661 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
662 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
663 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
664 histogram_tester.ExpectTotalCount(histogram_name, 6);
raymesbfb910a2015-04-29 07:43:09665}
666
Francois Doray405dd2d2017-06-09 15:23:33667INSTANTIATE_TEST_CASE_P(
668 WithoutCallback,
669 JsonPrefStoreTest,
670 ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK));
671INSTANTIATE_TEST_CASE_P(
672 WithCallback,
673 JsonPrefStoreTest,
674 ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
675
raymes4b6e14e2015-05-12 00:10:30676class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
probergefc46ac12016-09-21 18:03:00677 public:
678 JsonPrefStoreLossyWriteTest() = default;
679
raymes4b6e14e2015-05-12 00:10:30680 protected:
681 void SetUp() override {
682 JsonPrefStoreTest::SetUp();
vabr8023d872016-09-15 08:12:22683 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
raymes4b6e14e2015-05-12 00:10:30684 }
685
raymes4b6e14e2015-05-12 00:10:30686 scoped_refptr<JsonPrefStore> CreatePrefStore() {
Francois Doray405dd2d2017-06-09 15:23:33687 return base::MakeRefCounted<JsonPrefStore>(test_file_);
raymes4b6e14e2015-05-12 00:10:30688 }
689
690 // Return the ImportantFileWriter for a given JsonPrefStore.
probergefc46ac12016-09-21 18:03:00691 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
raymes4b6e14e2015-05-12 00:10:30692 return &(pref_store->writer_);
693 }
694
695 // Get the contents of kTestFile. Pumps the message loop before returning the
696 // result.
697 std::string GetTestFileContents() {
Francois Doray405dd2d2017-06-09 15:23:33698 scoped_task_environment_.RunUntilIdle();
raymes4b6e14e2015-05-12 00:10:30699 std::string file_contents;
700 ReadFileToString(test_file_, &file_contents);
701 return file_contents;
702 }
703
704 private:
705 base::FilePath test_file_;
probergefc46ac12016-09-21 18:03:00706
707 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreLossyWriteTest);
raymes4b6e14e2015-05-12 00:10:30708};
709
710TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
711 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00712 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30713
714 // Set a normal pref and check that it gets scheduled to be written.
715 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04716 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30717 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
718 ASSERT_TRUE(file_writer->HasPendingWrite());
719 file_writer->DoScheduledWrite();
720 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
721 ASSERT_FALSE(file_writer->HasPendingWrite());
722
723 // Set a lossy pref and check that it is not scheduled to be written.
724 // SetValue/RemoveValue.
jdoerrie122c4da2017-03-06 11:12:04725 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30726 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
727 ASSERT_FALSE(file_writer->HasPendingWrite());
728 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
729 ASSERT_FALSE(file_writer->HasPendingWrite());
730
731 // SetValueSilently/RemoveValueSilently.
jdoerrie122c4da2017-03-06 11:12:04732 pref_store->SetValueSilently("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30733 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
734 ASSERT_FALSE(file_writer->HasPendingWrite());
735 pref_store->RemoveValueSilently("lossy",
736 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
737 ASSERT_FALSE(file_writer->HasPendingWrite());
738
739 // ReportValueChanged.
jdoerrie122c4da2017-03-06 11:12:04740 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30741 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
742 ASSERT_FALSE(file_writer->HasPendingWrite());
743 pref_store->ReportValueChanged("lossy",
744 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
745 ASSERT_FALSE(file_writer->HasPendingWrite());
746
747 // Call CommitPendingWrite and check that the lossy pref and the normal pref
748 // are there with the last values set above.
Francois Doray405dd2d2017-06-09 15:23:33749 pref_store->CommitPendingWrite(base::OnceClosure());
raymes4b6e14e2015-05-12 00:10:30750 ASSERT_FALSE(file_writer->HasPendingWrite());
751 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
752 GetTestFileContents());
753}
754
755TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
756 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00757 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30758
759 // Set a lossy pref and check that it is not scheduled to be written.
760 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04761 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30762 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
763 ASSERT_FALSE(file_writer->HasPendingWrite());
764
765 // Set a normal pref and check that it is scheduled to be written.
jdoerrie122c4da2017-03-06 11:12:04766 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30767 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
768 ASSERT_TRUE(file_writer->HasPendingWrite());
769
770 // Call DoScheduledWrite and check both prefs get written.
771 file_writer->DoScheduledWrite();
772 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
773 GetTestFileContents());
774 ASSERT_FALSE(file_writer->HasPendingWrite());
775}
776
777TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
778 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00779 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30780
781 // Set a normal pref and check that it is scheduled to be written.
782 ASSERT_FALSE(file_writer->HasPendingWrite());
jdoerrie122c4da2017-03-06 11:12:04783 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
raymes4b6e14e2015-05-12 00:10:30784 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
785 ASSERT_TRUE(file_writer->HasPendingWrite());
786
787 // Set a lossy pref and check that the write is still scheduled.
jdoerrie122c4da2017-03-06 11:12:04788 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
raymes4b6e14e2015-05-12 00:10:30789 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
790 ASSERT_TRUE(file_writer->HasPendingWrite());
791
792 // Call DoScheduledWrite and check both prefs get written.
793 file_writer->DoScheduledWrite();
794 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
795 GetTestFileContents());
796 ASSERT_FALSE(file_writer->HasPendingWrite());
797}
798
benwells26730592015-05-28 13:08:08799TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
800 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00801 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
benwells26730592015-05-28 13:08:08802
803 // Set a lossy pref and check that it is not scheduled to be written.
jdoerrie122c4da2017-03-06 11:12:04804 pref_store->SetValue("lossy", base::MakeUnique<base::Value>("lossy"),
benwells26730592015-05-28 13:08:08805 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
806 ASSERT_FALSE(file_writer->HasPendingWrite());
807
808 // Schedule pending lossy writes and check that it is scheduled.
809 pref_store->SchedulePendingLossyWrites();
810 ASSERT_TRUE(file_writer->HasPendingWrite());
811
812 // Call CommitPendingWrite and check that the lossy pref is there with the
813 // last value set above.
Francois Doray405dd2d2017-06-09 15:23:33814 pref_store->CommitPendingWrite(base::OnceClosure());
benwells26730592015-05-28 13:08:08815 ASSERT_FALSE(file_writer->HasPendingWrite());
816 ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
817}
818
probergefc46ac12016-09-21 18:03:00819class SuccessfulWriteReplyObserver {
820 public:
821 SuccessfulWriteReplyObserver() = default;
822
823 // Returns true if a successful write was observed via on_successful_write()
824 // and resets the observation state to false regardless.
825 bool GetAndResetObservationState() {
826 bool was_successful_write_observed = successful_write_reply_observed_;
827 successful_write_reply_observed_ = false;
828 return was_successful_write_observed;
829 }
830
831 // Register OnWrite() to be called on the next write of |json_pref_store|.
832 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
833
834 void OnSuccessfulWrite() {
835 EXPECT_FALSE(successful_write_reply_observed_);
836 successful_write_reply_observed_ = true;
837 }
838
839 private:
840 bool successful_write_reply_observed_ = false;
841
842 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteReplyObserver);
843};
844
845void SuccessfulWriteReplyObserver::ObserveNextWriteCallback(
846 JsonPrefStore* json_pref_store) {
847 json_pref_store->RegisterOnNextSuccessfulWriteReply(
848 base::Bind(&SuccessfulWriteReplyObserver::OnSuccessfulWrite,
849 base::Unretained(this)));
850}
851
852enum WriteCallbackObservationState {
853 NOT_CALLED,
854 CALLED_WITH_ERROR,
855 CALLED_WITH_SUCCESS,
856};
857
probergec503d692016-09-28 19:51:05858class WriteCallbacksObserver {
probergefc46ac12016-09-21 18:03:00859 public:
probergec503d692016-09-28 19:51:05860 WriteCallbacksObserver() = default;
probergefc46ac12016-09-21 18:03:00861
862 // Register OnWrite() to be called on the next write of |json_pref_store|.
863 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
864
probergec503d692016-09-28 19:51:05865 // Returns whether OnPreWrite() was called, and resets the observation state
866 // to false.
867 bool GetAndResetPreWriteObservationState();
probergefc46ac12016-09-21 18:03:00868
probergec503d692016-09-28 19:51:05869 // Returns the |WriteCallbackObservationState| which was observed, then resets
870 // it to |NOT_CALLED|.
871 WriteCallbackObservationState GetAndResetPostWriteObservationState();
872
873 JsonPrefStore::OnWriteCallbackPair GetCallbackPair() {
874 return std::make_pair(
875 base::Bind(&WriteCallbacksObserver::OnPreWrite, base::Unretained(this)),
876 base::Bind(&WriteCallbacksObserver::OnPostWrite,
877 base::Unretained(this)));
878 }
879
880 void OnPreWrite() {
881 EXPECT_FALSE(pre_write_called_);
882 pre_write_called_ = true;
883 }
884
885 void OnPostWrite(bool success) {
886 EXPECT_EQ(NOT_CALLED, post_write_observation_state_);
887 post_write_observation_state_ =
888 success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
probergefc46ac12016-09-21 18:03:00889 }
890
891 private:
probergec503d692016-09-28 19:51:05892 bool pre_write_called_ = false;
893 WriteCallbackObservationState post_write_observation_state_ = NOT_CALLED;
probergefc46ac12016-09-21 18:03:00894
probergec503d692016-09-28 19:51:05895 DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
probergefc46ac12016-09-21 18:03:00896};
897
probergec503d692016-09-28 19:51:05898void WriteCallbacksObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
899 writer->RegisterOnNextWriteSynchronousCallbacks(GetCallbackPair());
900}
901
902bool WriteCallbacksObserver::GetAndResetPreWriteObservationState() {
903 bool observation_state = pre_write_called_;
904 pre_write_called_ = false;
905 return observation_state;
probergefc46ac12016-09-21 18:03:00906}
907
908WriteCallbackObservationState
probergec503d692016-09-28 19:51:05909WriteCallbacksObserver::GetAndResetPostWriteObservationState() {
910 WriteCallbackObservationState state = post_write_observation_state_;
911 pre_write_called_ = false;
912 post_write_observation_state_ = NOT_CALLED;
probergefc46ac12016-09-21 18:03:00913 return state;
914}
915
916class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
917 public:
918 JsonPrefStoreCallbackTest() = default;
919
920 protected:
921 void SetUp() override {
922 JsonPrefStoreTest::SetUp();
vabr5d919d62016-09-30 08:55:36923 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
probergefc46ac12016-09-21 18:03:00924 }
925
926 scoped_refptr<JsonPrefStore> CreatePrefStore() {
Francois Doray405dd2d2017-06-09 15:23:33927 return base::MakeRefCounted<JsonPrefStore>(test_file_);
probergefc46ac12016-09-21 18:03:00928 }
929
930 // Return the ImportantFileWriter for a given JsonPrefStore.
931 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
932 return &(pref_store->writer_);
933 }
934
935 void TriggerFakeWriteForCallback(JsonPrefStore* pref_store, bool success) {
936 JsonPrefStore::PostWriteCallback(
937 base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
938 pref_store->AsWeakPtr()),
probergec503d692016-09-28 19:51:05939 base::Bind(&WriteCallbacksObserver::OnPostWrite,
probergefc46ac12016-09-21 18:03:00940 base::Unretained(&write_callback_observer_)),
941 base::SequencedTaskRunnerHandle::Get(), success);
942 }
943
944 SuccessfulWriteReplyObserver successful_write_reply_observer_;
probergec503d692016-09-28 19:51:05945 WriteCallbacksObserver write_callback_observer_;
probergefc46ac12016-09-21 18:03:00946
947 private:
948 base::FilePath test_file_;
949
950 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
951};
952
Francois Doray5f547952017-07-25 21:02:05953TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
probergec503d692016-09-28 19:51:05954 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
955 ASSERT_LT(0,
956 base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
957
958 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
959 new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
Francois Doray405dd2d2017-06-09 15:23:33960 auto pref_store = base::MakeRefCounted<JsonPrefStore>(
961 input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
962 std::move(intercepting_pref_filter));
probergec503d692016-09-28 19:51:05963 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
964
965 EXPECT_EQ(NOT_CALLED,
966 write_callback_observer_.GetAndResetPostWriteObservationState());
jdoerrie122c4da2017-03-06 11:12:04967 pref_store->SetValue("normal", base::MakeUnique<base::Value>("normal"),
probergec503d692016-09-28 19:51:05968 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
969 file_writer->DoScheduledWrite();
970
971 // The observer should not be invoked right away.
972 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
973 EXPECT_EQ(NOT_CALLED,
974 write_callback_observer_.GetAndResetPostWriteObservationState());
975
Francois Doray405dd2d2017-06-09 15:23:33976 scoped_task_environment_.RunUntilIdle();
probergec503d692016-09-28 19:51:05977
978 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
979 EXPECT_EQ(CALLED_WITH_SUCCESS,
980 write_callback_observer_.GetAndResetPostWriteObservationState());
981}
982
983TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacks) {
probergefc46ac12016-09-21 18:03:00984 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
985 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
986
probergec503d692016-09-28 19:51:05987 // Test RegisterOnNextWriteSynchronousCallbacks after
probergefc46ac12016-09-21 18:03:00988 // RegisterOnNextSuccessfulWriteReply.
989 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
990 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
991 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:33992 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:00993 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:05994 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
995 EXPECT_EQ(CALLED_WITH_SUCCESS,
996 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:00997
998 // Test RegisterOnNextSuccessfulWriteReply after
probergec503d692016-09-28 19:51:05999 // RegisterOnNextWriteSynchronousCallbacks.
probergefc46ac12016-09-21 18:03:001000 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1001 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1002 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331003 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001004 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051005 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
1006 EXPECT_EQ(CALLED_WITH_SUCCESS,
1007 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001008
1009 // Test RegisterOnNextSuccessfulWriteReply only.
1010 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1011 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331012 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001013 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051014 EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
1015 EXPECT_EQ(NOT_CALLED,
1016 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001017
probergec503d692016-09-28 19:51:051018 // Test RegisterOnNextWriteSynchronousCallbacks only.
probergefc46ac12016-09-21 18:03:001019 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1020 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331021 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001022 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051023 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
1024 EXPECT_EQ(CALLED_WITH_SUCCESS,
1025 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001026}
1027
probergec503d692016-09-28 19:51:051028TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksWithFakeFailure) {
probergefc46ac12016-09-21 18:03:001029 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
1030
1031 // Confirm that the observers are invoked.
1032 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1033 TriggerFakeWriteForCallback(pref_store.get(), true);
Francois Doray405dd2d2017-06-09 15:23:331034 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001035 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1036 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051037 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001038
1039 // Confirm that the observation states were reset.
1040 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051041 EXPECT_EQ(NOT_CALLED,
1042 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001043
1044 // Confirm that re-installing the observers works for another write.
1045 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1046 TriggerFakeWriteForCallback(pref_store.get(), true);
Francois Doray405dd2d2017-06-09 15:23:331047 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001048 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1049 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051050 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001051
1052 // Confirm that the successful observer is not invoked by an unsuccessful
1053 // write, and that the synchronous observer is invoked.
1054 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1055 TriggerFakeWriteForCallback(pref_store.get(), false);
Francois Doray405dd2d2017-06-09 15:23:331056 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001057 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1058 EXPECT_EQ(CALLED_WITH_ERROR,
probergec503d692016-09-28 19:51:051059 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001060
1061 // Do a real write, and confirm that the successful observer was invoked after
1062 // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
1063 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
1064 file_writer->WriteNow(MakeUnique<std::string>("foo"));
Francois Doray405dd2d2017-06-09 15:23:331065 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001066 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051067 EXPECT_EQ(NOT_CALLED,
1068 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001069}
1070
probergec503d692016-09-28 19:51:051071TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksDuringProfileDeath) {
probergefc46ac12016-09-21 18:03:001072 // Create a JsonPrefStore and attach observers to it, then delete it by making
1073 // it go out of scope to simulate profile switch or Chrome shutdown.
1074 {
1075 scoped_refptr<JsonPrefStore> soon_out_of_scope_pref_store =
1076 CreatePrefStore();
1077 ImportantFileWriter* file_writer =
1078 GetImportantFileWriter(soon_out_of_scope_pref_store.get());
1079 successful_write_reply_observer_.ObserveNextWriteCallback(
1080 soon_out_of_scope_pref_store.get());
1081 write_callback_observer_.ObserveNextWriteCallback(
1082 soon_out_of_scope_pref_store.get());
1083 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1084 }
Francois Doray405dd2d2017-06-09 15:23:331085 scoped_task_environment_.RunUntilIdle();
probergefc46ac12016-09-21 18:03:001086 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:051087 EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
probergefc46ac12016-09-21 18:03:001088 EXPECT_EQ(CALLED_WITH_SUCCESS,
probergec503d692016-09-28 19:51:051089 write_callback_observer_.GetAndResetPostWriteObservationState());
probergefc46ac12016-09-21 18:03:001090}
1091
vabr5d919d62016-09-30 08:55:361092} // namespace base