blob: 728a57d3417fc4e5893c4226939f12ba1b5cc7e8 [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
[email protected]00c87822012-11-27 19:09:175#include "base/prefs/json_pref_store.h"
6
[email protected]e33c9512014-05-12 02:24:137#include "base/bind.h"
[email protected]e3177dd52014-08-13 20:22:148#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:239#include "base/files/scoped_temp_dir.h"
skyostil054861d2015-04-30 19:06:1510#include "base/location.h"
[email protected]3b63f8f42011-03-28 01:54:1511#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
[email protected]e33c9512014-05-12 02:24:1313#include "base/message_loop/message_loop.h"
raymesbfb910a2015-04-29 07:43:0914#include "base/metrics/histogram_samples.h"
15#include "base/metrics/statistics_recorder.h"
[email protected]277404c22010-04-22 13:09:4516#include "base/path_service.h"
[email protected]56cbcb3a2013-12-23 21:24:4617#include "base/prefs/pref_filter.h"
[email protected]f7b98b32013-02-05 08:14:1518#include "base/run_loop.h"
skyostil054861d2015-04-30 19:06:1519#include "base/single_thread_task_runner.h"
[email protected]dfa049e2013-02-07 02:57:2220#include "base/strings/string_number_conversions.h"
[email protected]d529cb02013-06-10 19:06:5721#include "base/strings/string_util.h"
[email protected]a4ea1f12013-06-07 18:37:0722#include "base/strings/utf_string_conversions.h"
raymesbfb910a2015-04-29 07:43:0923#include "base/test/simple_test_clock.h"
[email protected]0de615a2012-11-08 04:40:5924#include "base/threading/sequenced_worker_pool.h"
[email protected]34b99632011-01-01 01:01:0625#include "base/threading/thread.h"
[email protected]277404c22010-04-22 13:09:4526#include "base/values.h"
[email protected]845b43a82011-05-11 10:14:4327#include "testing/gmock/include/gmock/gmock.h"
[email protected]277404c22010-04-22 13:09:4528#include "testing/gtest/include/gtest/gtest.h"
29
[email protected]7e3ec42c2012-12-16 05:13:2130namespace base {
[email protected]845b43a82011-05-11 10:14:4331namespace {
32
[email protected]5bfdcfd2012-11-22 22:08:2433const char kHomePage[] = "homepage";
34
raymesbfb910a2015-04-29 07:43:0935// Set the time on the given SimpleTestClock to the given time in minutes.
36void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
37 const int32_t kBaseTimeMins = 100;
38 clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
39}
40
[email protected]e33c9512014-05-12 02:24:1341// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
42// to the |prefs| until explicitly asked to release them.
43class InterceptingPrefFilter : public PrefFilter {
44 public:
45 InterceptingPrefFilter();
dcheng56488182014-10-21 10:54:5146 ~InterceptingPrefFilter() override;
[email protected]e33c9512014-05-12 02:24:1347
48 // PrefFilter implementation:
dcheng56488182014-10-21 10:54:5149 void FilterOnLoad(
[email protected]e33c9512014-05-12 02:24:1350 const PostFilterOnLoadCallback& post_filter_on_load_callback,
mostynb9e096de2014-10-07 17:59:1151 scoped_ptr<base::DictionaryValue> pref_store_contents) override;
dcheng56488182014-10-21 10:54:5152 void FilterUpdate(const std::string& path) override {}
53 void FilterSerializeData(
mostynb9e096de2014-10-07 17:59:1154 base::DictionaryValue* pref_store_contents) override {}
[email protected]e33c9512014-05-12 02:24:1355
56 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
57
[email protected]cfcf0e52014-06-20 18:29:4758 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
[email protected]e33c9512014-05-12 02:24:1359 // JsonPrefStore.
60 void ReleasePrefs();
61
62 private:
63 PostFilterOnLoadCallback post_filter_on_load_callback_;
64 scoped_ptr<base::DictionaryValue> intercepted_prefs_;
65
66 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
67};
68
69InterceptingPrefFilter::InterceptingPrefFilter() {}
70InterceptingPrefFilter::~InterceptingPrefFilter() {}
71
72void InterceptingPrefFilter::FilterOnLoad(
73 const PostFilterOnLoadCallback& post_filter_on_load_callback,
74 scoped_ptr<base::DictionaryValue> pref_store_contents) {
75 post_filter_on_load_callback_ = post_filter_on_load_callback;
76 intercepted_prefs_ = pref_store_contents.Pass();
77}
78
79void InterceptingPrefFilter::ReleasePrefs() {
80 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
81 post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false);
82 post_filter_on_load_callback_.Reset();
83}
84
[email protected]845b43a82011-05-11 10:14:4385class MockPrefStoreObserver : public PrefStore::Observer {
86 public:
87 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
88 MOCK_METHOD1(OnInitializationCompleted, void (bool));
89};
90
91class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
92 public:
93 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
94};
95
96} // namespace
97
[email protected]277404c22010-04-22 13:09:4598class JsonPrefStoreTest : public testing::Test {
99 protected:
dcheng8aef37612014-12-23 02:56:47100 void SetUp() override {
[email protected]3a305db2011-04-12 13:40:53101 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]277404c22010-04-22 13:09:45102
[email protected]fd1d067b2013-04-07 16:27:46103 ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
[email protected]00c87822012-11-27 19:09:17104 data_dir_ = data_dir_.AppendASCII("prefs");
[email protected]7567484142013-07-11 17:36:07105 ASSERT_TRUE(PathExists(data_dir_));
[email protected]277404c22010-04-22 13:09:45106 }
107
dcheng8aef37612014-12-23 02:56:47108 void TearDown() override {
[email protected]e33c9512014-05-12 02:24:13109 // Make sure all pending tasks have been processed (e.g., deleting the
110 // JsonPrefStore may post write tasks).
skyostil054861d2015-04-30 19:06:15111 message_loop_.task_runner()->PostTask(FROM_HERE,
112 MessageLoop::QuitWhenIdleClosure());
[email protected]e33c9512014-05-12 02:24:13113 message_loop_.Run();
114 }
115
[email protected]3a305db2011-04-12 13:40:53116 // The path to temporary directory used to contain the test operations.
[email protected]ea1a3f62012-11-16 20:34:23117 base::ScopedTempDir temp_dir_;
[email protected]3a305db2011-04-12 13:40:53118 // The path to the directory where the test data is stored.
[email protected]023ad6ab2013-02-17 05:07:23119 base::FilePath data_dir_;
[email protected]ea587b02010-05-21 15:01:35120 // A message loop that we can use as the file thread message loop.
121 MessageLoop message_loop_;
raymesbfb910a2015-04-29 07:43:09122
123 private:
124 // Ensure histograms are reset for each test.
125 StatisticsRecorder statistics_recorder_;
[email protected]277404c22010-04-22 13:09:45126};
127
128// Test fallback behavior for a nonexistent file.
129TEST_F(JsonPrefStoreTest, NonExistentFile) {
[email protected]023ad6ab2013-02-17 05:07:23130 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07131 ASSERT_FALSE(PathExists(bogus_input_file));
[email protected]cadac622013-06-11 16:46:36132 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15133 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]f2d1f612010-12-09 15:10:17134 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
[email protected]9a8c4022011-01-25 14:25:33135 pref_store->ReadPrefs());
136 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45137}
138
[email protected]cfcf0e52014-06-20 18:29:47139// Test fallback behavior for a nonexistent file and alternate file.
140TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
141 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
142 base::FilePath bogus_alternate_input_file =
143 data_dir_.AppendASCII("read_alternate.txt");
144 ASSERT_FALSE(PathExists(bogus_input_file));
145 ASSERT_FALSE(PathExists(bogus_alternate_input_file));
skyostil054861d2015-04-30 19:06:15146 scoped_refptr<JsonPrefStore> pref_store =
147 new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
148 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47149 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
150 pref_store->ReadPrefs());
151 EXPECT_FALSE(pref_store->ReadOnly());
152}
153
[email protected]277404c22010-04-22 13:09:45154// Test fallback behavior for an invalid file.
155TEST_F(JsonPrefStoreTest, InvalidFile) {
[email protected]023ad6ab2013-02-17 05:07:23156 base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
157 base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
[email protected]f0ff2ad2013-07-09 17:42:26158 ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
skyostil054861d2015-04-30 19:06:15159 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
160 invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]f2d1f612010-12-09 15:10:17161 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
[email protected]9a8c4022011-01-25 14:25:33162 pref_store->ReadPrefs());
163 EXPECT_FALSE(pref_store->ReadOnly());
[email protected]277404c22010-04-22 13:09:45164
165 // The file should have been moved aside.
[email protected]7567484142013-07-11 17:36:07166 EXPECT_FALSE(PathExists(invalid_file));
[email protected]023ad6ab2013-02-17 05:07:23167 base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
[email protected]7567484142013-07-11 17:36:07168 EXPECT_TRUE(PathExists(moved_aside));
[email protected]dcd16612013-07-15 20:18:09169 EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside));
[email protected]277404c22010-04-22 13:09:45170}
171
[email protected]845b43a82011-05-11 10:14:43172// This function is used to avoid code duplication while testing synchronous and
173// asynchronous version of the JsonPrefStore loading.
[email protected]0de615a2012-11-08 04:40:59174void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
[email protected]023ad6ab2013-02-17 05:07:23175 const base::FilePath& output_file,
176 const base::FilePath& golden_output_file) {
[email protected]57ecc4b2010-08-11 03:02:51177 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
178 const char kMaxTabs[] = "tabs.max_tabs";
179 const char kLongIntPref[] = "long_int.pref";
[email protected]277404c22010-04-22 13:09:45180
[email protected]57ecc4b2010-08-11 03:02:51181 std::string cnn("http://www.cnn.com");
[email protected]277404c22010-04-22 13:09:45182
[email protected]68bf41a2011-03-25 16:38:31183 const Value* actual;
[email protected]5bfdcfd2012-11-22 22:08:24184 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
[email protected]57ecc4b2010-08-11 03:02:51185 std::string string_value;
[email protected]f2d1f612010-12-09 15:10:17186 EXPECT_TRUE(actual->GetAsString(&string_value));
[email protected]277404c22010-04-22 13:09:45187 EXPECT_EQ(cnn, string_value);
188
[email protected]57ecc4b2010-08-11 03:02:51189 const char kSomeDirectory[] = "some_directory";
[email protected]277404c22010-04-22 13:09:45190
[email protected]892f1d62012-11-08 18:24:34191 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]023ad6ab2013-02-17 05:07:23192 base::FilePath::StringType path;
[email protected]f2d1f612010-12-09 15:10:17193 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]023ad6ab2013-02-17 05:07:23194 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
195 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
[email protected]f2d1f612010-12-09 15:10:17196
[email protected]7e3ec42c2012-12-16 05:13:21197 pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()));
[email protected]892f1d62012-11-08 18:24:34198 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
[email protected]f2d1f612010-12-09 15:10:17199 EXPECT_TRUE(actual->GetAsString(&path));
[email protected]277404c22010-04-22 13:09:45200 EXPECT_EQ(some_path.value(), path);
201
202 // Test reading some other data types from sub-dictionaries.
[email protected]892f1d62012-11-08 18:24:34203 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17204 bool boolean = false;
205 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45206 EXPECT_TRUE(boolean);
207
[email protected]7e3ec42c2012-12-16 05:13:21208 pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false));
[email protected]892f1d62012-11-08 18:24:34209 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17210 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
[email protected]277404c22010-04-22 13:09:45211 EXPECT_FALSE(boolean);
212
[email protected]892f1d62012-11-08 18:24:34213 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17214 int integer = 0;
215 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45216 EXPECT_EQ(20, integer);
[email protected]7e3ec42c2012-12-16 05:13:21217 pref_store->SetValue(kMaxTabs, new FundamentalValue(10));
[email protected]892f1d62012-11-08 18:24:34218 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
[email protected]f2d1f612010-12-09 15:10:17219 EXPECT_TRUE(actual->GetAsInteger(&integer));
[email protected]277404c22010-04-22 13:09:45220 EXPECT_EQ(10, integer);
221
[email protected]9a8c4022011-01-25 14:25:33222 pref_store->SetValue(kLongIntPref,
[email protected]7e3ec42c2012-12-16 05:13:21223 new StringValue(base::Int64ToString(214748364842LL)));
[email protected]892f1d62012-11-08 18:24:34224 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
[email protected]f2d1f612010-12-09 15:10:17225 EXPECT_TRUE(actual->GetAsString(&string_value));
[email protected]e83326f2010-07-31 17:29:25226 int64 value;
[email protected]57ecc4b2010-08-11 03:02:51227 base::StringToInt64(string_value, &value);
[email protected]e83326f2010-07-31 17:29:25228 EXPECT_EQ(214748364842LL, value);
[email protected]277404c22010-04-22 13:09:45229
230 // Serialize and compare to expected output.
[email protected]7567484142013-07-11 17:36:07231 ASSERT_TRUE(PathExists(golden_output_file));
[email protected]fbe17c8a2011-12-27 16:41:48232 pref_store->CommitPendingWrite();
[email protected]f7b98b32013-02-05 08:14:15233 RunLoop().RunUntilIdle();
[email protected]dcd16612013-07-15 20:18:09234 EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file));
[email protected]dd3aa792013-07-16 19:10:23235 ASSERT_TRUE(base::DeleteFile(output_file, false));
[email protected]277404c22010-04-22 13:09:45236}
[email protected]845b43a82011-05-11 10:14:43237
238TEST_F(JsonPrefStoreTest, Basic) {
[email protected]f0ff2ad2013-07-09 17:42:26239 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
[email protected]e33c9512014-05-12 02:24:13240 temp_dir_.path().AppendASCII("write.json")));
[email protected]845b43a82011-05-11 10:14:43241
242 // Test that the persistent value can be loaded.
[email protected]023ad6ab2013-02-17 05:07:23243 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
[email protected]7567484142013-07-11 17:36:07244 ASSERT_TRUE(PathExists(input_file));
[email protected]56cbcb3a2013-12-23 21:24:46245 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15246 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43247 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
[email protected]e33c9512014-05-12 02:24:13248 EXPECT_FALSE(pref_store->ReadOnly());
249 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]845b43a82011-05-11 10:14:43250
251 // The JSON file looks like this:
252 // {
253 // "homepage": "http://www.cnn.com",
254 // "some_directory": "/usr/local/",
255 // "tabs": {
256 // "new_windows_in_tabs": true,
257 // "max_tabs": 20
258 // }
259 // }
260
[email protected]3703e922013-05-31 21:37:53261 RunBasicJsonPrefStoreTest(
262 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
[email protected]845b43a82011-05-11 10:14:43263}
264
265TEST_F(JsonPrefStoreTest, BasicAsync) {
[email protected]f0ff2ad2013-07-09 17:42:26266 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
[email protected]e33c9512014-05-12 02:24:13267 temp_dir_.path().AppendASCII("write.json")));
[email protected]845b43a82011-05-11 10:14:43268
269 // Test that the persistent value can be loaded.
[email protected]023ad6ab2013-02-17 05:07:23270 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
[email protected]7567484142013-07-11 17:36:07271 ASSERT_TRUE(PathExists(input_file));
[email protected]56cbcb3a2013-12-23 21:24:46272 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15273 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43274
[email protected]0de615a2012-11-08 04:40:59275 {
276 MockPrefStoreObserver mock_observer;
277 pref_store->AddObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43278
[email protected]0de615a2012-11-08 04:40:59279 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
280 pref_store->ReadPrefsAsync(mock_error_delegate);
[email protected]845b43a82011-05-11 10:14:43281
[email protected]0de615a2012-11-08 04:40:59282 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
283 EXPECT_CALL(*mock_error_delegate,
284 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
[email protected]7ff48ca2013-02-06 16:56:19285 RunLoop().RunUntilIdle();
[email protected]0de615a2012-11-08 04:40:59286 pref_store->RemoveObserver(&mock_observer);
[email protected]845b43a82011-05-11 10:14:43287
[email protected]e33c9512014-05-12 02:24:13288 EXPECT_FALSE(pref_store->ReadOnly());
289 EXPECT_TRUE(pref_store->IsInitializationComplete());
[email protected]0de615a2012-11-08 04:40:59290 }
[email protected]845b43a82011-05-11 10:14:43291
292 // The JSON file looks like this:
293 // {
294 // "homepage": "http://www.cnn.com",
295 // "some_directory": "/usr/local/",
296 // "tabs": {
297 // "new_windows_in_tabs": true,
298 // "max_tabs": 20
299 // }
300 // }
301
[email protected]3703e922013-05-31 21:37:53302 RunBasicJsonPrefStoreTest(
303 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
[email protected]845b43a82011-05-11 10:14:43304}
305
[email protected]aa3283392013-11-27 01:38:24306TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
307 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
308
[email protected]56cbcb3a2013-12-23 21:24:46309 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15310 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]aa3283392013-11-27 01:38:24311
312 // Set some keys with empty values.
313 pref_store->SetValue("list", new base::ListValue);
314 pref_store->SetValue("dict", new base::DictionaryValue);
315
316 // Write to file.
317 pref_store->CommitPendingWrite();
318 MessageLoop::current()->RunUntilIdle();
319
320 // Reload.
skyostil054861d2015-04-30 19:06:15321 pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
322 scoped_ptr<PrefFilter>());
[email protected]aa3283392013-11-27 01:38:24323 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
324 ASSERT_FALSE(pref_store->ReadOnly());
325
326 // Check values.
327 const Value* result = NULL;
328 EXPECT_TRUE(pref_store->GetValue("list", &result));
329 EXPECT_TRUE(ListValue().Equals(result));
330 EXPECT_TRUE(pref_store->GetValue("dict", &result));
331 EXPECT_TRUE(DictionaryValue().Equals(result));
332}
333
[email protected]eeedaa692014-01-30 09:22:27334// This test is just documenting some potentially non-obvious behavior. It
335// shouldn't be taken as normative.
336TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
337 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
338
339 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15340 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]eeedaa692014-01-30 09:22:27341
342 base::DictionaryValue* dict = new base::DictionaryValue;
343 dict->SetString("key", "value");
344 pref_store->SetValue("dict", dict);
345
346 pref_store->RemoveValue("dict.key");
347
348 const base::Value* retrieved_dict = NULL;
349 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
350 EXPECT_FALSE(has_dict);
351}
352
[email protected]845b43a82011-05-11 10:14:43353// Tests asynchronous reading of the file when there is no file.
354TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
[email protected]023ad6ab2013-02-17 05:07:23355 base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
[email protected]7567484142013-07-11 17:36:07356 ASSERT_FALSE(PathExists(bogus_input_file));
[email protected]cadac622013-06-11 16:46:36357 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
skyostil054861d2015-04-30 19:06:15358 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]845b43a82011-05-11 10:14:43359 MockPrefStoreObserver mock_observer;
360 pref_store->AddObserver(&mock_observer);
361
362 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
363 pref_store->ReadPrefsAsync(mock_error_delegate);
364
365 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
366 EXPECT_CALL(*mock_error_delegate,
367 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
[email protected]7ff48ca2013-02-06 16:56:19368 RunLoop().RunUntilIdle();
[email protected]845b43a82011-05-11 10:14:43369 pref_store->RemoveObserver(&mock_observer);
370
371 EXPECT_FALSE(pref_store->ReadOnly());
372}
[email protected]ea3e4972012-04-12 03:41:37373
[email protected]e33c9512014-05-12 02:24:13374TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
375 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
376 temp_dir_.path().AppendASCII("write.json")));
377
378 // Test that the persistent value can be loaded.
379 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
380 ASSERT_TRUE(PathExists(input_file));
381
382 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
383 new InterceptingPrefFilter());
384 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
385 intercepting_pref_filter.get();
skyostil054861d2015-04-30 19:06:15386 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
387 input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
[email protected]e33c9512014-05-12 02:24:13388
389 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
390 pref_store->ReadPrefs());
391 EXPECT_FALSE(pref_store->ReadOnly());
392
393 // The store shouldn't be considered initialized until the interceptor
394 // returns.
395 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
396 EXPECT_FALSE(pref_store->IsInitializationComplete());
397 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
398
399 raw_intercepting_pref_filter_->ReleasePrefs();
400
401 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
402 EXPECT_TRUE(pref_store->IsInitializationComplete());
403 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
404
405 // The JSON file looks like this:
406 // {
407 // "homepage": "http://www.cnn.com",
408 // "some_directory": "/usr/local/",
409 // "tabs": {
410 // "new_windows_in_tabs": true,
411 // "max_tabs": 20
412 // }
413 // }
414
415 RunBasicJsonPrefStoreTest(
416 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
417}
418
419TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
420 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
421 temp_dir_.path().AppendASCII("write.json")));
422
423 // Test that the persistent value can be loaded.
424 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
425 ASSERT_TRUE(PathExists(input_file));
426
427 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
428 new InterceptingPrefFilter());
429 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
430 intercepting_pref_filter.get();
skyostil054861d2015-04-30 19:06:15431 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
432 input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
[email protected]e33c9512014-05-12 02:24:13433
434 MockPrefStoreObserver mock_observer;
435 pref_store->AddObserver(&mock_observer);
436
437 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
438 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
439
440 {
441 pref_store->ReadPrefsAsync(mock_error_delegate);
442
443 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
444 // EXPECT_CALL(*mock_error_delegate,
445 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
446 RunLoop().RunUntilIdle();
447
448 EXPECT_FALSE(pref_store->ReadOnly());
449 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
450 EXPECT_FALSE(pref_store->IsInitializationComplete());
451 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
452 }
453
454 {
455 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
456 // EXPECT_CALL(*mock_error_delegate,
457 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
458
459 raw_intercepting_pref_filter_->ReleasePrefs();
460
461 EXPECT_FALSE(pref_store->ReadOnly());
462 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
463 EXPECT_TRUE(pref_store->IsInitializationComplete());
464 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
465 }
466
467 pref_store->RemoveObserver(&mock_observer);
468
469 // The JSON file looks like this:
470 // {
471 // "homepage": "http://www.cnn.com",
472 // "some_directory": "/usr/local/",
473 // "tabs": {
474 // "new_windows_in_tabs": true,
475 // "max_tabs": 20
476 // }
477 // }
478
479 RunBasicJsonPrefStoreTest(
480 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
481}
482
[email protected]cfcf0e52014-06-20 18:29:47483TEST_F(JsonPrefStoreTest, AlternateFile) {
484 ASSERT_TRUE(
485 base::CopyFile(data_dir_.AppendASCII("read.json"),
486 temp_dir_.path().AppendASCII("alternate.json")));
487
488 // Test that the alternate file is moved to the main file and read as-is from
489 // there.
490 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
491 base::FilePath alternate_input_file =
492 temp_dir_.path().AppendASCII("alternate.json");
493 ASSERT_FALSE(PathExists(input_file));
494 ASSERT_TRUE(PathExists(alternate_input_file));
skyostil054861d2015-04-30 19:06:15495 scoped_refptr<JsonPrefStore> pref_store =
496 new JsonPrefStore(input_file, alternate_input_file,
497 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47498
499 ASSERT_FALSE(PathExists(input_file));
500 ASSERT_TRUE(PathExists(alternate_input_file));
501 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
502
503 ASSERT_TRUE(PathExists(input_file));
504 ASSERT_FALSE(PathExists(alternate_input_file));
505
506 EXPECT_FALSE(pref_store->ReadOnly());
507 EXPECT_TRUE(pref_store->IsInitializationComplete());
508
509 // The JSON file looks like this:
510 // {
511 // "homepage": "http://www.cnn.com",
512 // "some_directory": "/usr/local/",
513 // "tabs": {
514 // "new_windows_in_tabs": true,
515 // "max_tabs": 20
516 // }
517 // }
518
519 RunBasicJsonPrefStoreTest(
520 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
521}
522
523TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
524 ASSERT_TRUE(
525 base::CopyFile(data_dir_.AppendASCII("read.json"),
526 temp_dir_.path().AppendASCII("write.json")));
527 ASSERT_TRUE(
528 base::CopyFile(data_dir_.AppendASCII("invalid.json"),
529 temp_dir_.path().AppendASCII("alternate.json")));
530
531 // Test that the alternate file is ignored and that the read occurs from the
532 // existing main file. There is no attempt at even deleting the alternate
533 // file as this scenario should never happen in normal user-data-dirs.
534 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
535 base::FilePath alternate_input_file =
536 temp_dir_.path().AppendASCII("alternate.json");
537 ASSERT_TRUE(PathExists(input_file));
538 ASSERT_TRUE(PathExists(alternate_input_file));
skyostil054861d2015-04-30 19:06:15539 scoped_refptr<JsonPrefStore> pref_store =
540 new JsonPrefStore(input_file, alternate_input_file,
541 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47542
543 ASSERT_TRUE(PathExists(input_file));
544 ASSERT_TRUE(PathExists(alternate_input_file));
545 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
546
547 ASSERT_TRUE(PathExists(input_file));
548 ASSERT_TRUE(PathExists(alternate_input_file));
549
550 EXPECT_FALSE(pref_store->ReadOnly());
551 EXPECT_TRUE(pref_store->IsInitializationComplete());
552
553 // The JSON file looks like this:
554 // {
555 // "homepage": "http://www.cnn.com",
556 // "some_directory": "/usr/local/",
557 // "tabs": {
558 // "new_windows_in_tabs": true,
559 // "max_tabs": 20
560 // }
561 // }
562
563 RunBasicJsonPrefStoreTest(
564 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
565}
566
567TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
568 ASSERT_TRUE(
569 base::CopyFile(data_dir_.AppendASCII("read.json"),
570 temp_dir_.path().AppendASCII("write.json")));
571
572 // Test that the basic read works fine when an alternate file is specified but
573 // does not exist.
574 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
575 base::FilePath alternate_input_file =
576 temp_dir_.path().AppendASCII("alternate.json");
577 ASSERT_TRUE(PathExists(input_file));
578 ASSERT_FALSE(PathExists(alternate_input_file));
skyostil054861d2015-04-30 19:06:15579 scoped_refptr<JsonPrefStore> pref_store =
580 new JsonPrefStore(input_file, alternate_input_file,
581 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47582
583 ASSERT_TRUE(PathExists(input_file));
584 ASSERT_FALSE(PathExists(alternate_input_file));
585 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
586
587 ASSERT_TRUE(PathExists(input_file));
588 ASSERT_FALSE(PathExists(alternate_input_file));
589
590 EXPECT_FALSE(pref_store->ReadOnly());
591 EXPECT_TRUE(pref_store->IsInitializationComplete());
592
593 // The JSON file looks like this:
594 // {
595 // "homepage": "http://www.cnn.com",
596 // "some_directory": "/usr/local/",
597 // "tabs": {
598 // "new_windows_in_tabs": true,
599 // "max_tabs": 20
600 // }
601 // }
602
603 RunBasicJsonPrefStoreTest(
604 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
605}
606
607TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
608 ASSERT_TRUE(
609 base::CopyFile(data_dir_.AppendASCII("read.json"),
610 temp_dir_.path().AppendASCII("alternate.json")));
611
612 // Test that the alternate file is moved to the main file and read as-is from
613 // there even when the read is made asynchronously.
614 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
615 base::FilePath alternate_input_file =
616 temp_dir_.path().AppendASCII("alternate.json");
617 ASSERT_FALSE(PathExists(input_file));
618 ASSERT_TRUE(PathExists(alternate_input_file));
skyostil054861d2015-04-30 19:06:15619 scoped_refptr<JsonPrefStore> pref_store =
620 new JsonPrefStore(input_file, alternate_input_file,
621 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
[email protected]cfcf0e52014-06-20 18:29:47622
623 ASSERT_FALSE(PathExists(input_file));
624 ASSERT_TRUE(PathExists(alternate_input_file));
625
626 {
627 MockPrefStoreObserver mock_observer;
628 pref_store->AddObserver(&mock_observer);
629
630 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
631 pref_store->ReadPrefsAsync(mock_error_delegate);
632
633 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
634 EXPECT_CALL(*mock_error_delegate,
635 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
636 RunLoop().RunUntilIdle();
637 pref_store->RemoveObserver(&mock_observer);
638
639 EXPECT_FALSE(pref_store->ReadOnly());
640 EXPECT_TRUE(pref_store->IsInitializationComplete());
641 }
642
643 ASSERT_TRUE(PathExists(input_file));
644 ASSERT_FALSE(PathExists(alternate_input_file));
645
646 // The JSON file looks like this:
647 // {
648 // "homepage": "http://www.cnn.com",
649 // "some_directory": "/usr/local/",
650 // "tabs": {
651 // "new_windows_in_tabs": true,
652 // "max_tabs": 20
653 // }
654 // }
655
656 RunBasicJsonPrefStoreTest(
657 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
658}
659
raymesbfb910a2015-04-29 07:43:09660TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
661 SimpleTestClock* test_clock = new SimpleTestClock;
662 SetCurrentTimeInMinutes(0, test_clock);
663 JsonPrefStore::WriteCountHistogram histogram(
664 base::TimeDelta::FromSeconds(10),
665 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
666 scoped_ptr<base::Clock>(test_clock));
667 int32 report_interval =
668 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
669
670 histogram.RecordWriteOccured();
671
672 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
673 histogram.ReportOutstandingWrites();
674 scoped_ptr<HistogramSamples> samples =
675 histogram.GetHistogram()->SnapshotSamples();
676 ASSERT_EQ(1, samples->GetCount(1));
677 ASSERT_EQ(1, samples->TotalCount());
678
679 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
680 histogram.GetHistogram()->histogram_name());
681 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
682}
683
684TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
685 SimpleTestClock* test_clock = new SimpleTestClock;
686 SetCurrentTimeInMinutes(0, test_clock);
687 JsonPrefStore::WriteCountHistogram histogram(
688 base::TimeDelta::FromSeconds(10),
689 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
690 scoped_ptr<base::Clock>(test_clock));
691 int32 report_interval =
692 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
693
694 histogram.RecordWriteOccured();
695 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
696 histogram.RecordWriteOccured();
697 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
698 histogram.RecordWriteOccured();
699
700 // Nothing should be recorded until the report period has elapsed.
701 scoped_ptr<HistogramSamples> samples =
702 histogram.GetHistogram()->SnapshotSamples();
703 ASSERT_EQ(0, samples->TotalCount());
704
705 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
706 histogram.RecordWriteOccured();
707
708 // Now the report period has elapsed.
709 samples = histogram.GetHistogram()->SnapshotSamples();
710 ASSERT_EQ(1, samples->GetCount(3));
711 ASSERT_EQ(1, samples->TotalCount());
712
713 // The last write won't be recorded because the second count period hasn't
714 // fully elapsed.
715 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
716 histogram.ReportOutstandingWrites();
717
718 samples = histogram.GetHistogram()->SnapshotSamples();
719 ASSERT_EQ(1, samples->GetCount(3));
720 ASSERT_EQ(1, samples->TotalCount());
721}
722
723TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
724 SimpleTestClock* test_clock = new SimpleTestClock;
725 SetCurrentTimeInMinutes(0, test_clock);
726 JsonPrefStore::WriteCountHistogram histogram(
727 base::TimeDelta::FromSeconds(10),
728 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
729 scoped_ptr<base::Clock>(test_clock));
730 int32 report_interval =
731 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
732
733 histogram.RecordWriteOccured();
734 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
735 histogram.RecordWriteOccured();
736 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
737 histogram.RecordWriteOccured();
738 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
739 histogram.RecordWriteOccured();
740 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
741 histogram.RecordWriteOccured();
742 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
743 histogram.RecordWriteOccured();
744 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
745 histogram.RecordWriteOccured();
746 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
747 histogram.RecordWriteOccured();
748 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
749 histogram.RecordWriteOccured();
750
751 // The last write won't be recorded because the second count period hasn't
752 // fully elapsed
753 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
754 histogram.ReportOutstandingWrites();
755 scoped_ptr<HistogramSamples> samples =
756 histogram.GetHistogram()->SnapshotSamples();
757 ASSERT_EQ(2, samples->GetCount(3));
758 ASSERT_EQ(1, samples->GetCount(2));
759 ASSERT_EQ(3, samples->TotalCount());
760}
761
762TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
763 SimpleTestClock* test_clock = new SimpleTestClock;
764 SetCurrentTimeInMinutes(0, test_clock);
765 JsonPrefStore::WriteCountHistogram histogram(
766 base::TimeDelta::FromSeconds(10),
767 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
768 scoped_ptr<base::Clock>(test_clock));
769 int32 report_interval =
770 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
771
772 // 1 write in the first period.
773 histogram.RecordWriteOccured();
774
775 // No writes in the second and third periods.
776
777 // 2 writes in the fourth period.
778 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
779 histogram.RecordWriteOccured();
780 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
781 histogram.RecordWriteOccured();
782
783 // No writes in the fifth period.
784
785 // 3 writes in the sixth period.
786 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
787 histogram.RecordWriteOccured();
788 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
789 histogram.RecordWriteOccured();
790 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
791 histogram.RecordWriteOccured();
792
793 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
794 histogram.ReportOutstandingWrites();
795 scoped_ptr<HistogramSamples> samples =
796 histogram.GetHistogram()->SnapshotSamples();
797 ASSERT_EQ(3, samples->GetCount(0));
798 ASSERT_EQ(1, samples->GetCount(1));
799 ASSERT_EQ(1, samples->GetCount(2));
800 ASSERT_EQ(1, samples->GetCount(3));
801 ASSERT_EQ(6, samples->TotalCount());
802}
803
[email protected]7e3ec42c2012-12-16 05:13:21804} // namespace base