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"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram_samples.h"
14 #include "base/metrics/statistics_recorder.h"
15 #include "base/path_service.h"
16 #include "base/prefs/pref_filter.h"
17 #include "base/run_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/test/simple_test_clock.h"
22 #include "base/threading/sequenced_worker_pool.h"
23 #include "base/threading/thread.h"
24 #include "base/values.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
31 const char kHomePage
[] = "homepage";
33 // Set the time on the given SimpleTestClock to the given time in minutes.
34 void SetCurrentTimeInMinutes(double minutes
, base::SimpleTestClock
* clock
) {
35 const int32_t kBaseTimeMins
= 100;
36 clock
->SetNow(base::Time::FromDoubleT((kBaseTimeMins
+ minutes
) * 60));
39 // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
40 // to the |prefs| until explicitly asked to release them.
41 class InterceptingPrefFilter
: public PrefFilter
{
43 InterceptingPrefFilter();
44 ~InterceptingPrefFilter() override
;
46 // PrefFilter implementation:
48 const PostFilterOnLoadCallback
& post_filter_on_load_callback
,
49 scoped_ptr
<base::DictionaryValue
> pref_store_contents
) override
;
50 void FilterUpdate(const std::string
& path
) override
{}
51 void FilterSerializeData(
52 base::DictionaryValue
* pref_store_contents
) override
{}
54 bool has_intercepted_prefs() const { return intercepted_prefs_
!= NULL
; }
56 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
61 PostFilterOnLoadCallback post_filter_on_load_callback_
;
62 scoped_ptr
<base::DictionaryValue
> intercepted_prefs_
;
64 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter
);
67 InterceptingPrefFilter::InterceptingPrefFilter() {}
68 InterceptingPrefFilter::~InterceptingPrefFilter() {}
70 void InterceptingPrefFilter::FilterOnLoad(
71 const PostFilterOnLoadCallback
& post_filter_on_load_callback
,
72 scoped_ptr
<base::DictionaryValue
> pref_store_contents
) {
73 post_filter_on_load_callback_
= post_filter_on_load_callback
;
74 intercepted_prefs_
= pref_store_contents
.Pass();
77 void InterceptingPrefFilter::ReleasePrefs() {
78 EXPECT_FALSE(post_filter_on_load_callback_
.is_null());
79 post_filter_on_load_callback_
.Run(intercepted_prefs_
.Pass(), false);
80 post_filter_on_load_callback_
.Reset();
83 class MockPrefStoreObserver
: public PrefStore::Observer
{
85 MOCK_METHOD1(OnPrefValueChanged
, void (const std::string
&));
86 MOCK_METHOD1(OnInitializationCompleted
, void (bool));
89 class MockReadErrorDelegate
: public PersistentPrefStore::ReadErrorDelegate
{
91 MOCK_METHOD1(OnError
, void(PersistentPrefStore::PrefReadError
));
96 class JsonPrefStoreTest
: public testing::Test
{
98 void SetUp() override
{
99 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
101 ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA
, &data_dir_
));
102 data_dir_
= data_dir_
.AppendASCII("prefs");
103 ASSERT_TRUE(PathExists(data_dir_
));
106 void TearDown() override
{
107 // Make sure all pending tasks have been processed (e.g., deleting the
108 // JsonPrefStore may post write tasks).
109 message_loop_
.PostTask(FROM_HERE
, MessageLoop::QuitWhenIdleClosure());
113 // The path to temporary directory used to contain the test operations.
114 base::ScopedTempDir temp_dir_
;
115 // The path to the directory where the test data is stored.
116 base::FilePath data_dir_
;
117 // A message loop that we can use as the file thread message loop.
118 MessageLoop message_loop_
;
121 // Ensure histograms are reset for each test.
122 StatisticsRecorder statistics_recorder_
;
125 // Test fallback behavior for a nonexistent file.
126 TEST_F(JsonPrefStoreTest
, NonExistentFile
) {
127 base::FilePath bogus_input_file
= data_dir_
.AppendASCII("read.txt");
128 ASSERT_FALSE(PathExists(bogus_input_file
));
129 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
131 message_loop_
.message_loop_proxy().get(),
132 scoped_ptr
<PrefFilter
>());
133 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE
,
134 pref_store
->ReadPrefs());
135 EXPECT_FALSE(pref_store
->ReadOnly());
138 // Test fallback behavior for a nonexistent file and alternate file.
139 TEST_F(JsonPrefStoreTest
, NonExistentFileAndAlternateFile
) {
140 base::FilePath bogus_input_file
= data_dir_
.AppendASCII("read.txt");
141 base::FilePath bogus_alternate_input_file
=
142 data_dir_
.AppendASCII("read_alternate.txt");
143 ASSERT_FALSE(PathExists(bogus_input_file
));
144 ASSERT_FALSE(PathExists(bogus_alternate_input_file
));
145 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
147 bogus_alternate_input_file
,
148 message_loop_
.message_loop_proxy().get(),
149 scoped_ptr
<PrefFilter
>());
150 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE
,
151 pref_store
->ReadPrefs());
152 EXPECT_FALSE(pref_store
->ReadOnly());
155 // Test fallback behavior for an invalid file.
156 TEST_F(JsonPrefStoreTest
, InvalidFile
) {
157 base::FilePath invalid_file_original
= data_dir_
.AppendASCII("invalid.json");
158 base::FilePath invalid_file
= temp_dir_
.path().AppendASCII("invalid.json");
159 ASSERT_TRUE(base::CopyFile(invalid_file_original
, invalid_file
));
160 scoped_refptr
<JsonPrefStore
> pref_store
=
161 new JsonPrefStore(invalid_file
,
162 message_loop_
.message_loop_proxy().get(),
163 scoped_ptr
<PrefFilter
>());
164 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE
,
165 pref_store
->ReadPrefs());
166 EXPECT_FALSE(pref_store
->ReadOnly());
168 // The file should have been moved aside.
169 EXPECT_FALSE(PathExists(invalid_file
));
170 base::FilePath moved_aside
= temp_dir_
.path().AppendASCII("invalid.bad");
171 EXPECT_TRUE(PathExists(moved_aside
));
172 EXPECT_TRUE(TextContentsEqual(invalid_file_original
, moved_aside
));
175 // This function is used to avoid code duplication while testing synchronous and
176 // asynchronous version of the JsonPrefStore loading.
177 void RunBasicJsonPrefStoreTest(JsonPrefStore
* pref_store
,
178 const base::FilePath
& output_file
,
179 const base::FilePath
& golden_output_file
) {
180 const char kNewWindowsInTabs
[] = "tabs.new_windows_in_tabs";
181 const char kMaxTabs
[] = "tabs.max_tabs";
182 const char kLongIntPref
[] = "long_int.pref";
184 std::string
cnn("http://www.cnn.com");
187 EXPECT_TRUE(pref_store
->GetValue(kHomePage
, &actual
));
188 std::string string_value
;
189 EXPECT_TRUE(actual
->GetAsString(&string_value
));
190 EXPECT_EQ(cnn
, string_value
);
192 const char kSomeDirectory
[] = "some_directory";
194 EXPECT_TRUE(pref_store
->GetValue(kSomeDirectory
, &actual
));
195 base::FilePath::StringType path
;
196 EXPECT_TRUE(actual
->GetAsString(&path
));
197 EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path
);
198 base::FilePath
some_path(FILE_PATH_LITERAL("/usr/sbin/"));
200 pref_store
->SetValue(kSomeDirectory
, new StringValue(some_path
.value()));
201 EXPECT_TRUE(pref_store
->GetValue(kSomeDirectory
, &actual
));
202 EXPECT_TRUE(actual
->GetAsString(&path
));
203 EXPECT_EQ(some_path
.value(), path
);
205 // Test reading some other data types from sub-dictionaries.
206 EXPECT_TRUE(pref_store
->GetValue(kNewWindowsInTabs
, &actual
));
207 bool boolean
= false;
208 EXPECT_TRUE(actual
->GetAsBoolean(&boolean
));
209 EXPECT_TRUE(boolean
);
211 pref_store
->SetValue(kNewWindowsInTabs
, new FundamentalValue(false));
212 EXPECT_TRUE(pref_store
->GetValue(kNewWindowsInTabs
, &actual
));
213 EXPECT_TRUE(actual
->GetAsBoolean(&boolean
));
214 EXPECT_FALSE(boolean
);
216 EXPECT_TRUE(pref_store
->GetValue(kMaxTabs
, &actual
));
218 EXPECT_TRUE(actual
->GetAsInteger(&integer
));
219 EXPECT_EQ(20, integer
);
220 pref_store
->SetValue(kMaxTabs
, new FundamentalValue(10));
221 EXPECT_TRUE(pref_store
->GetValue(kMaxTabs
, &actual
));
222 EXPECT_TRUE(actual
->GetAsInteger(&integer
));
223 EXPECT_EQ(10, integer
);
225 pref_store
->SetValue(kLongIntPref
,
226 new StringValue(base::Int64ToString(214748364842LL)));
227 EXPECT_TRUE(pref_store
->GetValue(kLongIntPref
, &actual
));
228 EXPECT_TRUE(actual
->GetAsString(&string_value
));
230 base::StringToInt64(string_value
, &value
);
231 EXPECT_EQ(214748364842LL, value
);
233 // Serialize and compare to expected output.
234 ASSERT_TRUE(PathExists(golden_output_file
));
235 pref_store
->CommitPendingWrite();
236 RunLoop().RunUntilIdle();
237 EXPECT_TRUE(TextContentsEqual(golden_output_file
, output_file
));
238 ASSERT_TRUE(base::DeleteFile(output_file
, false));
241 TEST_F(JsonPrefStoreTest
, Basic
) {
242 ASSERT_TRUE(base::CopyFile(data_dir_
.AppendASCII("read.json"),
243 temp_dir_
.path().AppendASCII("write.json")));
245 // Test that the persistent value can be loaded.
246 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
247 ASSERT_TRUE(PathExists(input_file
));
248 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
250 message_loop_
.message_loop_proxy().get(),
251 scoped_ptr
<PrefFilter
>());
252 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE
, pref_store
->ReadPrefs());
253 EXPECT_FALSE(pref_store
->ReadOnly());
254 EXPECT_TRUE(pref_store
->IsInitializationComplete());
256 // The JSON file looks like this:
258 // "homepage": "http://www.cnn.com",
259 // "some_directory": "/usr/local/",
261 // "new_windows_in_tabs": true,
266 RunBasicJsonPrefStoreTest(
267 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
270 TEST_F(JsonPrefStoreTest
, BasicAsync
) {
271 ASSERT_TRUE(base::CopyFile(data_dir_
.AppendASCII("read.json"),
272 temp_dir_
.path().AppendASCII("write.json")));
274 // Test that the persistent value can be loaded.
275 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
276 ASSERT_TRUE(PathExists(input_file
));
277 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
279 message_loop_
.message_loop_proxy().get(),
280 scoped_ptr
<PrefFilter
>());
283 MockPrefStoreObserver mock_observer
;
284 pref_store
->AddObserver(&mock_observer
);
286 MockReadErrorDelegate
* mock_error_delegate
= new MockReadErrorDelegate
;
287 pref_store
->ReadPrefsAsync(mock_error_delegate
);
289 EXPECT_CALL(mock_observer
, OnInitializationCompleted(true)).Times(1);
290 EXPECT_CALL(*mock_error_delegate
,
291 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE
)).Times(0);
292 RunLoop().RunUntilIdle();
293 pref_store
->RemoveObserver(&mock_observer
);
295 EXPECT_FALSE(pref_store
->ReadOnly());
296 EXPECT_TRUE(pref_store
->IsInitializationComplete());
299 // The JSON file looks like this:
301 // "homepage": "http://www.cnn.com",
302 // "some_directory": "/usr/local/",
304 // "new_windows_in_tabs": true,
309 RunBasicJsonPrefStoreTest(
310 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
313 TEST_F(JsonPrefStoreTest
, PreserveEmptyValues
) {
314 FilePath pref_file
= temp_dir_
.path().AppendASCII("empty_values.json");
316 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
318 message_loop_
.message_loop_proxy(),
319 scoped_ptr
<PrefFilter
>());
321 // Set some keys with empty values.
322 pref_store
->SetValue("list", new base::ListValue
);
323 pref_store
->SetValue("dict", new base::DictionaryValue
);
326 pref_store
->CommitPendingWrite();
327 MessageLoop::current()->RunUntilIdle();
330 pref_store
= new JsonPrefStore(
332 message_loop_
.message_loop_proxy(),
333 scoped_ptr
<PrefFilter
>());
334 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE
, pref_store
->ReadPrefs());
335 ASSERT_FALSE(pref_store
->ReadOnly());
338 const Value
* result
= NULL
;
339 EXPECT_TRUE(pref_store
->GetValue("list", &result
));
340 EXPECT_TRUE(ListValue().Equals(result
));
341 EXPECT_TRUE(pref_store
->GetValue("dict", &result
));
342 EXPECT_TRUE(DictionaryValue().Equals(result
));
345 // This test is just documenting some potentially non-obvious behavior. It
346 // shouldn't be taken as normative.
347 TEST_F(JsonPrefStoreTest
, RemoveClearsEmptyParent
) {
348 FilePath pref_file
= temp_dir_
.path().AppendASCII("empty_values.json");
350 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
352 message_loop_
.message_loop_proxy(),
353 scoped_ptr
<PrefFilter
>());
355 base::DictionaryValue
* dict
= new base::DictionaryValue
;
356 dict
->SetString("key", "value");
357 pref_store
->SetValue("dict", dict
);
359 pref_store
->RemoveValue("dict.key");
361 const base::Value
* retrieved_dict
= NULL
;
362 bool has_dict
= pref_store
->GetValue("dict", &retrieved_dict
);
363 EXPECT_FALSE(has_dict
);
366 // Tests asynchronous reading of the file when there is no file.
367 TEST_F(JsonPrefStoreTest
, AsyncNonExistingFile
) {
368 base::FilePath bogus_input_file
= data_dir_
.AppendASCII("read.txt");
369 ASSERT_FALSE(PathExists(bogus_input_file
));
370 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
372 message_loop_
.message_loop_proxy().get(),
373 scoped_ptr
<PrefFilter
>());
374 MockPrefStoreObserver mock_observer
;
375 pref_store
->AddObserver(&mock_observer
);
377 MockReadErrorDelegate
*mock_error_delegate
= new MockReadErrorDelegate
;
378 pref_store
->ReadPrefsAsync(mock_error_delegate
);
380 EXPECT_CALL(mock_observer
, OnInitializationCompleted(true)).Times(1);
381 EXPECT_CALL(*mock_error_delegate
,
382 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE
)).Times(1);
383 RunLoop().RunUntilIdle();
384 pref_store
->RemoveObserver(&mock_observer
);
386 EXPECT_FALSE(pref_store
->ReadOnly());
389 TEST_F(JsonPrefStoreTest
, ReadWithInterceptor
) {
390 ASSERT_TRUE(base::CopyFile(data_dir_
.AppendASCII("read.json"),
391 temp_dir_
.path().AppendASCII("write.json")));
393 // Test that the persistent value can be loaded.
394 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
395 ASSERT_TRUE(PathExists(input_file
));
397 scoped_ptr
<InterceptingPrefFilter
> intercepting_pref_filter(
398 new InterceptingPrefFilter());
399 InterceptingPrefFilter
* raw_intercepting_pref_filter_
=
400 intercepting_pref_filter
.get();
401 scoped_refptr
<JsonPrefStore
> pref_store
=
402 new JsonPrefStore(input_file
,
403 message_loop_
.message_loop_proxy().get(),
404 intercepting_pref_filter
.Pass());
406 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
,
407 pref_store
->ReadPrefs());
408 EXPECT_FALSE(pref_store
->ReadOnly());
410 // The store shouldn't be considered initialized until the interceptor
412 EXPECT_TRUE(raw_intercepting_pref_filter_
->has_intercepted_prefs());
413 EXPECT_FALSE(pref_store
->IsInitializationComplete());
414 EXPECT_FALSE(pref_store
->GetValue(kHomePage
, NULL
));
416 raw_intercepting_pref_filter_
->ReleasePrefs();
418 EXPECT_FALSE(raw_intercepting_pref_filter_
->has_intercepted_prefs());
419 EXPECT_TRUE(pref_store
->IsInitializationComplete());
420 EXPECT_TRUE(pref_store
->GetValue(kHomePage
, NULL
));
422 // The JSON file looks like this:
424 // "homepage": "http://www.cnn.com",
425 // "some_directory": "/usr/local/",
427 // "new_windows_in_tabs": true,
432 RunBasicJsonPrefStoreTest(
433 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
436 TEST_F(JsonPrefStoreTest
, ReadAsyncWithInterceptor
) {
437 ASSERT_TRUE(base::CopyFile(data_dir_
.AppendASCII("read.json"),
438 temp_dir_
.path().AppendASCII("write.json")));
440 // Test that the persistent value can be loaded.
441 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
442 ASSERT_TRUE(PathExists(input_file
));
444 scoped_ptr
<InterceptingPrefFilter
> intercepting_pref_filter(
445 new InterceptingPrefFilter());
446 InterceptingPrefFilter
* raw_intercepting_pref_filter_
=
447 intercepting_pref_filter
.get();
448 scoped_refptr
<JsonPrefStore
> pref_store
=
449 new JsonPrefStore(input_file
,
450 message_loop_
.message_loop_proxy().get(),
451 intercepting_pref_filter
.Pass());
453 MockPrefStoreObserver mock_observer
;
454 pref_store
->AddObserver(&mock_observer
);
456 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
457 MockReadErrorDelegate
* mock_error_delegate
= new MockReadErrorDelegate
;
460 pref_store
->ReadPrefsAsync(mock_error_delegate
);
462 EXPECT_CALL(mock_observer
, OnInitializationCompleted(true)).Times(0);
463 // EXPECT_CALL(*mock_error_delegate,
464 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
465 RunLoop().RunUntilIdle();
467 EXPECT_FALSE(pref_store
->ReadOnly());
468 EXPECT_TRUE(raw_intercepting_pref_filter_
->has_intercepted_prefs());
469 EXPECT_FALSE(pref_store
->IsInitializationComplete());
470 EXPECT_FALSE(pref_store
->GetValue(kHomePage
, NULL
));
474 EXPECT_CALL(mock_observer
, OnInitializationCompleted(true)).Times(1);
475 // EXPECT_CALL(*mock_error_delegate,
476 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
478 raw_intercepting_pref_filter_
->ReleasePrefs();
480 EXPECT_FALSE(pref_store
->ReadOnly());
481 EXPECT_FALSE(raw_intercepting_pref_filter_
->has_intercepted_prefs());
482 EXPECT_TRUE(pref_store
->IsInitializationComplete());
483 EXPECT_TRUE(pref_store
->GetValue(kHomePage
, NULL
));
486 pref_store
->RemoveObserver(&mock_observer
);
488 // The JSON file looks like this:
490 // "homepage": "http://www.cnn.com",
491 // "some_directory": "/usr/local/",
493 // "new_windows_in_tabs": true,
498 RunBasicJsonPrefStoreTest(
499 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
502 TEST_F(JsonPrefStoreTest
, AlternateFile
) {
504 base::CopyFile(data_dir_
.AppendASCII("read.json"),
505 temp_dir_
.path().AppendASCII("alternate.json")));
507 // Test that the alternate file is moved to the main file and read as-is from
509 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
510 base::FilePath alternate_input_file
=
511 temp_dir_
.path().AppendASCII("alternate.json");
512 ASSERT_FALSE(PathExists(input_file
));
513 ASSERT_TRUE(PathExists(alternate_input_file
));
514 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
516 alternate_input_file
,
517 message_loop_
.message_loop_proxy().get(),
518 scoped_ptr
<PrefFilter
>());
520 ASSERT_FALSE(PathExists(input_file
));
521 ASSERT_TRUE(PathExists(alternate_input_file
));
522 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE
, pref_store
->ReadPrefs());
524 ASSERT_TRUE(PathExists(input_file
));
525 ASSERT_FALSE(PathExists(alternate_input_file
));
527 EXPECT_FALSE(pref_store
->ReadOnly());
528 EXPECT_TRUE(pref_store
->IsInitializationComplete());
530 // The JSON file looks like this:
532 // "homepage": "http://www.cnn.com",
533 // "some_directory": "/usr/local/",
535 // "new_windows_in_tabs": true,
540 RunBasicJsonPrefStoreTest(
541 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
544 TEST_F(JsonPrefStoreTest
, AlternateFileIgnoredWhenMainFileExists
) {
546 base::CopyFile(data_dir_
.AppendASCII("read.json"),
547 temp_dir_
.path().AppendASCII("write.json")));
549 base::CopyFile(data_dir_
.AppendASCII("invalid.json"),
550 temp_dir_
.path().AppendASCII("alternate.json")));
552 // Test that the alternate file is ignored and that the read occurs from the
553 // existing main file. There is no attempt at even deleting the alternate
554 // file as this scenario should never happen in normal user-data-dirs.
555 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
556 base::FilePath alternate_input_file
=
557 temp_dir_
.path().AppendASCII("alternate.json");
558 ASSERT_TRUE(PathExists(input_file
));
559 ASSERT_TRUE(PathExists(alternate_input_file
));
560 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
562 alternate_input_file
,
563 message_loop_
.message_loop_proxy().get(),
564 scoped_ptr
<PrefFilter
>());
566 ASSERT_TRUE(PathExists(input_file
));
567 ASSERT_TRUE(PathExists(alternate_input_file
));
568 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE
, pref_store
->ReadPrefs());
570 ASSERT_TRUE(PathExists(input_file
));
571 ASSERT_TRUE(PathExists(alternate_input_file
));
573 EXPECT_FALSE(pref_store
->ReadOnly());
574 EXPECT_TRUE(pref_store
->IsInitializationComplete());
576 // The JSON file looks like this:
578 // "homepage": "http://www.cnn.com",
579 // "some_directory": "/usr/local/",
581 // "new_windows_in_tabs": true,
586 RunBasicJsonPrefStoreTest(
587 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
590 TEST_F(JsonPrefStoreTest
, AlternateFileDNE
) {
592 base::CopyFile(data_dir_
.AppendASCII("read.json"),
593 temp_dir_
.path().AppendASCII("write.json")));
595 // Test that the basic read works fine when an alternate file is specified but
597 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
598 base::FilePath alternate_input_file
=
599 temp_dir_
.path().AppendASCII("alternate.json");
600 ASSERT_TRUE(PathExists(input_file
));
601 ASSERT_FALSE(PathExists(alternate_input_file
));
602 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
604 alternate_input_file
,
605 message_loop_
.message_loop_proxy().get(),
606 scoped_ptr
<PrefFilter
>());
608 ASSERT_TRUE(PathExists(input_file
));
609 ASSERT_FALSE(PathExists(alternate_input_file
));
610 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE
, pref_store
->ReadPrefs());
612 ASSERT_TRUE(PathExists(input_file
));
613 ASSERT_FALSE(PathExists(alternate_input_file
));
615 EXPECT_FALSE(pref_store
->ReadOnly());
616 EXPECT_TRUE(pref_store
->IsInitializationComplete());
618 // The JSON file looks like this:
620 // "homepage": "http://www.cnn.com",
621 // "some_directory": "/usr/local/",
623 // "new_windows_in_tabs": true,
628 RunBasicJsonPrefStoreTest(
629 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
632 TEST_F(JsonPrefStoreTest
, BasicAsyncWithAlternateFile
) {
634 base::CopyFile(data_dir_
.AppendASCII("read.json"),
635 temp_dir_
.path().AppendASCII("alternate.json")));
637 // Test that the alternate file is moved to the main file and read as-is from
638 // there even when the read is made asynchronously.
639 base::FilePath input_file
= temp_dir_
.path().AppendASCII("write.json");
640 base::FilePath alternate_input_file
=
641 temp_dir_
.path().AppendASCII("alternate.json");
642 ASSERT_FALSE(PathExists(input_file
));
643 ASSERT_TRUE(PathExists(alternate_input_file
));
644 scoped_refptr
<JsonPrefStore
> pref_store
= new JsonPrefStore(
646 alternate_input_file
,
647 message_loop_
.message_loop_proxy().get(),
648 scoped_ptr
<PrefFilter
>());
650 ASSERT_FALSE(PathExists(input_file
));
651 ASSERT_TRUE(PathExists(alternate_input_file
));
654 MockPrefStoreObserver mock_observer
;
655 pref_store
->AddObserver(&mock_observer
);
657 MockReadErrorDelegate
* mock_error_delegate
= new MockReadErrorDelegate
;
658 pref_store
->ReadPrefsAsync(mock_error_delegate
);
660 EXPECT_CALL(mock_observer
, OnInitializationCompleted(true)).Times(1);
661 EXPECT_CALL(*mock_error_delegate
,
662 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE
)).Times(0);
663 RunLoop().RunUntilIdle();
664 pref_store
->RemoveObserver(&mock_observer
);
666 EXPECT_FALSE(pref_store
->ReadOnly());
667 EXPECT_TRUE(pref_store
->IsInitializationComplete());
670 ASSERT_TRUE(PathExists(input_file
));
671 ASSERT_FALSE(PathExists(alternate_input_file
));
673 // The JSON file looks like this:
675 // "homepage": "http://www.cnn.com",
676 // "some_directory": "/usr/local/",
678 // "new_windows_in_tabs": true,
683 RunBasicJsonPrefStoreTest(
684 pref_store
.get(), input_file
, data_dir_
.AppendASCII("write.golden.json"));
687 TEST_F(JsonPrefStoreTest
, WriteCountHistogramTestBasic
) {
688 SimpleTestClock
* test_clock
= new SimpleTestClock
;
689 SetCurrentTimeInMinutes(0, test_clock
);
690 JsonPrefStore::WriteCountHistogram
histogram(
691 base::TimeDelta::FromSeconds(10),
692 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
693 scoped_ptr
<base::Clock
>(test_clock
));
694 int32 report_interval
=
695 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins
;
697 histogram
.RecordWriteOccured();
699 SetCurrentTimeInMinutes(1.5 * report_interval
, test_clock
);
700 histogram
.ReportOutstandingWrites();
701 scoped_ptr
<HistogramSamples
> samples
=
702 histogram
.GetHistogram()->SnapshotSamples();
703 ASSERT_EQ(1, samples
->GetCount(1));
704 ASSERT_EQ(1, samples
->TotalCount());
706 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
707 histogram
.GetHistogram()->histogram_name());
708 ASSERT_TRUE(histogram
.GetHistogram()->HasConstructionArguments(1, 30, 31));
711 TEST_F(JsonPrefStoreTest
, WriteCountHistogramTestSinglePeriod
) {
712 SimpleTestClock
* test_clock
= new SimpleTestClock
;
713 SetCurrentTimeInMinutes(0, test_clock
);
714 JsonPrefStore::WriteCountHistogram
histogram(
715 base::TimeDelta::FromSeconds(10),
716 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
717 scoped_ptr
<base::Clock
>(test_clock
));
718 int32 report_interval
=
719 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins
;
721 histogram
.RecordWriteOccured();
722 SetCurrentTimeInMinutes(0.5 * report_interval
, test_clock
);
723 histogram
.RecordWriteOccured();
724 SetCurrentTimeInMinutes(0.7 * report_interval
, test_clock
);
725 histogram
.RecordWriteOccured();
727 // Nothing should be recorded until the report period has elapsed.
728 scoped_ptr
<HistogramSamples
> samples
=
729 histogram
.GetHistogram()->SnapshotSamples();
730 ASSERT_EQ(0, samples
->TotalCount());
732 SetCurrentTimeInMinutes(1.3 * report_interval
, test_clock
);
733 histogram
.RecordWriteOccured();
735 // Now the report period has elapsed.
736 samples
= histogram
.GetHistogram()->SnapshotSamples();
737 ASSERT_EQ(1, samples
->GetCount(3));
738 ASSERT_EQ(1, samples
->TotalCount());
740 // The last write won't be recorded because the second count period hasn't
742 SetCurrentTimeInMinutes(1.5 * report_interval
, test_clock
);
743 histogram
.ReportOutstandingWrites();
745 samples
= histogram
.GetHistogram()->SnapshotSamples();
746 ASSERT_EQ(1, samples
->GetCount(3));
747 ASSERT_EQ(1, samples
->TotalCount());
750 TEST_F(JsonPrefStoreTest
, WriteCountHistogramTestMultiplePeriods
) {
751 SimpleTestClock
* test_clock
= new SimpleTestClock
;
752 SetCurrentTimeInMinutes(0, test_clock
);
753 JsonPrefStore::WriteCountHistogram
histogram(
754 base::TimeDelta::FromSeconds(10),
755 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
756 scoped_ptr
<base::Clock
>(test_clock
));
757 int32 report_interval
=
758 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins
;
760 histogram
.RecordWriteOccured();
761 SetCurrentTimeInMinutes(0.5 * report_interval
, test_clock
);
762 histogram
.RecordWriteOccured();
763 SetCurrentTimeInMinutes(0.7 * report_interval
, test_clock
);
764 histogram
.RecordWriteOccured();
765 SetCurrentTimeInMinutes(1.3 * report_interval
, test_clock
);
766 histogram
.RecordWriteOccured();
767 SetCurrentTimeInMinutes(1.5 * report_interval
, test_clock
);
768 histogram
.RecordWriteOccured();
769 SetCurrentTimeInMinutes(2.1 * report_interval
, test_clock
);
770 histogram
.RecordWriteOccured();
771 SetCurrentTimeInMinutes(2.5 * report_interval
, test_clock
);
772 histogram
.RecordWriteOccured();
773 SetCurrentTimeInMinutes(2.7 * report_interval
, test_clock
);
774 histogram
.RecordWriteOccured();
775 SetCurrentTimeInMinutes(3.3 * report_interval
, test_clock
);
776 histogram
.RecordWriteOccured();
778 // The last write won't be recorded because the second count period hasn't
780 SetCurrentTimeInMinutes(3.5 * report_interval
, test_clock
);
781 histogram
.ReportOutstandingWrites();
782 scoped_ptr
<HistogramSamples
> samples
=
783 histogram
.GetHistogram()->SnapshotSamples();
784 ASSERT_EQ(2, samples
->GetCount(3));
785 ASSERT_EQ(1, samples
->GetCount(2));
786 ASSERT_EQ(3, samples
->TotalCount());
789 TEST_F(JsonPrefStoreTest
, WriteCountHistogramTestPeriodWithGaps
) {
790 SimpleTestClock
* test_clock
= new SimpleTestClock
;
791 SetCurrentTimeInMinutes(0, test_clock
);
792 JsonPrefStore::WriteCountHistogram
histogram(
793 base::TimeDelta::FromSeconds(10),
794 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
795 scoped_ptr
<base::Clock
>(test_clock
));
796 int32 report_interval
=
797 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins
;
799 // 1 write in the first period.
800 histogram
.RecordWriteOccured();
802 // No writes in the second and third periods.
804 // 2 writes in the fourth period.
805 SetCurrentTimeInMinutes(3.1 * report_interval
, test_clock
);
806 histogram
.RecordWriteOccured();
807 SetCurrentTimeInMinutes(3.3 * report_interval
, test_clock
);
808 histogram
.RecordWriteOccured();
810 // No writes in the fifth period.
812 // 3 writes in the sixth period.
813 SetCurrentTimeInMinutes(5.1 * report_interval
, test_clock
);
814 histogram
.RecordWriteOccured();
815 SetCurrentTimeInMinutes(5.3 * report_interval
, test_clock
);
816 histogram
.RecordWriteOccured();
817 SetCurrentTimeInMinutes(5.5 * report_interval
, test_clock
);
818 histogram
.RecordWriteOccured();
820 SetCurrentTimeInMinutes(6.1 * report_interval
, test_clock
);
821 histogram
.ReportOutstandingWrites();
822 scoped_ptr
<HistogramSamples
> samples
=
823 histogram
.GetHistogram()->SnapshotSamples();
824 ASSERT_EQ(3, samples
->GetCount(0));
825 ASSERT_EQ(1, samples
->GetCount(1));
826 ASSERT_EQ(1, samples
->GetCount(2));
827 ASSERT_EQ(1, samples
->GetCount(3));
828 ASSERT_EQ(6, samples
->TotalCount());