Remove AccountManagerDelegate.removeAccount()
[chromium-blink-merge.git] / base / prefs / json_pref_store_unittest.cc
blob67a8adbb4d4f93bca61d964ace97353736345f3f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/prefs/json_pref_store.h"
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/location.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram_samples.h"
15 #include "base/metrics/statistics_recorder.h"
16 #include "base/path_service.h"
17 #include "base/prefs/pref_filter.h"
18 #include "base/run_loop.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/test/simple_test_clock.h"
24 #include "base/threading/sequenced_worker_pool.h"
25 #include "base/threading/thread.h"
26 #include "base/values.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
30 namespace base {
31 namespace {
33 const char kHomePage[] = "homepage";
35 // Set the time on the given SimpleTestClock to the given time in minutes.
36 void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
37 const int32_t kBaseTimeMins = 100;
38 clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
41 // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
42 // to the |prefs| until explicitly asked to release them.
43 class InterceptingPrefFilter : public PrefFilter {
44 public:
45 InterceptingPrefFilter();
46 ~InterceptingPrefFilter() override;
48 // PrefFilter implementation:
49 void FilterOnLoad(
50 const PostFilterOnLoadCallback& post_filter_on_load_callback,
51 scoped_ptr<base::DictionaryValue> pref_store_contents) override;
52 void FilterUpdate(const std::string& path) override {}
53 void FilterSerializeData(
54 base::DictionaryValue* pref_store_contents) override {}
56 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
58 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
59 // JsonPrefStore.
60 void ReleasePrefs();
62 private:
63 PostFilterOnLoadCallback post_filter_on_load_callback_;
64 scoped_ptr<base::DictionaryValue> intercepted_prefs_;
66 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
69 InterceptingPrefFilter::InterceptingPrefFilter() {}
70 InterceptingPrefFilter::~InterceptingPrefFilter() {}
72 void 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();
79 void 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();
85 class MockPrefStoreObserver : public PrefStore::Observer {
86 public:
87 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
88 MOCK_METHOD1(OnInitializationCompleted, void (bool));
91 class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
92 public:
93 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
96 } // namespace
98 class JsonPrefStoreTest : public testing::Test {
99 protected:
100 void SetUp() override {
101 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
103 ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
104 data_dir_ = data_dir_.AppendASCII("prefs");
105 ASSERT_TRUE(PathExists(data_dir_));
108 void TearDown() override {
109 // Make sure all pending tasks have been processed (e.g., deleting the
110 // JsonPrefStore may post write tasks).
111 RunLoop().RunUntilIdle();
114 // The path to temporary directory used to contain the test operations.
115 base::ScopedTempDir temp_dir_;
116 // The path to the directory where the test data is stored.
117 base::FilePath data_dir_;
118 // A message loop that we can use as the file thread message loop.
119 MessageLoop message_loop_;
121 private:
122 // Ensure histograms are reset for each test.
123 StatisticsRecorder statistics_recorder_;
126 // Test fallback behavior for a nonexistent file.
127 TEST_F(JsonPrefStoreTest, NonExistentFile) {
128 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
129 ASSERT_FALSE(PathExists(bogus_input_file));
130 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
131 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
132 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
133 pref_store->ReadPrefs());
134 EXPECT_FALSE(pref_store->ReadOnly());
137 // Test fallback behavior for a nonexistent file and alternate file.
138 TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
139 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
140 base::FilePath bogus_alternate_input_file =
141 temp_dir_.path().AppendASCII("read_alternate.txt");
142 ASSERT_FALSE(PathExists(bogus_input_file));
143 ASSERT_FALSE(PathExists(bogus_alternate_input_file));
144 scoped_refptr<JsonPrefStore> pref_store =
145 new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
146 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
147 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
148 pref_store->ReadPrefs());
149 EXPECT_FALSE(pref_store->ReadOnly());
152 // Test fallback behavior for an invalid file.
153 TEST_F(JsonPrefStoreTest, InvalidFile) {
154 base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
155 base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
156 ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
157 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
158 invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
159 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
160 pref_store->ReadPrefs());
161 EXPECT_FALSE(pref_store->ReadOnly());
163 // The file should have been moved aside.
164 EXPECT_FALSE(PathExists(invalid_file));
165 base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
166 EXPECT_TRUE(PathExists(moved_aside));
167 EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside));
170 // This function is used to avoid code duplication while testing synchronous and
171 // asynchronous version of the JsonPrefStore loading.
172 void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
173 const base::FilePath& output_file,
174 const base::FilePath& golden_output_file) {
175 const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
176 const char kMaxTabs[] = "tabs.max_tabs";
177 const char kLongIntPref[] = "long_int.pref";
179 std::string cnn("http://www.cnn.com");
181 const Value* actual;
182 EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
183 std::string string_value;
184 EXPECT_TRUE(actual->GetAsString(&string_value));
185 EXPECT_EQ(cnn, string_value);
187 const char kSomeDirectory[] = "some_directory";
189 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
190 base::FilePath::StringType path;
191 EXPECT_TRUE(actual->GetAsString(&path));
192 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
193 base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
195 pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()),
196 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
197 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
198 EXPECT_TRUE(actual->GetAsString(&path));
199 EXPECT_EQ(some_path.value(), path);
201 // Test reading some other data types from sub-dictionaries.
202 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
203 bool boolean = false;
204 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
205 EXPECT_TRUE(boolean);
207 pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
208 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
209 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
210 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
211 EXPECT_FALSE(boolean);
213 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
214 int integer = 0;
215 EXPECT_TRUE(actual->GetAsInteger(&integer));
216 EXPECT_EQ(20, integer);
217 pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
218 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
219 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
220 EXPECT_TRUE(actual->GetAsInteger(&integer));
221 EXPECT_EQ(10, integer);
223 pref_store->SetValue(kLongIntPref,
224 new StringValue(base::Int64ToString(214748364842LL)),
225 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
226 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
227 EXPECT_TRUE(actual->GetAsString(&string_value));
228 int64 value;
229 base::StringToInt64(string_value, &value);
230 EXPECT_EQ(214748364842LL, value);
232 // Serialize and compare to expected output.
233 ASSERT_TRUE(PathExists(golden_output_file));
234 pref_store->CommitPendingWrite();
235 RunLoop().RunUntilIdle();
236 EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file));
237 ASSERT_TRUE(base::DeleteFile(output_file, false));
240 TEST_F(JsonPrefStoreTest, Basic) {
241 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
242 temp_dir_.path().AppendASCII("write.json")));
244 // Test that the persistent value can be loaded.
245 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
246 ASSERT_TRUE(PathExists(input_file));
247 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
248 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
249 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
250 EXPECT_FALSE(pref_store->ReadOnly());
251 EXPECT_TRUE(pref_store->IsInitializationComplete());
253 // The JSON file looks like this:
254 // {
255 // "homepage": "http://www.cnn.com",
256 // "some_directory": "/usr/local/",
257 // "tabs": {
258 // "new_windows_in_tabs": true,
259 // "max_tabs": 20
260 // }
261 // }
263 RunBasicJsonPrefStoreTest(
264 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
267 TEST_F(JsonPrefStoreTest, BasicAsync) {
268 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
269 temp_dir_.path().AppendASCII("write.json")));
271 // Test that the persistent value can be loaded.
272 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
273 ASSERT_TRUE(PathExists(input_file));
274 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
275 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
278 MockPrefStoreObserver mock_observer;
279 pref_store->AddObserver(&mock_observer);
281 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
282 pref_store->ReadPrefsAsync(mock_error_delegate);
284 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
285 EXPECT_CALL(*mock_error_delegate,
286 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
287 RunLoop().RunUntilIdle();
288 pref_store->RemoveObserver(&mock_observer);
290 EXPECT_FALSE(pref_store->ReadOnly());
291 EXPECT_TRUE(pref_store->IsInitializationComplete());
294 // The JSON file looks like this:
295 // {
296 // "homepage": "http://www.cnn.com",
297 // "some_directory": "/usr/local/",
298 // "tabs": {
299 // "new_windows_in_tabs": true,
300 // "max_tabs": 20
301 // }
302 // }
304 RunBasicJsonPrefStoreTest(
305 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
308 TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
309 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
311 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
312 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
314 // Set some keys with empty values.
315 pref_store->SetValue("list", new base::ListValue,
316 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
317 pref_store->SetValue("dict", new base::DictionaryValue,
318 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
320 // Write to file.
321 pref_store->CommitPendingWrite();
322 RunLoop().RunUntilIdle();
324 // Reload.
325 pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
326 scoped_ptr<PrefFilter>());
327 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
328 ASSERT_FALSE(pref_store->ReadOnly());
330 // Check values.
331 const Value* result = NULL;
332 EXPECT_TRUE(pref_store->GetValue("list", &result));
333 EXPECT_TRUE(ListValue().Equals(result));
334 EXPECT_TRUE(pref_store->GetValue("dict", &result));
335 EXPECT_TRUE(DictionaryValue().Equals(result));
338 // This test is just documenting some potentially non-obvious behavior. It
339 // shouldn't be taken as normative.
340 TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
341 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
343 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
344 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
346 base::DictionaryValue* dict = new base::DictionaryValue;
347 dict->SetString("key", "value");
348 pref_store->SetValue("dict", dict,
349 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
351 pref_store->RemoveValue("dict.key",
352 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
354 const base::Value* retrieved_dict = NULL;
355 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
356 EXPECT_FALSE(has_dict);
359 // Tests asynchronous reading of the file when there is no file.
360 TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
361 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
362 ASSERT_FALSE(PathExists(bogus_input_file));
363 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
364 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
365 MockPrefStoreObserver mock_observer;
366 pref_store->AddObserver(&mock_observer);
368 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
369 pref_store->ReadPrefsAsync(mock_error_delegate);
371 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
372 EXPECT_CALL(*mock_error_delegate,
373 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
374 RunLoop().RunUntilIdle();
375 pref_store->RemoveObserver(&mock_observer);
377 EXPECT_FALSE(pref_store->ReadOnly());
380 TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
381 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
382 temp_dir_.path().AppendASCII("write.json")));
384 // Test that the persistent value can be loaded.
385 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
386 ASSERT_TRUE(PathExists(input_file));
388 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
389 new InterceptingPrefFilter());
390 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
391 intercepting_pref_filter.get();
392 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
393 input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
395 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
396 pref_store->ReadPrefs());
397 EXPECT_FALSE(pref_store->ReadOnly());
399 // The store shouldn't be considered initialized until the interceptor
400 // returns.
401 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
402 EXPECT_FALSE(pref_store->IsInitializationComplete());
403 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
405 raw_intercepting_pref_filter_->ReleasePrefs();
407 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
408 EXPECT_TRUE(pref_store->IsInitializationComplete());
409 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
411 // The JSON file looks like this:
412 // {
413 // "homepage": "http://www.cnn.com",
414 // "some_directory": "/usr/local/",
415 // "tabs": {
416 // "new_windows_in_tabs": true,
417 // "max_tabs": 20
418 // }
419 // }
421 RunBasicJsonPrefStoreTest(
422 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
425 TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
426 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
427 temp_dir_.path().AppendASCII("write.json")));
429 // Test that the persistent value can be loaded.
430 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
431 ASSERT_TRUE(PathExists(input_file));
433 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
434 new InterceptingPrefFilter());
435 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
436 intercepting_pref_filter.get();
437 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
438 input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
440 MockPrefStoreObserver mock_observer;
441 pref_store->AddObserver(&mock_observer);
443 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
444 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
447 pref_store->ReadPrefsAsync(mock_error_delegate);
449 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
450 // EXPECT_CALL(*mock_error_delegate,
451 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
452 RunLoop().RunUntilIdle();
454 EXPECT_FALSE(pref_store->ReadOnly());
455 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
456 EXPECT_FALSE(pref_store->IsInitializationComplete());
457 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
461 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
462 // EXPECT_CALL(*mock_error_delegate,
463 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
465 raw_intercepting_pref_filter_->ReleasePrefs();
467 EXPECT_FALSE(pref_store->ReadOnly());
468 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
469 EXPECT_TRUE(pref_store->IsInitializationComplete());
470 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
473 pref_store->RemoveObserver(&mock_observer);
475 // The JSON file looks like this:
476 // {
477 // "homepage": "http://www.cnn.com",
478 // "some_directory": "/usr/local/",
479 // "tabs": {
480 // "new_windows_in_tabs": true,
481 // "max_tabs": 20
482 // }
483 // }
485 RunBasicJsonPrefStoreTest(
486 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
489 TEST_F(JsonPrefStoreTest, AlternateFile) {
490 ASSERT_TRUE(
491 base::CopyFile(data_dir_.AppendASCII("read.json"),
492 temp_dir_.path().AppendASCII("alternate.json")));
494 // Test that the alternate file is moved to the main file and read as-is from
495 // there.
496 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
497 base::FilePath alternate_input_file =
498 temp_dir_.path().AppendASCII("alternate.json");
499 ASSERT_FALSE(PathExists(input_file));
500 ASSERT_TRUE(PathExists(alternate_input_file));
501 scoped_refptr<JsonPrefStore> pref_store =
502 new JsonPrefStore(input_file, alternate_input_file,
503 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
505 ASSERT_FALSE(PathExists(input_file));
506 ASSERT_TRUE(PathExists(alternate_input_file));
507 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
509 ASSERT_TRUE(PathExists(input_file));
510 ASSERT_FALSE(PathExists(alternate_input_file));
512 EXPECT_FALSE(pref_store->ReadOnly());
513 EXPECT_TRUE(pref_store->IsInitializationComplete());
515 // The JSON file looks like this:
516 // {
517 // "homepage": "http://www.cnn.com",
518 // "some_directory": "/usr/local/",
519 // "tabs": {
520 // "new_windows_in_tabs": true,
521 // "max_tabs": 20
522 // }
523 // }
525 RunBasicJsonPrefStoreTest(
526 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
529 TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
530 ASSERT_TRUE(
531 base::CopyFile(data_dir_.AppendASCII("read.json"),
532 temp_dir_.path().AppendASCII("write.json")));
533 ASSERT_TRUE(
534 base::CopyFile(data_dir_.AppendASCII("invalid.json"),
535 temp_dir_.path().AppendASCII("alternate.json")));
537 // Test that the alternate file is ignored and that the read occurs from the
538 // existing main file. There is no attempt at even deleting the alternate
539 // file as this scenario should never happen in normal user-data-dirs.
540 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
541 base::FilePath alternate_input_file =
542 temp_dir_.path().AppendASCII("alternate.json");
543 ASSERT_TRUE(PathExists(input_file));
544 ASSERT_TRUE(PathExists(alternate_input_file));
545 scoped_refptr<JsonPrefStore> pref_store =
546 new JsonPrefStore(input_file, alternate_input_file,
547 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
549 ASSERT_TRUE(PathExists(input_file));
550 ASSERT_TRUE(PathExists(alternate_input_file));
551 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
553 ASSERT_TRUE(PathExists(input_file));
554 ASSERT_TRUE(PathExists(alternate_input_file));
556 EXPECT_FALSE(pref_store->ReadOnly());
557 EXPECT_TRUE(pref_store->IsInitializationComplete());
559 // The JSON file looks like this:
560 // {
561 // "homepage": "http://www.cnn.com",
562 // "some_directory": "/usr/local/",
563 // "tabs": {
564 // "new_windows_in_tabs": true,
565 // "max_tabs": 20
566 // }
567 // }
569 RunBasicJsonPrefStoreTest(
570 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
573 TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
574 ASSERT_TRUE(
575 base::CopyFile(data_dir_.AppendASCII("read.json"),
576 temp_dir_.path().AppendASCII("write.json")));
578 // Test that the basic read works fine when an alternate file is specified but
579 // does not exist.
580 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
581 base::FilePath alternate_input_file =
582 temp_dir_.path().AppendASCII("alternate.json");
583 ASSERT_TRUE(PathExists(input_file));
584 ASSERT_FALSE(PathExists(alternate_input_file));
585 scoped_refptr<JsonPrefStore> pref_store =
586 new JsonPrefStore(input_file, alternate_input_file,
587 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
589 ASSERT_TRUE(PathExists(input_file));
590 ASSERT_FALSE(PathExists(alternate_input_file));
591 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
593 ASSERT_TRUE(PathExists(input_file));
594 ASSERT_FALSE(PathExists(alternate_input_file));
596 EXPECT_FALSE(pref_store->ReadOnly());
597 EXPECT_TRUE(pref_store->IsInitializationComplete());
599 // The JSON file looks like this:
600 // {
601 // "homepage": "http://www.cnn.com",
602 // "some_directory": "/usr/local/",
603 // "tabs": {
604 // "new_windows_in_tabs": true,
605 // "max_tabs": 20
606 // }
607 // }
609 RunBasicJsonPrefStoreTest(
610 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
613 TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
614 ASSERT_TRUE(
615 base::CopyFile(data_dir_.AppendASCII("read.json"),
616 temp_dir_.path().AppendASCII("alternate.json")));
618 // Test that the alternate file is moved to the main file and read as-is from
619 // there even when the read is made asynchronously.
620 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
621 base::FilePath alternate_input_file =
622 temp_dir_.path().AppendASCII("alternate.json");
623 ASSERT_FALSE(PathExists(input_file));
624 ASSERT_TRUE(PathExists(alternate_input_file));
625 scoped_refptr<JsonPrefStore> pref_store =
626 new JsonPrefStore(input_file, alternate_input_file,
627 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
629 ASSERT_FALSE(PathExists(input_file));
630 ASSERT_TRUE(PathExists(alternate_input_file));
633 MockPrefStoreObserver mock_observer;
634 pref_store->AddObserver(&mock_observer);
636 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
637 pref_store->ReadPrefsAsync(mock_error_delegate);
639 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
640 EXPECT_CALL(*mock_error_delegate,
641 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
642 RunLoop().RunUntilIdle();
643 pref_store->RemoveObserver(&mock_observer);
645 EXPECT_FALSE(pref_store->ReadOnly());
646 EXPECT_TRUE(pref_store->IsInitializationComplete());
649 ASSERT_TRUE(PathExists(input_file));
650 ASSERT_FALSE(PathExists(alternate_input_file));
652 // The JSON file looks like this:
653 // {
654 // "homepage": "http://www.cnn.com",
655 // "some_directory": "/usr/local/",
656 // "tabs": {
657 // "new_windows_in_tabs": true,
658 // "max_tabs": 20
659 // }
660 // }
662 RunBasicJsonPrefStoreTest(
663 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
666 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
667 SimpleTestClock* test_clock = new SimpleTestClock;
668 SetCurrentTimeInMinutes(0, test_clock);
669 JsonPrefStore::WriteCountHistogram histogram(
670 base::TimeDelta::FromSeconds(10),
671 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
672 scoped_ptr<base::Clock>(test_clock));
673 int32 report_interval =
674 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
676 histogram.RecordWriteOccured();
678 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
679 histogram.ReportOutstandingWrites();
680 scoped_ptr<HistogramSamples> samples =
681 histogram.GetHistogram()->SnapshotSamples();
682 ASSERT_EQ(1, samples->GetCount(1));
683 ASSERT_EQ(1, samples->TotalCount());
685 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
686 histogram.GetHistogram()->histogram_name());
687 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
690 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
691 SimpleTestClock* test_clock = new SimpleTestClock;
692 SetCurrentTimeInMinutes(0, test_clock);
693 JsonPrefStore::WriteCountHistogram histogram(
694 base::TimeDelta::FromSeconds(10),
695 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
696 scoped_ptr<base::Clock>(test_clock));
697 int32 report_interval =
698 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
700 histogram.RecordWriteOccured();
701 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
702 histogram.RecordWriteOccured();
703 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
704 histogram.RecordWriteOccured();
706 // Nothing should be recorded until the report period has elapsed.
707 scoped_ptr<HistogramSamples> samples =
708 histogram.GetHistogram()->SnapshotSamples();
709 ASSERT_EQ(0, samples->TotalCount());
711 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
712 histogram.RecordWriteOccured();
714 // Now the report period has elapsed.
715 samples = histogram.GetHistogram()->SnapshotSamples();
716 ASSERT_EQ(1, samples->GetCount(3));
717 ASSERT_EQ(1, samples->TotalCount());
719 // The last write won't be recorded because the second count period hasn't
720 // fully elapsed.
721 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
722 histogram.ReportOutstandingWrites();
724 samples = histogram.GetHistogram()->SnapshotSamples();
725 ASSERT_EQ(1, samples->GetCount(3));
726 ASSERT_EQ(1, samples->TotalCount());
729 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
730 SimpleTestClock* test_clock = new SimpleTestClock;
731 SetCurrentTimeInMinutes(0, test_clock);
732 JsonPrefStore::WriteCountHistogram histogram(
733 base::TimeDelta::FromSeconds(10),
734 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
735 scoped_ptr<base::Clock>(test_clock));
736 int32 report_interval =
737 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
739 histogram.RecordWriteOccured();
740 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
741 histogram.RecordWriteOccured();
742 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
743 histogram.RecordWriteOccured();
744 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
745 histogram.RecordWriteOccured();
746 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
747 histogram.RecordWriteOccured();
748 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
749 histogram.RecordWriteOccured();
750 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
751 histogram.RecordWriteOccured();
752 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
753 histogram.RecordWriteOccured();
754 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
755 histogram.RecordWriteOccured();
757 // The last write won't be recorded because the second count period hasn't
758 // fully elapsed
759 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
760 histogram.ReportOutstandingWrites();
761 scoped_ptr<HistogramSamples> samples =
762 histogram.GetHistogram()->SnapshotSamples();
763 ASSERT_EQ(2, samples->GetCount(3));
764 ASSERT_EQ(1, samples->GetCount(2));
765 ASSERT_EQ(3, samples->TotalCount());
768 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
769 SimpleTestClock* test_clock = new SimpleTestClock;
770 SetCurrentTimeInMinutes(0, test_clock);
771 JsonPrefStore::WriteCountHistogram histogram(
772 base::TimeDelta::FromSeconds(10),
773 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
774 scoped_ptr<base::Clock>(test_clock));
775 int32 report_interval =
776 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
778 // 1 write in the first period.
779 histogram.RecordWriteOccured();
781 // No writes in the second and third periods.
783 // 2 writes in the fourth period.
784 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
785 histogram.RecordWriteOccured();
786 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
787 histogram.RecordWriteOccured();
789 // No writes in the fifth period.
791 // 3 writes in the sixth period.
792 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
793 histogram.RecordWriteOccured();
794 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
795 histogram.RecordWriteOccured();
796 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
797 histogram.RecordWriteOccured();
799 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
800 histogram.ReportOutstandingWrites();
801 scoped_ptr<HistogramSamples> samples =
802 histogram.GetHistogram()->SnapshotSamples();
803 ASSERT_EQ(3, samples->GetCount(0));
804 ASSERT_EQ(1, samples->GetCount(1));
805 ASSERT_EQ(1, samples->GetCount(2));
806 ASSERT_EQ(1, samples->GetCount(3));
807 ASSERT_EQ(6, samples->TotalCount());
810 class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
811 protected:
812 void SetUp() override {
813 JsonPrefStoreTest::SetUp();
814 test_file_ = temp_dir_.path().AppendASCII("test.json");
817 // Creates a JsonPrefStore with the given |file_writer|.
818 scoped_refptr<JsonPrefStore> CreatePrefStore() {
819 return new JsonPrefStore(test_file_, message_loop_.task_runner(),
820 scoped_ptr<PrefFilter>());
823 // Return the ImportantFileWriter for a given JsonPrefStore.
824 ImportantFileWriter* GetImportantFileWriter(
825 scoped_refptr<JsonPrefStore> pref_store) {
826 return &(pref_store->writer_);
829 // Get the contents of kTestFile. Pumps the message loop before returning the
830 // result.
831 std::string GetTestFileContents() {
832 RunLoop().RunUntilIdle();
833 std::string file_contents;
834 ReadFileToString(test_file_, &file_contents);
835 return file_contents;
838 private:
839 base::FilePath test_file_;
842 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
843 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
844 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
846 // Set a normal pref and check that it gets scheduled to be written.
847 ASSERT_FALSE(file_writer->HasPendingWrite());
848 pref_store->SetValue("normal", new base::StringValue("normal"),
849 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
850 ASSERT_TRUE(file_writer->HasPendingWrite());
851 file_writer->DoScheduledWrite();
852 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
853 ASSERT_FALSE(file_writer->HasPendingWrite());
855 // Set a lossy pref and check that it is not scheduled to be written.
856 // SetValue/RemoveValue.
857 pref_store->SetValue("lossy", new base::StringValue("lossy"),
858 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
859 ASSERT_FALSE(file_writer->HasPendingWrite());
860 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
861 ASSERT_FALSE(file_writer->HasPendingWrite());
863 // SetValueSilently/RemoveValueSilently.
864 pref_store->SetValueSilently("lossy", new base::StringValue("lossy"),
865 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
866 ASSERT_FALSE(file_writer->HasPendingWrite());
867 pref_store->RemoveValueSilently("lossy",
868 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
869 ASSERT_FALSE(file_writer->HasPendingWrite());
871 // ReportValueChanged.
872 pref_store->SetValue("lossy", new base::StringValue("lossy"),
873 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
874 ASSERT_FALSE(file_writer->HasPendingWrite());
875 pref_store->ReportValueChanged("lossy",
876 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
877 ASSERT_FALSE(file_writer->HasPendingWrite());
879 // Call CommitPendingWrite and check that the lossy pref and the normal pref
880 // are there with the last values set above.
881 pref_store->CommitPendingWrite();
882 ASSERT_FALSE(file_writer->HasPendingWrite());
883 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
884 GetTestFileContents());
887 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
888 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
889 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
891 // Set a lossy pref and check that it is not scheduled to be written.
892 ASSERT_FALSE(file_writer->HasPendingWrite());
893 pref_store->SetValue("lossy", new base::StringValue("lossy"),
894 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
895 ASSERT_FALSE(file_writer->HasPendingWrite());
897 // Set a normal pref and check that it is scheduled to be written.
898 pref_store->SetValue("normal", new base::StringValue("normal"),
899 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
900 ASSERT_TRUE(file_writer->HasPendingWrite());
902 // Call DoScheduledWrite and check both prefs get written.
903 file_writer->DoScheduledWrite();
904 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
905 GetTestFileContents());
906 ASSERT_FALSE(file_writer->HasPendingWrite());
909 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
910 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
911 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
913 // Set a normal pref and check that it is scheduled to be written.
914 ASSERT_FALSE(file_writer->HasPendingWrite());
915 pref_store->SetValue("normal", new base::StringValue("normal"),
916 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
917 ASSERT_TRUE(file_writer->HasPendingWrite());
919 // Set a lossy pref and check that the write is still scheduled.
920 pref_store->SetValue("lossy", new base::StringValue("lossy"),
921 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
922 ASSERT_TRUE(file_writer->HasPendingWrite());
924 // Call DoScheduledWrite and check both prefs get written.
925 file_writer->DoScheduledWrite();
926 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
927 GetTestFileContents());
928 ASSERT_FALSE(file_writer->HasPendingWrite());
931 } // namespace base