blob: cf93e7ef3352a137cf1bf4f5a5e312990036bae7 [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"
[email protected]e33c9512014-05-12 02:24:1319#include "base/message_loop/message_loop.h"
raymesbfb910a2015-04-29 07:43:0920#include "base/metrics/histogram_samples.h"
[email protected]277404c22010-04-22 13:09:4521#include "base/path_service.h"
[email protected]f7b98b32013-02-05 08:14:1522#include "base/run_loop.h"
skyostil054861d2015-04-30 19:06:1523#include "base/single_thread_task_runner.h"
[email protected]dfa049e2013-02-07 02:57:2224#include "base/strings/string_number_conversions.h"
[email protected]d529cb02013-06-10 19:06:5725#include "base/strings/string_util.h"
[email protected]a4ea1f12013-06-07 18:37:0726#include "base/strings/utf_string_conversions.h"
brettw58cd1f12016-01-30 05:56:0527#include "base/test/histogram_tester.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"
brettwf00b9b42016-02-01 22:11:3833#include "components/prefs/pref_filter.h"
[email protected]845b43a82011-05-11 10:14:4334#include "testing/gmock/include/gmock/gmock.h"
[email protected]277404c22010-04-22 13:09:4535#include "testing/gtest/include/gtest/gtest.h"
36
[email protected]7e3ec42c2012-12-16 05:13:2137namespace base {
[email protected]845b43a82011-05-11 10:14:4338namespace {
39
[email protected]5bfdcfd2012-11-22 22:08:2440const char kHomePage[] = "homepage";
41
brettw58cd1f12016-01-30 05:56:0542const char kReadJson[] =
43 "{\n"
44 " \"homepage\": \"http://www.cnn.com\",\n"
45 " \"some_directory\": \"/usr/local/\",\n"
46 " \"tabs\": {\n"
47 " \"new_windows_in_tabs\": true,\n"
48 " \"max_tabs\": 20\n"
49 " }\n"
50 "}";
51
52const char kInvalidJson[] = "!@#$%^&";
53
54// Expected output for tests using RunBasicJsonPrefStoreTest().
55const char kWriteGolden[] =
56 "{\"homepage\":\"http://www.cnn.com\","
57 "\"long_int\":{\"pref\":\"214748364842\"},"
58 "\"some_directory\":\"/usr/sbin/\","
59 "\"tabs\":{\"max_tabs\":10,\"new_windows_in_tabs\":false}}";
60
raymesbfb910a2015-04-29 07:43:0961// Set the time on the given SimpleTestClock to the given time in minutes.
62void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
63 const int32_t kBaseTimeMins = 100;
64 clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
65}
66
[email protected]e33c9512014-05-12 02:24:1367// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
68// to the |prefs| until explicitly asked to release them.
69class InterceptingPrefFilter : public PrefFilter {
70 public:
71 InterceptingPrefFilter();
dcheng56488182014-10-21 10:54:5172 ~InterceptingPrefFilter() override;
[email protected]e33c9512014-05-12 02:24:1373
74 // PrefFilter implementation:
dcheng56488182014-10-21 10:54:5175 void FilterOnLoad(
[email protected]e33c9512014-05-12 02:24:1376 const PostFilterOnLoadCallback& post_filter_on_load_callback,
dcheng5f043bc2016-04-22 19:09:0677 std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
dcheng56488182014-10-21 10:54:5178 void FilterUpdate(const std::string& path) override {}
79 void FilterSerializeData(
mostynb9e096de2014-10-07 17:59:1180 base::DictionaryValue* pref_store_contents) override {}
[email protected]e33c9512014-05-12 02:24:1381
82 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
83
[email protected]cfcf0e52014-06-20 18:29:4784 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
[email protected]e33c9512014-05-12 02:24:1385 // JsonPrefStore.
86 void ReleasePrefs();
87
88 private:
89 PostFilterOnLoadCallback post_filter_on_load_callback_;
dcheng5f043bc2016-04-22 19:09:0690 std::unique_ptr<base::DictionaryValue> intercepted_prefs_;
[email protected]e33c9512014-05-12 02:24:1391
92 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
93};
94
95InterceptingPrefFilter::InterceptingPrefFilter() {}
96InterceptingPrefFilter::~InterceptingPrefFilter() {}
97
98void InterceptingPrefFilter::FilterOnLoad(
99 const PostFilterOnLoadCallback& post_filter_on_load_callback,
dcheng5f043bc2016-04-22 19:09:06100 std::unique_ptr<base::DictionaryValue> pref_store_contents) {
[email protected]e33c9512014-05-12 02:24:13101 post_filter_on_load_callback_ = post_filter_on_load_callback;
danakj0c8d4aa2015-11-25 05:29:58102 intercepted_prefs_ = std::move(pref_store_contents);
[email protected]e33c9512014-05-12 02:24:13103}
104
105void InterceptingPrefFilter::ReleasePrefs() {
106 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
danakj0c8d4aa2015-11-25 05:29:58107 post_filter_on_load_callback_.Run(std::move(intercepted_prefs_), false);
[email protected]e33c9512014-05-12 02:24:13108 post_filter_on_load_callback_.Reset();
109}
110
[email protected]845b43a82011-05-11 10:14:43111class MockPrefStoreObserver : public PrefStore::Observer {
112 public:
113 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
114 MOCK_METHOD1(OnInitializationCompleted, void (bool));
115};
116
117class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
118 public:
119 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
120};
121
122} // namespace
123
[email protected]277404c22010-04-22 13:09:45124class JsonPrefStoreTest : public testing::Test {
probergefc46ac12016-09-21 18:03:00125 public:
126 JsonPrefStoreTest() = default;
127
[email protected]277404c22010-04-22 13:09:45128 protected:
dcheng8aef37612014-12-23 02:56:47129 void SetUp() override {
[email protected]3a305db2011-04-12 13:40:53130 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]277404c22010-04-22 13:09:45131 }
132
dcheng8aef37612014-12-23 02:56:47133 void TearDown() override {
[email protected]e33c9512014-05-12 02:24:13134 // Make sure all pending tasks have been processed (e.g., deleting the
135 // JsonPrefStore may post write tasks).
raymes4b6e14e2015-05-12 00:10:30136 RunLoop().RunUntilIdle();
[email protected]e33c9512014-05-12 02:24:13137 }
138
[email protected]3a305db2011-04-12 13:40:53139 // The path to temporary directory used to contain the test operations.
[email protected]ea1a3f62012-11-16 20:34:23140 base::ScopedTempDir temp_dir_;
[email protected]ea587b02010-05-21 15:01:35141 // A message loop that we can use as the file thread message loop.
142 MessageLoop message_loop_;
probergefc46ac12016-09-21 18:03:00143
144 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreTest);
[email protected]277404c22010-04-22 13:09:45145};
146
147// Test fallback behavior for a nonexistent file.
148TEST_F(JsonPrefStoreTest, NonExistentFile) {
vabr8023d872016-09-15 08:12:22149 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07150 ASSERT_FALSE(PathExists(bogus_input_file));
dcheng5f043bc2016-04-22 19:09:06151 scoped_refptr<JsonPrefStore> pref_store =
152 new JsonPrefStore(bogus_input_file, message_loop_.task_runner(),
153 std::unique_ptr<PrefFilter>());
[email protected]f2d1f612010-12-09 15:10:17154 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
[email protected]9a8c4022011-01-25 14:25:33155 pref_store->ReadPrefs());
156 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45157}
158
[email protected]cfcf0e52014-06-20 18:29:47159// Test fallback behavior for a nonexistent file and alternate file.
160TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
vabr8023d872016-09-15 08:12:22161 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]cfcf0e52014-06-20 18:29:47162 base::FilePath bogus_alternate_input_file =
vabr8023d872016-09-15 08:12:22163 temp_dir_.GetPath().AppendASCII("read_alternate.txt");
[email protected]cfcf0e52014-06-20 18:29:47164 ASSERT_FALSE(PathExists(bogus_input_file));
165 ASSERT_FALSE(PathExists(bogus_alternate_input_file));
dcheng5f043bc2016-04-22 19:09:06166 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
167 bogus_input_file, bogus_alternate_input_file, message_loop_.task_runner(),
168 std::unique_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47169 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
170 pref_store->ReadPrefs());
171 EXPECT_FALSE(pref_store->ReadOnly());
172}
173
[email protected]277404c22010-04-22 13:09:45174// Test fallback behavior for an invalid file.
175TEST_F(JsonPrefStoreTest, InvalidFile) {
vabr8023d872016-09-15 08:12:22176 base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
brettw58cd1f12016-01-30 05:56:05177 ASSERT_LT(0, base::WriteFile(invalid_file,
178 kInvalidJson, arraysize(kInvalidJson) - 1));
179
skyostil054861d2015-04-30 19:06:15180 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
dcheng5f043bc2016-04-22 19:09:06181 invalid_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
[email protected]f2d1f612010-12-09 15:10:17182 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
[email protected]9a8c4022011-01-25 14:25:33183 pref_store->ReadPrefs());
184 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45185
186 // The file should have been moved aside.
[email protected]7567484142013-07-11 17:36:07187 EXPECT_FALSE(PathExists(invalid_file));
vabr8023d872016-09-15 08:12:22188 base::FilePath moved_aside = temp_dir_.GetPath().AppendASCII("invalid.bad");
[email protected]7567484142013-07-11 17:36:07189 EXPECT_TRUE(PathExists(moved_aside));
brettw58cd1f12016-01-30 05:56:05190
191 std::string moved_aside_contents;
192 ASSERT_TRUE(base::ReadFileToString(moved_aside, &moved_aside_contents));
193 EXPECT_EQ(kInvalidJson, moved_aside_contents);
[email protected]277404c22010-04-22 13:09:45194}
195
brettw58cd1f12016-01-30 05:56:05196// This function is used to avoid code duplication while testing synchronous
197// and asynchronous version of the JsonPrefStore loading. It validates that the
198// given output file's contents matches kWriteGolden.
[email protected]0de615a2012-11-08 04:40:59199void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
brettw58cd1f12016-01-30 05:56:05200 const base::FilePath& output_file) {
[email protected]57ecc4b2010-08-11 03:02:51201 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
202 const char kMaxTabs[] = "tabs.max_tabs";
203 const char kLongIntPref[] = "long_int.pref";
[email protected]277404c22010-04-22 13:09:45204
[email protected]57ecc4b2010-08-11 03:02:51205 std::string cnn("http://www.cnn.com");
[email protected]277404c22010-04-22 13:09:45206
[email protected]68bf41a2011-03-25 16:38:31207 const Value* actual;
[email protected]5bfdcfd2012-11-22 22:08:24208 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
[email protected]57ecc4b2010-08-11 03:02:51209 std::string string_value;
[email protected]f2d1f612010-12-09 15:10:17210 EXPECT_TRUE(actual->GetAsString(&string_value));
[email protected]277404c22010-04-22 13:09:45211 EXPECT_EQ(cnn, string_value);
212
[email protected]57ecc4b2010-08-11 03:02:51213 const char kSomeDirectory[] = "some_directory";
[email protected]277404c22010-04-22 13:09:45214
[email protected]892f1d62012-11-08 18:24:34215 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]023ad6ab2013-02-17 05:07:23216 base::FilePath::StringType path;
[email protected]f2d1f612010-12-09 15:10:17217 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]023ad6ab2013-02-17 05:07:23218 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
219 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
[email protected]f2d1f612010-12-09 15:10:17220
estade0bd407f2015-06-26 18:16:18221 pref_store->SetValue(kSomeDirectory,
ricea85ec57952016-08-31 09:34:10222 base::MakeUnique<StringValue>(some_path.value()),
raymes76de1af2015-05-06 03:22:21223 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34224 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]f2d1f612010-12-09 15:10:17225 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]277404c22010-04-22 13:09:45226 EXPECT_EQ(some_path.value(), path);
227
228 // Test reading some other data types from sub-dictionaries.
[email protected]892f1d62012-11-08 18:24:34229 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17230 bool boolean = false;
231 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45232 EXPECT_TRUE(boolean);
233
estade0bd407f2015-06-26 18:16:18234 pref_store->SetValue(kNewWindowsInTabs,
ricea85ec57952016-08-31 09:34:10235 base::MakeUnique<FundamentalValue>(false),
raymes76de1af2015-05-06 03:22:21236 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34237 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17238 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45239 EXPECT_FALSE(boolean);
240
[email protected]892f1d62012-11-08 18:24:34241 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17242 int integer = 0;
243 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45244 EXPECT_EQ(20, integer);
ricea85ec57952016-08-31 09:34:10245 pref_store->SetValue(kMaxTabs, base::MakeUnique<FundamentalValue>(10),
raymes76de1af2015-05-06 03:22:21246 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34247 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17248 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45249 EXPECT_EQ(10, integer);
250
ricea85ec57952016-08-31 09:34:10251 pref_store->SetValue(kLongIntPref, base::MakeUnique<StringValue>(
252 base::Int64ToString(214748364842LL)),
253 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]892f1d62012-11-08 18:24:34254 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
[email protected]f2d1f612010-12-09 15:10:17255 EXPECT_TRUE(actual->GetAsString(&string_value));
avi9ef8bb02015-12-24 05:29:36256 int64_t value;
[email protected]57ecc4b2010-08-11 03:02:51257 base::StringToInt64(string_value, &value);
[email protected]e83326f2010-07-31 17:29:25258 EXPECT_EQ(214748364842LL, value);
[email protected]277404c22010-04-22 13:09:45259
260 // Serialize and compare to expected output.
[email protected]fbe17c8a2011-12-27 16:41:48261 pref_store->CommitPendingWrite();
[email protected]f7b98b32013-02-05 08:14:15262 RunLoop().RunUntilIdle();
brettw58cd1f12016-01-30 05:56:05263
264 std::string output_contents;
265 ASSERT_TRUE(base::ReadFileToString(output_file, &output_contents));
266 EXPECT_EQ(kWriteGolden, output_contents);
[email protected]dd3aa792013-07-16 19:10:23267 ASSERT_TRUE(base::DeleteFile(output_file, false));
[email protected]277404c22010-04-22 13:09:45268}
[email protected]845b43a82011-05-11 10:14:43269
270TEST_F(JsonPrefStoreTest, Basic) {
vabr8023d872016-09-15 08:12:22271 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05272 ASSERT_LT(0, base::WriteFile(input_file,
273 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43274
275 // Test that the persistent value can be loaded.
[email protected]7567484142013-07-11 17:36:07276 ASSERT_TRUE(PathExists(input_file));
[email protected]56cbcb3a2013-12-23 21:24:46277 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
dcheng5f043bc2016-04-22 19:09:06278 input_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43279 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
[email protected]e33c9512014-05-12 02:24:13280 EXPECT_FALSE(pref_store->ReadOnly());
281 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]845b43a82011-05-11 10:14:43282
283 // The JSON file looks like this:
284 // {
285 // "homepage": "http://www.cnn.com",
286 // "some_directory": "/usr/local/",
287 // "tabs": {
288 // "new_windows_in_tabs": true,
289 // "max_tabs": 20
290 // }
291 // }
292
brettw58cd1f12016-01-30 05:56:05293 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]845b43a82011-05-11 10:14:43294}
295
296TEST_F(JsonPrefStoreTest, BasicAsync) {
vabr8023d872016-09-15 08:12:22297 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05298 ASSERT_LT(0, base::WriteFile(input_file,
299 kReadJson, arraysize(kReadJson) - 1));
[email protected]845b43a82011-05-11 10:14:43300
301 // Test that the persistent value can be loaded.
[email protected]56cbcb3a2013-12-23 21:24:46302 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
dcheng5f043bc2016-04-22 19:09:06303 input_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43304
[email protected]0de615a2012-11-08 04:40:59305 {
306 MockPrefStoreObserver mock_observer;
307 pref_store->AddObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43308
[email protected]0de615a2012-11-08 04:40:59309 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
310 pref_store->ReadPrefsAsync(mock_error_delegate);
[email protected]845b43a82011-05-11 10:14:43311
[email protected]0de615a2012-11-08 04:40:59312 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
313 EXPECT_CALL(*mock_error_delegate,
314 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
[email protected]7ff48ca2013-02-06 16:56:19315 RunLoop().RunUntilIdle();
[email protected]0de615a2012-11-08 04:40:59316 pref_store->RemoveObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43317
[email protected]e33c9512014-05-12 02:24:13318 EXPECT_FALSE(pref_store->ReadOnly());
319 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]0de615a2012-11-08 04:40:59320 }
[email protected]845b43a82011-05-11 10:14:43321
322 // The JSON file looks like this:
323 // {
324 // "homepage": "http://www.cnn.com",
325 // "some_directory": "/usr/local/",
326 // "tabs": {
327 // "new_windows_in_tabs": true,
328 // "max_tabs": 20
329 // }
330 // }
331
brettw58cd1f12016-01-30 05:56:05332 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]845b43a82011-05-11 10:14:43333}
334
[email protected]aa3283392013-11-27 01:38:24335TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
vabr8023d872016-09-15 08:12:22336 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]aa3283392013-11-27 01:38:24337
[email protected]56cbcb3a2013-12-23 21:24:46338 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
dcheng5f043bc2016-04-22 19:09:06339 pref_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
[email protected]aa3283392013-11-27 01:38:24340
341 // Set some keys with empty values.
dcheng5f043bc2016-04-22 19:09:06342 pref_store->SetValue("list", base::WrapUnique(new base::ListValue),
raymes76de1af2015-05-06 03:22:21343 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
dcheng5f043bc2016-04-22 19:09:06344 pref_store->SetValue("dict", base::WrapUnique(new base::DictionaryValue),
raymes76de1af2015-05-06 03:22:21345 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]aa3283392013-11-27 01:38:24346
347 // Write to file.
348 pref_store->CommitPendingWrite();
raymes4b6e14e2015-05-12 00:10:30349 RunLoop().RunUntilIdle();
[email protected]aa3283392013-11-27 01:38:24350
351 // Reload.
skyostil054861d2015-04-30 19:06:15352 pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
dcheng5f043bc2016-04-22 19:09:06353 std::unique_ptr<PrefFilter>());
[email protected]aa3283392013-11-27 01:38:24354 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
355 ASSERT_FALSE(pref_store->ReadOnly());
356
357 // Check values.
358 const Value* result = NULL;
359 EXPECT_TRUE(pref_store->GetValue("list", &result));
360 EXPECT_TRUE(ListValue().Equals(result));
361 EXPECT_TRUE(pref_store->GetValue("dict", &result));
362 EXPECT_TRUE(DictionaryValue().Equals(result));
363}
364
[email protected]eeedaa692014-01-30 09:22:27365// This test is just documenting some potentially non-obvious behavior. It
366// shouldn't be taken as normative.
367TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
vabr8023d872016-09-15 08:12:22368 FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
[email protected]eeedaa692014-01-30 09:22:27369
370 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
dcheng5f043bc2016-04-22 19:09:06371 pref_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
[email protected]eeedaa692014-01-30 09:22:27372
dcheng5f043bc2016-04-22 19:09:06373 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
[email protected]eeedaa692014-01-30 09:22:27374 dict->SetString("key", "value");
danakj0c8d4aa2015-11-25 05:29:58375 pref_store->SetValue("dict", std::move(dict),
raymes76de1af2015-05-06 03:22:21376 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27377
raymes76de1af2015-05-06 03:22:21378 pref_store->RemoveValue("dict.key",
379 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
[email protected]eeedaa692014-01-30 09:22:27380
381 const base::Value* retrieved_dict = NULL;
382 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
383 EXPECT_FALSE(has_dict);
384}
385
[email protected]845b43a82011-05-11 10:14:43386// Tests asynchronous reading of the file when there is no file.
387TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
vabr8023d872016-09-15 08:12:22388 base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07389 ASSERT_FALSE(PathExists(bogus_input_file));
dcheng5f043bc2016-04-22 19:09:06390 scoped_refptr<JsonPrefStore> pref_store =
391 new JsonPrefStore(bogus_input_file, message_loop_.task_runner(),
392 std::unique_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43393 MockPrefStoreObserver mock_observer;
394 pref_store->AddObserver(&mock_observer);
395
396 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
397 pref_store->ReadPrefsAsync(mock_error_delegate);
398
399 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
400 EXPECT_CALL(*mock_error_delegate,
401 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
[email protected]7ff48ca2013-02-06 16:56:19402 RunLoop().RunUntilIdle();
[email protected]845b43a82011-05-11 10:14:43403 pref_store->RemoveObserver(&mock_observer);
404
405 EXPECT_FALSE(pref_store->ReadOnly());
406}
[email protected]ea3e4972012-04-12 03:41:37407
[email protected]e33c9512014-05-12 02:24:13408TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
vabr8023d872016-09-15 08:12:22409 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05410 ASSERT_LT(0, base::WriteFile(input_file,
411 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13412
dcheng5f043bc2016-04-22 19:09:06413 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13414 new InterceptingPrefFilter());
415 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
416 intercepting_pref_filter.get();
danakj0c8d4aa2015-11-25 05:29:58417 scoped_refptr<JsonPrefStore> pref_store =
418 new JsonPrefStore(input_file, message_loop_.task_runner(),
419 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13420
421 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
422 pref_store->ReadPrefs());
423 EXPECT_FALSE(pref_store->ReadOnly());
424
425 // The store shouldn't be considered initialized until the interceptor
426 // returns.
427 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
428 EXPECT_FALSE(pref_store->IsInitializationComplete());
429 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
430
431 raw_intercepting_pref_filter_->ReleasePrefs();
432
433 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
434 EXPECT_TRUE(pref_store->IsInitializationComplete());
435 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
436
437 // The JSON file looks like this:
438 // {
439 // "homepage": "http://www.cnn.com",
440 // "some_directory": "/usr/local/",
441 // "tabs": {
442 // "new_windows_in_tabs": true,
443 // "max_tabs": 20
444 // }
445 // }
446
brettw58cd1f12016-01-30 05:56:05447 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]e33c9512014-05-12 02:24:13448}
449
450TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
vabr8023d872016-09-15 08:12:22451 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05452 ASSERT_LT(0, base::WriteFile(input_file,
453 kReadJson, arraysize(kReadJson) - 1));
[email protected]e33c9512014-05-12 02:24:13454
dcheng5f043bc2016-04-22 19:09:06455 std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
[email protected]e33c9512014-05-12 02:24:13456 new InterceptingPrefFilter());
457 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
458 intercepting_pref_filter.get();
danakj0c8d4aa2015-11-25 05:29:58459 scoped_refptr<JsonPrefStore> pref_store =
460 new JsonPrefStore(input_file, message_loop_.task_runner(),
461 std::move(intercepting_pref_filter));
[email protected]e33c9512014-05-12 02:24:13462
463 MockPrefStoreObserver mock_observer;
464 pref_store->AddObserver(&mock_observer);
465
466 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
467 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
468
469 {
470 pref_store->ReadPrefsAsync(mock_error_delegate);
471
472 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
473 // EXPECT_CALL(*mock_error_delegate,
474 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
475 RunLoop().RunUntilIdle();
476
477 EXPECT_FALSE(pref_store->ReadOnly());
478 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
479 EXPECT_FALSE(pref_store->IsInitializationComplete());
480 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
481 }
482
483 {
484 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
485 // EXPECT_CALL(*mock_error_delegate,
486 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
487
488 raw_intercepting_pref_filter_->ReleasePrefs();
489
490 EXPECT_FALSE(pref_store->ReadOnly());
491 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
492 EXPECT_TRUE(pref_store->IsInitializationComplete());
493 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
494 }
495
496 pref_store->RemoveObserver(&mock_observer);
497
498 // The JSON file looks like this:
499 // {
500 // "homepage": "http://www.cnn.com",
501 // "some_directory": "/usr/local/",
502 // "tabs": {
503 // "new_windows_in_tabs": true,
504 // "max_tabs": 20
505 // }
506 // }
507
brettw58cd1f12016-01-30 05:56:05508 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]e33c9512014-05-12 02:24:13509}
510
[email protected]cfcf0e52014-06-20 18:29:47511TEST_F(JsonPrefStoreTest, AlternateFile) {
brettw58cd1f12016-01-30 05:56:05512 base::FilePath alternate_input_file =
vabr8023d872016-09-15 08:12:22513 temp_dir_.GetPath().AppendASCII("alternate.json");
brettw58cd1f12016-01-30 05:56:05514 ASSERT_LT(0, base::WriteFile(alternate_input_file,
515 kReadJson, arraysize(kReadJson) - 1));
[email protected]cfcf0e52014-06-20 18:29:47516
517 // Test that the alternate file is moved to the main file and read as-is from
518 // there.
vabr8023d872016-09-15 08:12:22519 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
[email protected]cfcf0e52014-06-20 18:29:47520 ASSERT_FALSE(PathExists(input_file));
521 ASSERT_TRUE(PathExists(alternate_input_file));
dcheng5f043bc2016-04-22 19:09:06522 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
523 input_file, alternate_input_file, message_loop_.task_runner(),
524 std::unique_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47525
526 ASSERT_FALSE(PathExists(input_file));
527 ASSERT_TRUE(PathExists(alternate_input_file));
528 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
529
530 ASSERT_TRUE(PathExists(input_file));
531 ASSERT_FALSE(PathExists(alternate_input_file));
532
533 EXPECT_FALSE(pref_store->ReadOnly());
534 EXPECT_TRUE(pref_store->IsInitializationComplete());
535
536 // The JSON file looks like this:
537 // {
538 // "homepage": "http://www.cnn.com",
539 // "some_directory": "/usr/local/",
540 // "tabs": {
541 // "new_windows_in_tabs": true,
542 // "max_tabs": 20
543 // }
544 // }
545
brettw58cd1f12016-01-30 05:56:05546 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]cfcf0e52014-06-20 18:29:47547}
548
549TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
vabr8023d872016-09-15 08:12:22550 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05551 ASSERT_LT(0, base::WriteFile(input_file,
552 kReadJson, arraysize(kReadJson) - 1));
553
554 base::FilePath alternate_input_file =
vabr8023d872016-09-15 08:12:22555 temp_dir_.GetPath().AppendASCII("alternate.json");
brettw58cd1f12016-01-30 05:56:05556 ASSERT_LT(0, base::WriteFile(alternate_input_file,
557 kInvalidJson, arraysize(kInvalidJson) - 1));
[email protected]cfcf0e52014-06-20 18:29:47558
559 // Test that the alternate file is ignored and that the read occurs from the
560 // existing main file. There is no attempt at even deleting the alternate
561 // file as this scenario should never happen in normal user-data-dirs.
dcheng5f043bc2016-04-22 19:09:06562 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
563 input_file, alternate_input_file, message_loop_.task_runner(),
564 std::unique_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47565
566 ASSERT_TRUE(PathExists(input_file));
567 ASSERT_TRUE(PathExists(alternate_input_file));
568 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
569
570 ASSERT_TRUE(PathExists(input_file));
571 ASSERT_TRUE(PathExists(alternate_input_file));
572
573 EXPECT_FALSE(pref_store->ReadOnly());
574 EXPECT_TRUE(pref_store->IsInitializationComplete());
575
576 // The JSON file looks like this:
577 // {
578 // "homepage": "http://www.cnn.com",
579 // "some_directory": "/usr/local/",
580 // "tabs": {
581 // "new_windows_in_tabs": true,
582 // "max_tabs": 20
583 // }
584 // }
585
brettw58cd1f12016-01-30 05:56:05586 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]cfcf0e52014-06-20 18:29:47587}
588
589TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
vabr8023d872016-09-15 08:12:22590 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
brettw58cd1f12016-01-30 05:56:05591 ASSERT_LT(0, base::WriteFile(input_file,
592 kReadJson, arraysize(kReadJson) - 1));
[email protected]cfcf0e52014-06-20 18:29:47593
594 // Test that the basic read works fine when an alternate file is specified but
595 // does not exist.
[email protected]cfcf0e52014-06-20 18:29:47596 base::FilePath alternate_input_file =
vabr8023d872016-09-15 08:12:22597 temp_dir_.GetPath().AppendASCII("alternate.json");
[email protected]cfcf0e52014-06-20 18:29:47598 ASSERT_TRUE(PathExists(input_file));
599 ASSERT_FALSE(PathExists(alternate_input_file));
dcheng5f043bc2016-04-22 19:09:06600 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
601 input_file, alternate_input_file, message_loop_.task_runner(),
602 std::unique_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47603
604 ASSERT_TRUE(PathExists(input_file));
605 ASSERT_FALSE(PathExists(alternate_input_file));
606 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
607
608 ASSERT_TRUE(PathExists(input_file));
609 ASSERT_FALSE(PathExists(alternate_input_file));
610
611 EXPECT_FALSE(pref_store->ReadOnly());
612 EXPECT_TRUE(pref_store->IsInitializationComplete());
613
614 // The JSON file looks like this:
615 // {
616 // "homepage": "http://www.cnn.com",
617 // "some_directory": "/usr/local/",
618 // "tabs": {
619 // "new_windows_in_tabs": true,
620 // "max_tabs": 20
621 // }
622 // }
623
brettw58cd1f12016-01-30 05:56:05624 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]cfcf0e52014-06-20 18:29:47625}
626
627TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
brettw58cd1f12016-01-30 05:56:05628 base::FilePath alternate_input_file =
vabr8023d872016-09-15 08:12:22629 temp_dir_.GetPath().AppendASCII("alternate.json");
brettw58cd1f12016-01-30 05:56:05630 ASSERT_LT(0, base::WriteFile(alternate_input_file,
631 kReadJson, arraysize(kReadJson) - 1));
[email protected]cfcf0e52014-06-20 18:29:47632
633 // Test that the alternate file is moved to the main file and read as-is from
634 // there even when the read is made asynchronously.
vabr8023d872016-09-15 08:12:22635 base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
dcheng5f043bc2016-04-22 19:09:06636 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
637 input_file, alternate_input_file, message_loop_.task_runner(),
638 std::unique_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47639
640 ASSERT_FALSE(PathExists(input_file));
641 ASSERT_TRUE(PathExists(alternate_input_file));
642
643 {
644 MockPrefStoreObserver mock_observer;
645 pref_store->AddObserver(&mock_observer);
646
647 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
648 pref_store->ReadPrefsAsync(mock_error_delegate);
649
650 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
651 EXPECT_CALL(*mock_error_delegate,
652 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
653 RunLoop().RunUntilIdle();
654 pref_store->RemoveObserver(&mock_observer);
655
656 EXPECT_FALSE(pref_store->ReadOnly());
657 EXPECT_TRUE(pref_store->IsInitializationComplete());
658 }
659
660 ASSERT_TRUE(PathExists(input_file));
661 ASSERT_FALSE(PathExists(alternate_input_file));
662
663 // The JSON file looks like this:
664 // {
665 // "homepage": "http://www.cnn.com",
666 // "some_directory": "/usr/local/",
667 // "tabs": {
668 // "new_windows_in_tabs": true,
669 // "max_tabs": 20
670 // }
671 // }
672
brettw58cd1f12016-01-30 05:56:05673 RunBasicJsonPrefStoreTest(pref_store.get(), input_file);
[email protected]cfcf0e52014-06-20 18:29:47674}
675
raymesbfb910a2015-04-29 07:43:09676TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
brettw58cd1f12016-01-30 05:56:05677 base::HistogramTester histogram_tester;
678
raymesbfb910a2015-04-29 07:43:09679 SimpleTestClock* test_clock = new SimpleTestClock;
680 SetCurrentTimeInMinutes(0, test_clock);
681 JsonPrefStore::WriteCountHistogram histogram(
682 base::TimeDelta::FromSeconds(10),
683 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06684 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36685 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09686 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
687
688 histogram.RecordWriteOccured();
689
690 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
691 histogram.ReportOutstandingWrites();
dcheng5f043bc2016-04-22 19:09:06692 std::unique_ptr<HistogramSamples> samples =
raymesbfb910a2015-04-29 07:43:09693 histogram.GetHistogram()->SnapshotSamples();
brettw58cd1f12016-01-30 05:56:05694
695 std::string histogram_name = histogram.GetHistogram()->histogram_name();
696 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
697 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09698
699 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
700 histogram.GetHistogram()->histogram_name());
701 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
702}
703
704TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
brettw58cd1f12016-01-30 05:56:05705 base::HistogramTester histogram_tester;
706
raymesbfb910a2015-04-29 07:43:09707 SimpleTestClock* test_clock = new SimpleTestClock;
708 SetCurrentTimeInMinutes(0, test_clock);
709 JsonPrefStore::WriteCountHistogram histogram(
710 base::TimeDelta::FromSeconds(10),
711 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06712 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36713 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09714 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
715
716 histogram.RecordWriteOccured();
717 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
718 histogram.RecordWriteOccured();
719 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
720 histogram.RecordWriteOccured();
721
722 // Nothing should be recorded until the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05723 std::string histogram_name = histogram.GetHistogram()->histogram_name();
724 histogram_tester.ExpectTotalCount(histogram_name, 0);
raymesbfb910a2015-04-29 07:43:09725
726 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
727 histogram.RecordWriteOccured();
728
729 // Now the report period has elapsed.
brettw58cd1f12016-01-30 05:56:05730 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
731 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09732
733 // The last write won't be recorded because the second count period hasn't
734 // fully elapsed.
735 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
736 histogram.ReportOutstandingWrites();
737
brettw58cd1f12016-01-30 05:56:05738 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
739 histogram_tester.ExpectTotalCount(histogram_name, 1);
raymesbfb910a2015-04-29 07:43:09740}
741
742TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
brettw58cd1f12016-01-30 05:56:05743 base::HistogramTester histogram_tester;
744
raymesbfb910a2015-04-29 07:43:09745 SimpleTestClock* test_clock = new SimpleTestClock;
746 SetCurrentTimeInMinutes(0, test_clock);
747 JsonPrefStore::WriteCountHistogram histogram(
748 base::TimeDelta::FromSeconds(10),
749 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06750 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36751 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09752 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
753
754 histogram.RecordWriteOccured();
755 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
756 histogram.RecordWriteOccured();
757 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
758 histogram.RecordWriteOccured();
759 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
760 histogram.RecordWriteOccured();
761 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
762 histogram.RecordWriteOccured();
763 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
764 histogram.RecordWriteOccured();
765 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
766 histogram.RecordWriteOccured();
767 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
768 histogram.RecordWriteOccured();
769 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
770 histogram.RecordWriteOccured();
771
772 // The last write won't be recorded because the second count period hasn't
773 // fully elapsed
774 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
775 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05776 std::string histogram_name = histogram.GetHistogram()->histogram_name();
777 histogram_tester.ExpectBucketCount(histogram_name, 3, 2);
778 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
779 histogram_tester.ExpectTotalCount(histogram_name, 3);
raymesbfb910a2015-04-29 07:43:09780}
781
782TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
brettw58cd1f12016-01-30 05:56:05783 base::HistogramTester histogram_tester;
784
raymesbfb910a2015-04-29 07:43:09785 SimpleTestClock* test_clock = new SimpleTestClock;
786 SetCurrentTimeInMinutes(0, test_clock);
787 JsonPrefStore::WriteCountHistogram histogram(
788 base::TimeDelta::FromSeconds(10),
789 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
dcheng5f043bc2016-04-22 19:09:06790 std::unique_ptr<base::Clock>(test_clock));
avi9ef8bb02015-12-24 05:29:36791 int32_t report_interval =
raymesbfb910a2015-04-29 07:43:09792 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
793
794 // 1 write in the first period.
795 histogram.RecordWriteOccured();
796
797 // No writes in the second and third periods.
798
799 // 2 writes in the fourth period.
800 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
801 histogram.RecordWriteOccured();
802 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
803 histogram.RecordWriteOccured();
804
805 // No writes in the fifth period.
806
807 // 3 writes in the sixth period.
808 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
809 histogram.RecordWriteOccured();
810 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
811 histogram.RecordWriteOccured();
812 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
813 histogram.RecordWriteOccured();
814
815 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
816 histogram.ReportOutstandingWrites();
brettw58cd1f12016-01-30 05:56:05817 std::string histogram_name = histogram.GetHistogram()->histogram_name();
818 histogram_tester.ExpectBucketCount(histogram_name, 0, 3);
819 histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
820 histogram_tester.ExpectBucketCount(histogram_name, 2, 1);
821 histogram_tester.ExpectBucketCount(histogram_name, 3, 1);
822 histogram_tester.ExpectTotalCount(histogram_name, 6);
raymesbfb910a2015-04-29 07:43:09823}
824
raymes4b6e14e2015-05-12 00:10:30825class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
probergefc46ac12016-09-21 18:03:00826 public:
827 JsonPrefStoreLossyWriteTest() = default;
828
raymes4b6e14e2015-05-12 00:10:30829 protected:
830 void SetUp() override {
831 JsonPrefStoreTest::SetUp();
vabr8023d872016-09-15 08:12:22832 test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
raymes4b6e14e2015-05-12 00:10:30833 }
834
raymes4b6e14e2015-05-12 00:10:30835 scoped_refptr<JsonPrefStore> CreatePrefStore() {
836 return new JsonPrefStore(test_file_, message_loop_.task_runner(),
dcheng5f043bc2016-04-22 19:09:06837 std::unique_ptr<PrefFilter>());
raymes4b6e14e2015-05-12 00:10:30838 }
839
840 // Return the ImportantFileWriter for a given JsonPrefStore.
probergefc46ac12016-09-21 18:03:00841 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
raymes4b6e14e2015-05-12 00:10:30842 return &(pref_store->writer_);
843 }
844
845 // Get the contents of kTestFile. Pumps the message loop before returning the
846 // result.
847 std::string GetTestFileContents() {
848 RunLoop().RunUntilIdle();
849 std::string file_contents;
850 ReadFileToString(test_file_, &file_contents);
851 return file_contents;
852 }
853
854 private:
855 base::FilePath test_file_;
probergefc46ac12016-09-21 18:03:00856
857 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreLossyWriteTest);
raymes4b6e14e2015-05-12 00:10:30858};
859
860TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
861 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00862 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30863
864 // Set a normal pref and check that it gets scheduled to be written.
865 ASSERT_FALSE(file_writer->HasPendingWrite());
ricea85ec57952016-08-31 09:34:10866 pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
raymes4b6e14e2015-05-12 00:10:30867 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
868 ASSERT_TRUE(file_writer->HasPendingWrite());
869 file_writer->DoScheduledWrite();
870 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
871 ASSERT_FALSE(file_writer->HasPendingWrite());
872
873 // Set a lossy pref and check that it is not scheduled to be written.
874 // SetValue/RemoveValue.
ricea85ec57952016-08-31 09:34:10875 pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
raymes4b6e14e2015-05-12 00:10:30876 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
877 ASSERT_FALSE(file_writer->HasPendingWrite());
878 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
879 ASSERT_FALSE(file_writer->HasPendingWrite());
880
881 // SetValueSilently/RemoveValueSilently.
estade0bd407f2015-06-26 18:16:18882 pref_store->SetValueSilently("lossy",
ricea85ec57952016-08-31 09:34:10883 base::MakeUnique<base::StringValue>("lossy"),
raymes4b6e14e2015-05-12 00:10:30884 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
885 ASSERT_FALSE(file_writer->HasPendingWrite());
886 pref_store->RemoveValueSilently("lossy",
887 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
888 ASSERT_FALSE(file_writer->HasPendingWrite());
889
890 // ReportValueChanged.
ricea85ec57952016-08-31 09:34:10891 pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
raymes4b6e14e2015-05-12 00:10:30892 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
893 ASSERT_FALSE(file_writer->HasPendingWrite());
894 pref_store->ReportValueChanged("lossy",
895 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
896 ASSERT_FALSE(file_writer->HasPendingWrite());
897
898 // Call CommitPendingWrite and check that the lossy pref and the normal pref
899 // are there with the last values set above.
900 pref_store->CommitPendingWrite();
901 ASSERT_FALSE(file_writer->HasPendingWrite());
902 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
903 GetTestFileContents());
904}
905
906TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
907 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00908 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30909
910 // Set a lossy pref and check that it is not scheduled to be written.
911 ASSERT_FALSE(file_writer->HasPendingWrite());
ricea85ec57952016-08-31 09:34:10912 pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
raymes4b6e14e2015-05-12 00:10:30913 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
914 ASSERT_FALSE(file_writer->HasPendingWrite());
915
916 // Set a normal pref and check that it is scheduled to be written.
ricea85ec57952016-08-31 09:34:10917 pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
raymes4b6e14e2015-05-12 00:10:30918 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
919 ASSERT_TRUE(file_writer->HasPendingWrite());
920
921 // Call DoScheduledWrite and check both prefs get written.
922 file_writer->DoScheduledWrite();
923 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
924 GetTestFileContents());
925 ASSERT_FALSE(file_writer->HasPendingWrite());
926}
927
928TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
929 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00930 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
raymes4b6e14e2015-05-12 00:10:30931
932 // Set a normal pref and check that it is scheduled to be written.
933 ASSERT_FALSE(file_writer->HasPendingWrite());
ricea85ec57952016-08-31 09:34:10934 pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
raymes4b6e14e2015-05-12 00:10:30935 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
936 ASSERT_TRUE(file_writer->HasPendingWrite());
937
938 // Set a lossy pref and check that the write is still scheduled.
ricea85ec57952016-08-31 09:34:10939 pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
raymes4b6e14e2015-05-12 00:10:30940 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
941 ASSERT_TRUE(file_writer->HasPendingWrite());
942
943 // Call DoScheduledWrite and check both prefs get written.
944 file_writer->DoScheduledWrite();
945 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
946 GetTestFileContents());
947 ASSERT_FALSE(file_writer->HasPendingWrite());
948}
949
benwells26730592015-05-28 13:08:08950TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
951 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
probergefc46ac12016-09-21 18:03:00952 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
benwells26730592015-05-28 13:08:08953
954 // Set a lossy pref and check that it is not scheduled to be written.
ricea85ec57952016-08-31 09:34:10955 pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
benwells26730592015-05-28 13:08:08956 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
957 ASSERT_FALSE(file_writer->HasPendingWrite());
958
959 // Schedule pending lossy writes and check that it is scheduled.
960 pref_store->SchedulePendingLossyWrites();
961 ASSERT_TRUE(file_writer->HasPendingWrite());
962
963 // Call CommitPendingWrite and check that the lossy pref is there with the
964 // last value set above.
965 pref_store->CommitPendingWrite();
966 ASSERT_FALSE(file_writer->HasPendingWrite());
967 ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
968}
969
probergefc46ac12016-09-21 18:03:00970class SuccessfulWriteReplyObserver {
971 public:
972 SuccessfulWriteReplyObserver() = default;
973
974 // Returns true if a successful write was observed via on_successful_write()
975 // and resets the observation state to false regardless.
976 bool GetAndResetObservationState() {
977 bool was_successful_write_observed = successful_write_reply_observed_;
978 successful_write_reply_observed_ = false;
979 return was_successful_write_observed;
980 }
981
982 // Register OnWrite() to be called on the next write of |json_pref_store|.
983 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
984
985 void OnSuccessfulWrite() {
986 EXPECT_FALSE(successful_write_reply_observed_);
987 successful_write_reply_observed_ = true;
988 }
989
990 private:
991 bool successful_write_reply_observed_ = false;
992
993 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteReplyObserver);
994};
995
996void SuccessfulWriteReplyObserver::ObserveNextWriteCallback(
997 JsonPrefStore* json_pref_store) {
998 json_pref_store->RegisterOnNextSuccessfulWriteReply(
999 base::Bind(&SuccessfulWriteReplyObserver::OnSuccessfulWrite,
1000 base::Unretained(this)));
1001}
1002
1003enum WriteCallbackObservationState {
1004 NOT_CALLED,
1005 CALLED_WITH_ERROR,
1006 CALLED_WITH_SUCCESS,
1007};
1008
1009class WriteCallbackObserver {
1010 public:
1011 WriteCallbackObserver() = default;
1012
1013 // Register OnWrite() to be called on the next write of |json_pref_store|.
1014 void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
1015
1016 // Returns true if a write was observed via OnWrite()
1017 // and resets the observation state to false regardless.
1018 WriteCallbackObservationState GetAndResetObservationState();
1019
1020 void OnWrite(bool success) {
1021 EXPECT_EQ(NOT_CALLED, observation_state_);
1022 observation_state_ = success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
1023 }
1024
1025 private:
1026 WriteCallbackObservationState observation_state_ = NOT_CALLED;
1027
1028 DISALLOW_COPY_AND_ASSIGN(WriteCallbackObserver);
1029};
1030
1031void WriteCallbackObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
1032 writer->RegisterOnNextWriteSynchronousCallback(
1033 base::Bind(&WriteCallbackObserver::OnWrite, base::Unretained(this)));
1034}
1035
1036WriteCallbackObservationState
1037WriteCallbackObserver::GetAndResetObservationState() {
1038 WriteCallbackObservationState state = observation_state_;
1039 observation_state_ = NOT_CALLED;
1040 return state;
1041}
1042
1043class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
1044 public:
1045 JsonPrefStoreCallbackTest() = default;
1046
1047 protected:
1048 void SetUp() override {
1049 JsonPrefStoreTest::SetUp();
1050 test_file_ = temp_dir_.path().AppendASCII("test.json");
1051 }
1052
1053 scoped_refptr<JsonPrefStore> CreatePrefStore() {
1054 return new JsonPrefStore(test_file_, message_loop_.task_runner(),
1055 std::unique_ptr<PrefFilter>());
1056 }
1057
1058 // Return the ImportantFileWriter for a given JsonPrefStore.
1059 ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
1060 return &(pref_store->writer_);
1061 }
1062
1063 void TriggerFakeWriteForCallback(JsonPrefStore* pref_store, bool success) {
1064 JsonPrefStore::PostWriteCallback(
1065 base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
1066 pref_store->AsWeakPtr()),
1067 base::Bind(&WriteCallbackObserver::OnWrite,
1068 base::Unretained(&write_callback_observer_)),
1069 base::SequencedTaskRunnerHandle::Get(), success);
1070 }
1071
1072 SuccessfulWriteReplyObserver successful_write_reply_observer_;
1073 WriteCallbackObserver write_callback_observer_;
1074
1075 private:
1076 base::FilePath test_file_;
1077
1078 DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
1079};
1080
1081TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallback) {
1082 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
1083 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
1084
1085 // Test RegisterOnNextWriteSynchronousCallback after
1086 // RegisterOnNextSuccessfulWriteReply.
1087 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1088 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1089 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1090 RunLoop().RunUntilIdle();
1091 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1092 EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
1093
1094 // Test RegisterOnNextSuccessfulWriteReply after
1095 // RegisterOnNextWriteSynchronousCallback.
1096 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1097 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1098 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1099 RunLoop().RunUntilIdle();
1100 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1101 EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
1102
1103 // Test RegisterOnNextSuccessfulWriteReply only.
1104 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1105 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1106 RunLoop().RunUntilIdle();
1107 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1108 EXPECT_FALSE(write_callback_observer_.GetAndResetObservationState());
1109
1110 // Test RegisterOnNextWriteSynchronousCallback only.
1111 write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
1112 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1113 RunLoop().RunUntilIdle();
1114 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1115 EXPECT_TRUE(write_callback_observer_.GetAndResetObservationState());
1116}
1117
1118TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbackWithFakeFailure) {
1119 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
1120
1121 // Confirm that the observers are invoked.
1122 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1123 TriggerFakeWriteForCallback(pref_store.get(), true);
1124 RunLoop().RunUntilIdle();
1125 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1126 EXPECT_EQ(CALLED_WITH_SUCCESS,
1127 write_callback_observer_.GetAndResetObservationState());
1128
1129 // Confirm that the observation states were reset.
1130 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1131 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
1132
1133 // Confirm that re-installing the observers works for another write.
1134 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1135 TriggerFakeWriteForCallback(pref_store.get(), true);
1136 RunLoop().RunUntilIdle();
1137 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1138 EXPECT_EQ(CALLED_WITH_SUCCESS,
1139 write_callback_observer_.GetAndResetObservationState());
1140
1141 // Confirm that the successful observer is not invoked by an unsuccessful
1142 // write, and that the synchronous observer is invoked.
1143 successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
1144 TriggerFakeWriteForCallback(pref_store.get(), false);
1145 RunLoop().RunUntilIdle();
1146 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1147 EXPECT_EQ(CALLED_WITH_ERROR,
1148 write_callback_observer_.GetAndResetObservationState());
1149
1150 // Do a real write, and confirm that the successful observer was invoked after
1151 // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
1152 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
1153 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1154 RunLoop().RunUntilIdle();
1155 EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
1156 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
1157}
1158
1159TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbackDuringProfileDeath) {
1160 // Create a JsonPrefStore and attach observers to it, then delete it by making
1161 // it go out of scope to simulate profile switch or Chrome shutdown.
1162 {
1163 scoped_refptr<JsonPrefStore> soon_out_of_scope_pref_store =
1164 CreatePrefStore();
1165 ImportantFileWriter* file_writer =
1166 GetImportantFileWriter(soon_out_of_scope_pref_store.get());
1167 successful_write_reply_observer_.ObserveNextWriteCallback(
1168 soon_out_of_scope_pref_store.get());
1169 write_callback_observer_.ObserveNextWriteCallback(
1170 soon_out_of_scope_pref_store.get());
1171 file_writer->WriteNow(MakeUnique<std::string>("foo"));
1172 }
1173 RunLoop().RunUntilIdle();
1174 EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
1175 EXPECT_EQ(CALLED_WITH_SUCCESS,
1176 write_callback_observer_.GetAndResetObservationState());
1177}
1178
1179} // namespace base