Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: base/prefs/json_pref_store_unittest.cc

Issue 1648403002: Move base/prefs to components/prefs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/prefs/json_pref_store.cc ('k') | base/prefs/mock_pref_change_callback.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "base/prefs/json_pref_store.h"
6
7 #include <stdint.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/location.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/histogram_samples.h"
20 #include "base/metrics/statistics_recorder.h"
21 #include "base/path_service.h"
22 #include "base/prefs/pref_filter.h"
23 #include "base/run_loop.h"
24 #include "base/single_thread_task_runner.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/test/simple_test_clock.h"
29 #include "base/threading/sequenced_worker_pool.h"
30 #include "base/threading/thread.h"
31 #include "base/values.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 namespace base {
36 namespace {
37
38 const char kHomePage[] = "homepage";
39
40 // Set the time on the given SimpleTestClock to the given time in minutes.
41 void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
42 const int32_t kBaseTimeMins = 100;
43 clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
44 }
45
46 // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
47 // to the |prefs| until explicitly asked to release them.
48 class InterceptingPrefFilter : public PrefFilter {
49 public:
50 InterceptingPrefFilter();
51 ~InterceptingPrefFilter() override;
52
53 // PrefFilter implementation:
54 void FilterOnLoad(
55 const PostFilterOnLoadCallback& post_filter_on_load_callback,
56 scoped_ptr<base::DictionaryValue> pref_store_contents) override;
57 void FilterUpdate(const std::string& path) override {}
58 void FilterSerializeData(
59 base::DictionaryValue* pref_store_contents) override {}
60
61 bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
62
63 // Finalize an intercepted read, handing |intercepted_prefs_| back to its
64 // JsonPrefStore.
65 void ReleasePrefs();
66
67 private:
68 PostFilterOnLoadCallback post_filter_on_load_callback_;
69 scoped_ptr<base::DictionaryValue> intercepted_prefs_;
70
71 DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
72 };
73
74 InterceptingPrefFilter::InterceptingPrefFilter() {}
75 InterceptingPrefFilter::~InterceptingPrefFilter() {}
76
77 void InterceptingPrefFilter::FilterOnLoad(
78 const PostFilterOnLoadCallback& post_filter_on_load_callback,
79 scoped_ptr<base::DictionaryValue> pref_store_contents) {
80 post_filter_on_load_callback_ = post_filter_on_load_callback;
81 intercepted_prefs_ = std::move(pref_store_contents);
82 }
83
84 void InterceptingPrefFilter::ReleasePrefs() {
85 EXPECT_FALSE(post_filter_on_load_callback_.is_null());
86 post_filter_on_load_callback_.Run(std::move(intercepted_prefs_), false);
87 post_filter_on_load_callback_.Reset();
88 }
89
90 class MockPrefStoreObserver : public PrefStore::Observer {
91 public:
92 MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
93 MOCK_METHOD1(OnInitializationCompleted, void (bool));
94 };
95
96 class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
97 public:
98 MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
99 };
100
101 } // namespace
102
103 class JsonPrefStoreTest : public testing::Test {
104 protected:
105 void SetUp() override {
106 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
107
108 ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
109 data_dir_ = data_dir_.AppendASCII("prefs");
110 ASSERT_TRUE(PathExists(data_dir_));
111 }
112
113 void TearDown() override {
114 // Make sure all pending tasks have been processed (e.g., deleting the
115 // JsonPrefStore may post write tasks).
116 RunLoop().RunUntilIdle();
117 }
118
119 // The path to temporary directory used to contain the test operations.
120 base::ScopedTempDir temp_dir_;
121 // The path to the directory where the test data is stored.
122 base::FilePath data_dir_;
123 // A message loop that we can use as the file thread message loop.
124 MessageLoop message_loop_;
125
126 private:
127 // Ensure histograms are reset for each test.
128 StatisticsRecorder statistics_recorder_;
129 };
130
131 // Test fallback behavior for a nonexistent file.
132 TEST_F(JsonPrefStoreTest, NonExistentFile) {
133 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
134 ASSERT_FALSE(PathExists(bogus_input_file));
135 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
136 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
137 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
138 pref_store->ReadPrefs());
139 EXPECT_FALSE(pref_store->ReadOnly());
140 }
141
142 // Test fallback behavior for a nonexistent file and alternate file.
143 TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
144 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
145 base::FilePath bogus_alternate_input_file =
146 temp_dir_.path().AppendASCII("read_alternate.txt");
147 ASSERT_FALSE(PathExists(bogus_input_file));
148 ASSERT_FALSE(PathExists(bogus_alternate_input_file));
149 scoped_refptr<JsonPrefStore> pref_store =
150 new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
151 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
152 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
153 pref_store->ReadPrefs());
154 EXPECT_FALSE(pref_store->ReadOnly());
155 }
156
157 // Test fallback behavior for an invalid file.
158 TEST_F(JsonPrefStoreTest, InvalidFile) {
159 base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
160 base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
161 ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
162 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
163 invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
164 EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
165 pref_store->ReadPrefs());
166 EXPECT_FALSE(pref_store->ReadOnly());
167
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));
173 }
174
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";
183
184 std::string cnn("http://www.cnn.com");
185
186 const Value* actual;
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);
191
192 const char kSomeDirectory[] = "some_directory";
193
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/"));
199
200 pref_store->SetValue(kSomeDirectory,
201 make_scoped_ptr(new StringValue(some_path.value())),
202 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
203 EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
204 EXPECT_TRUE(actual->GetAsString(&path));
205 EXPECT_EQ(some_path.value(), path);
206
207 // Test reading some other data types from sub-dictionaries.
208 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
209 bool boolean = false;
210 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
211 EXPECT_TRUE(boolean);
212
213 pref_store->SetValue(kNewWindowsInTabs,
214 make_scoped_ptr(new FundamentalValue(false)),
215 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
216 EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
217 EXPECT_TRUE(actual->GetAsBoolean(&boolean));
218 EXPECT_FALSE(boolean);
219
220 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
221 int integer = 0;
222 EXPECT_TRUE(actual->GetAsInteger(&integer));
223 EXPECT_EQ(20, integer);
224 pref_store->SetValue(kMaxTabs, make_scoped_ptr(new FundamentalValue(10)),
225 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
226 EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
227 EXPECT_TRUE(actual->GetAsInteger(&integer));
228 EXPECT_EQ(10, integer);
229
230 pref_store->SetValue(
231 kLongIntPref,
232 make_scoped_ptr(new StringValue(base::Int64ToString(214748364842LL))),
233 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
234 EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
235 EXPECT_TRUE(actual->GetAsString(&string_value));
236 int64_t value;
237 base::StringToInt64(string_value, &value);
238 EXPECT_EQ(214748364842LL, value);
239
240 // Serialize and compare to expected output.
241 ASSERT_TRUE(PathExists(golden_output_file));
242 pref_store->CommitPendingWrite();
243 RunLoop().RunUntilIdle();
244 EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file));
245 ASSERT_TRUE(base::DeleteFile(output_file, false));
246 }
247
248 TEST_F(JsonPrefStoreTest, Basic) {
249 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
250 temp_dir_.path().AppendASCII("write.json")));
251
252 // Test that the persistent value can be loaded.
253 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
254 ASSERT_TRUE(PathExists(input_file));
255 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
256 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
257 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
258 EXPECT_FALSE(pref_store->ReadOnly());
259 EXPECT_TRUE(pref_store->IsInitializationComplete());
260
261 // The JSON file looks like this:
262 // {
263 // "homepage": "http://www.cnn.com",
264 // "some_directory": "/usr/local/",
265 // "tabs": {
266 // "new_windows_in_tabs": true,
267 // "max_tabs": 20
268 // }
269 // }
270
271 RunBasicJsonPrefStoreTest(
272 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
273 }
274
275 TEST_F(JsonPrefStoreTest, BasicAsync) {
276 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
277 temp_dir_.path().AppendASCII("write.json")));
278
279 // Test that the persistent value can be loaded.
280 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
281 ASSERT_TRUE(PathExists(input_file));
282 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
283 input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
284
285 {
286 MockPrefStoreObserver mock_observer;
287 pref_store->AddObserver(&mock_observer);
288
289 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
290 pref_store->ReadPrefsAsync(mock_error_delegate);
291
292 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
293 EXPECT_CALL(*mock_error_delegate,
294 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
295 RunLoop().RunUntilIdle();
296 pref_store->RemoveObserver(&mock_observer);
297
298 EXPECT_FALSE(pref_store->ReadOnly());
299 EXPECT_TRUE(pref_store->IsInitializationComplete());
300 }
301
302 // The JSON file looks like this:
303 // {
304 // "homepage": "http://www.cnn.com",
305 // "some_directory": "/usr/local/",
306 // "tabs": {
307 // "new_windows_in_tabs": true,
308 // "max_tabs": 20
309 // }
310 // }
311
312 RunBasicJsonPrefStoreTest(
313 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
314 }
315
316 TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
317 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
318
319 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
320 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
321
322 // Set some keys with empty values.
323 pref_store->SetValue("list", make_scoped_ptr(new base::ListValue),
324 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
325 pref_store->SetValue("dict", make_scoped_ptr(new base::DictionaryValue),
326 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
327
328 // Write to file.
329 pref_store->CommitPendingWrite();
330 RunLoop().RunUntilIdle();
331
332 // Reload.
333 pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
334 scoped_ptr<PrefFilter>());
335 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
336 ASSERT_FALSE(pref_store->ReadOnly());
337
338 // Check values.
339 const Value* result = NULL;
340 EXPECT_TRUE(pref_store->GetValue("list", &result));
341 EXPECT_TRUE(ListValue().Equals(result));
342 EXPECT_TRUE(pref_store->GetValue("dict", &result));
343 EXPECT_TRUE(DictionaryValue().Equals(result));
344 }
345
346 // This test is just documenting some potentially non-obvious behavior. It
347 // shouldn't be taken as normative.
348 TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
349 FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
350
351 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
352 pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
353
354 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
355 dict->SetString("key", "value");
356 pref_store->SetValue("dict", std::move(dict),
357 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
358
359 pref_store->RemoveValue("dict.key",
360 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
361
362 const base::Value* retrieved_dict = NULL;
363 bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
364 EXPECT_FALSE(has_dict);
365 }
366
367 // Tests asynchronous reading of the file when there is no file.
368 TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
369 base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
370 ASSERT_FALSE(PathExists(bogus_input_file));
371 scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
372 bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
373 MockPrefStoreObserver mock_observer;
374 pref_store->AddObserver(&mock_observer);
375
376 MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
377 pref_store->ReadPrefsAsync(mock_error_delegate);
378
379 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
380 EXPECT_CALL(*mock_error_delegate,
381 OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
382 RunLoop().RunUntilIdle();
383 pref_store->RemoveObserver(&mock_observer);
384
385 EXPECT_FALSE(pref_store->ReadOnly());
386 }
387
388 TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
389 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
390 temp_dir_.path().AppendASCII("write.json")));
391
392 // Test that the persistent value can be loaded.
393 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
394 ASSERT_TRUE(PathExists(input_file));
395
396 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
397 new InterceptingPrefFilter());
398 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
399 intercepting_pref_filter.get();
400 scoped_refptr<JsonPrefStore> pref_store =
401 new JsonPrefStore(input_file, message_loop_.task_runner(),
402 std::move(intercepting_pref_filter));
403
404 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
405 pref_store->ReadPrefs());
406 EXPECT_FALSE(pref_store->ReadOnly());
407
408 // The store shouldn't be considered initialized until the interceptor
409 // returns.
410 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
411 EXPECT_FALSE(pref_store->IsInitializationComplete());
412 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
413
414 raw_intercepting_pref_filter_->ReleasePrefs();
415
416 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
417 EXPECT_TRUE(pref_store->IsInitializationComplete());
418 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
419
420 // The JSON file looks like this:
421 // {
422 // "homepage": "http://www.cnn.com",
423 // "some_directory": "/usr/local/",
424 // "tabs": {
425 // "new_windows_in_tabs": true,
426 // "max_tabs": 20
427 // }
428 // }
429
430 RunBasicJsonPrefStoreTest(
431 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
432 }
433
434 TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
435 ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
436 temp_dir_.path().AppendASCII("write.json")));
437
438 // Test that the persistent value can be loaded.
439 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
440 ASSERT_TRUE(PathExists(input_file));
441
442 scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
443 new InterceptingPrefFilter());
444 InterceptingPrefFilter* raw_intercepting_pref_filter_ =
445 intercepting_pref_filter.get();
446 scoped_refptr<JsonPrefStore> pref_store =
447 new JsonPrefStore(input_file, message_loop_.task_runner(),
448 std::move(intercepting_pref_filter));
449
450 MockPrefStoreObserver mock_observer;
451 pref_store->AddObserver(&mock_observer);
452
453 // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
454 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
455
456 {
457 pref_store->ReadPrefsAsync(mock_error_delegate);
458
459 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
460 // EXPECT_CALL(*mock_error_delegate,
461 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
462 RunLoop().RunUntilIdle();
463
464 EXPECT_FALSE(pref_store->ReadOnly());
465 EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
466 EXPECT_FALSE(pref_store->IsInitializationComplete());
467 EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
468 }
469
470 {
471 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
472 // EXPECT_CALL(*mock_error_delegate,
473 // OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
474
475 raw_intercepting_pref_filter_->ReleasePrefs();
476
477 EXPECT_FALSE(pref_store->ReadOnly());
478 EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
479 EXPECT_TRUE(pref_store->IsInitializationComplete());
480 EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
481 }
482
483 pref_store->RemoveObserver(&mock_observer);
484
485 // The JSON file looks like this:
486 // {
487 // "homepage": "http://www.cnn.com",
488 // "some_directory": "/usr/local/",
489 // "tabs": {
490 // "new_windows_in_tabs": true,
491 // "max_tabs": 20
492 // }
493 // }
494
495 RunBasicJsonPrefStoreTest(
496 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
497 }
498
499 TEST_F(JsonPrefStoreTest, AlternateFile) {
500 ASSERT_TRUE(
501 base::CopyFile(data_dir_.AppendASCII("read.json"),
502 temp_dir_.path().AppendASCII("alternate.json")));
503
504 // Test that the alternate file is moved to the main file and read as-is from
505 // there.
506 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
507 base::FilePath alternate_input_file =
508 temp_dir_.path().AppendASCII("alternate.json");
509 ASSERT_FALSE(PathExists(input_file));
510 ASSERT_TRUE(PathExists(alternate_input_file));
511 scoped_refptr<JsonPrefStore> pref_store =
512 new JsonPrefStore(input_file, alternate_input_file,
513 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
514
515 ASSERT_FALSE(PathExists(input_file));
516 ASSERT_TRUE(PathExists(alternate_input_file));
517 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
518
519 ASSERT_TRUE(PathExists(input_file));
520 ASSERT_FALSE(PathExists(alternate_input_file));
521
522 EXPECT_FALSE(pref_store->ReadOnly());
523 EXPECT_TRUE(pref_store->IsInitializationComplete());
524
525 // The JSON file looks like this:
526 // {
527 // "homepage": "http://www.cnn.com",
528 // "some_directory": "/usr/local/",
529 // "tabs": {
530 // "new_windows_in_tabs": true,
531 // "max_tabs": 20
532 // }
533 // }
534
535 RunBasicJsonPrefStoreTest(
536 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
537 }
538
539 TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
540 ASSERT_TRUE(
541 base::CopyFile(data_dir_.AppendASCII("read.json"),
542 temp_dir_.path().AppendASCII("write.json")));
543 ASSERT_TRUE(
544 base::CopyFile(data_dir_.AppendASCII("invalid.json"),
545 temp_dir_.path().AppendASCII("alternate.json")));
546
547 // Test that the alternate file is ignored and that the read occurs from the
548 // existing main file. There is no attempt at even deleting the alternate
549 // file as this scenario should never happen in normal user-data-dirs.
550 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
551 base::FilePath alternate_input_file =
552 temp_dir_.path().AppendASCII("alternate.json");
553 ASSERT_TRUE(PathExists(input_file));
554 ASSERT_TRUE(PathExists(alternate_input_file));
555 scoped_refptr<JsonPrefStore> pref_store =
556 new JsonPrefStore(input_file, alternate_input_file,
557 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
558
559 ASSERT_TRUE(PathExists(input_file));
560 ASSERT_TRUE(PathExists(alternate_input_file));
561 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
562
563 ASSERT_TRUE(PathExists(input_file));
564 ASSERT_TRUE(PathExists(alternate_input_file));
565
566 EXPECT_FALSE(pref_store->ReadOnly());
567 EXPECT_TRUE(pref_store->IsInitializationComplete());
568
569 // The JSON file looks like this:
570 // {
571 // "homepage": "http://www.cnn.com",
572 // "some_directory": "/usr/local/",
573 // "tabs": {
574 // "new_windows_in_tabs": true,
575 // "max_tabs": 20
576 // }
577 // }
578
579 RunBasicJsonPrefStoreTest(
580 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
581 }
582
583 TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
584 ASSERT_TRUE(
585 base::CopyFile(data_dir_.AppendASCII("read.json"),
586 temp_dir_.path().AppendASCII("write.json")));
587
588 // Test that the basic read works fine when an alternate file is specified but
589 // does not exist.
590 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
591 base::FilePath alternate_input_file =
592 temp_dir_.path().AppendASCII("alternate.json");
593 ASSERT_TRUE(PathExists(input_file));
594 ASSERT_FALSE(PathExists(alternate_input_file));
595 scoped_refptr<JsonPrefStore> pref_store =
596 new JsonPrefStore(input_file, alternate_input_file,
597 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
598
599 ASSERT_TRUE(PathExists(input_file));
600 ASSERT_FALSE(PathExists(alternate_input_file));
601 ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
602
603 ASSERT_TRUE(PathExists(input_file));
604 ASSERT_FALSE(PathExists(alternate_input_file));
605
606 EXPECT_FALSE(pref_store->ReadOnly());
607 EXPECT_TRUE(pref_store->IsInitializationComplete());
608
609 // The JSON file looks like this:
610 // {
611 // "homepage": "http://www.cnn.com",
612 // "some_directory": "/usr/local/",
613 // "tabs": {
614 // "new_windows_in_tabs": true,
615 // "max_tabs": 20
616 // }
617 // }
618
619 RunBasicJsonPrefStoreTest(
620 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
621 }
622
623 TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
624 ASSERT_TRUE(
625 base::CopyFile(data_dir_.AppendASCII("read.json"),
626 temp_dir_.path().AppendASCII("alternate.json")));
627
628 // Test that the alternate file is moved to the main file and read as-is from
629 // there even when the read is made asynchronously.
630 base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
631 base::FilePath alternate_input_file =
632 temp_dir_.path().AppendASCII("alternate.json");
633 ASSERT_FALSE(PathExists(input_file));
634 ASSERT_TRUE(PathExists(alternate_input_file));
635 scoped_refptr<JsonPrefStore> pref_store =
636 new JsonPrefStore(input_file, alternate_input_file,
637 message_loop_.task_runner(), scoped_ptr<PrefFilter>());
638
639 ASSERT_FALSE(PathExists(input_file));
640 ASSERT_TRUE(PathExists(alternate_input_file));
641
642 {
643 MockPrefStoreObserver mock_observer;
644 pref_store->AddObserver(&mock_observer);
645
646 MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
647 pref_store->ReadPrefsAsync(mock_error_delegate);
648
649 EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
650 EXPECT_CALL(*mock_error_delegate,
651 OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
652 RunLoop().RunUntilIdle();
653 pref_store->RemoveObserver(&mock_observer);
654
655 EXPECT_FALSE(pref_store->ReadOnly());
656 EXPECT_TRUE(pref_store->IsInitializationComplete());
657 }
658
659 ASSERT_TRUE(PathExists(input_file));
660 ASSERT_FALSE(PathExists(alternate_input_file));
661
662 // The JSON file looks like this:
663 // {
664 // "homepage": "http://www.cnn.com",
665 // "some_directory": "/usr/local/",
666 // "tabs": {
667 // "new_windows_in_tabs": true,
668 // "max_tabs": 20
669 // }
670 // }
671
672 RunBasicJsonPrefStoreTest(
673 pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
674 }
675
676 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
677 SimpleTestClock* test_clock = new SimpleTestClock;
678 SetCurrentTimeInMinutes(0, test_clock);
679 JsonPrefStore::WriteCountHistogram histogram(
680 base::TimeDelta::FromSeconds(10),
681 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
682 scoped_ptr<base::Clock>(test_clock));
683 int32_t report_interval =
684 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
685
686 histogram.RecordWriteOccured();
687
688 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
689 histogram.ReportOutstandingWrites();
690 scoped_ptr<HistogramSamples> samples =
691 histogram.GetHistogram()->SnapshotSamples();
692 ASSERT_EQ(1, samples->GetCount(1));
693 ASSERT_EQ(1, samples->TotalCount());
694
695 ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
696 histogram.GetHistogram()->histogram_name());
697 ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
698 }
699
700 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
701 SimpleTestClock* test_clock = new SimpleTestClock;
702 SetCurrentTimeInMinutes(0, test_clock);
703 JsonPrefStore::WriteCountHistogram histogram(
704 base::TimeDelta::FromSeconds(10),
705 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
706 scoped_ptr<base::Clock>(test_clock));
707 int32_t report_interval =
708 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
709
710 histogram.RecordWriteOccured();
711 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
712 histogram.RecordWriteOccured();
713 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
714 histogram.RecordWriteOccured();
715
716 // Nothing should be recorded until the report period has elapsed.
717 scoped_ptr<HistogramSamples> samples =
718 histogram.GetHistogram()->SnapshotSamples();
719 ASSERT_EQ(0, samples->TotalCount());
720
721 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
722 histogram.RecordWriteOccured();
723
724 // Now the report period has elapsed.
725 samples = histogram.GetHistogram()->SnapshotSamples();
726 ASSERT_EQ(1, samples->GetCount(3));
727 ASSERT_EQ(1, samples->TotalCount());
728
729 // The last write won't be recorded because the second count period hasn't
730 // fully elapsed.
731 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
732 histogram.ReportOutstandingWrites();
733
734 samples = histogram.GetHistogram()->SnapshotSamples();
735 ASSERT_EQ(1, samples->GetCount(3));
736 ASSERT_EQ(1, samples->TotalCount());
737 }
738
739 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
740 SimpleTestClock* test_clock = new SimpleTestClock;
741 SetCurrentTimeInMinutes(0, test_clock);
742 JsonPrefStore::WriteCountHistogram histogram(
743 base::TimeDelta::FromSeconds(10),
744 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
745 scoped_ptr<base::Clock>(test_clock));
746 int32_t report_interval =
747 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
748
749 histogram.RecordWriteOccured();
750 SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
751 histogram.RecordWriteOccured();
752 SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
753 histogram.RecordWriteOccured();
754 SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
755 histogram.RecordWriteOccured();
756 SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
757 histogram.RecordWriteOccured();
758 SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
759 histogram.RecordWriteOccured();
760 SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
761 histogram.RecordWriteOccured();
762 SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
763 histogram.RecordWriteOccured();
764 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
765 histogram.RecordWriteOccured();
766
767 // The last write won't be recorded because the second count period hasn't
768 // fully elapsed
769 SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
770 histogram.ReportOutstandingWrites();
771 scoped_ptr<HistogramSamples> samples =
772 histogram.GetHistogram()->SnapshotSamples();
773 ASSERT_EQ(2, samples->GetCount(3));
774 ASSERT_EQ(1, samples->GetCount(2));
775 ASSERT_EQ(3, samples->TotalCount());
776 }
777
778 TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
779 SimpleTestClock* test_clock = new SimpleTestClock;
780 SetCurrentTimeInMinutes(0, test_clock);
781 JsonPrefStore::WriteCountHistogram histogram(
782 base::TimeDelta::FromSeconds(10),
783 base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
784 scoped_ptr<base::Clock>(test_clock));
785 int32_t report_interval =
786 JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
787
788 // 1 write in the first period.
789 histogram.RecordWriteOccured();
790
791 // No writes in the second and third periods.
792
793 // 2 writes in the fourth period.
794 SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
795 histogram.RecordWriteOccured();
796 SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
797 histogram.RecordWriteOccured();
798
799 // No writes in the fifth period.
800
801 // 3 writes in the sixth period.
802 SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
803 histogram.RecordWriteOccured();
804 SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
805 histogram.RecordWriteOccured();
806 SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
807 histogram.RecordWriteOccured();
808
809 SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
810 histogram.ReportOutstandingWrites();
811 scoped_ptr<HistogramSamples> samples =
812 histogram.GetHistogram()->SnapshotSamples();
813 ASSERT_EQ(3, samples->GetCount(0));
814 ASSERT_EQ(1, samples->GetCount(1));
815 ASSERT_EQ(1, samples->GetCount(2));
816 ASSERT_EQ(1, samples->GetCount(3));
817 ASSERT_EQ(6, samples->TotalCount());
818 }
819
820 class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
821 protected:
822 void SetUp() override {
823 JsonPrefStoreTest::SetUp();
824 test_file_ = temp_dir_.path().AppendASCII("test.json");
825 }
826
827 // Creates a JsonPrefStore with the given |file_writer|.
828 scoped_refptr<JsonPrefStore> CreatePrefStore() {
829 return new JsonPrefStore(test_file_, message_loop_.task_runner(),
830 scoped_ptr<PrefFilter>());
831 }
832
833 // Return the ImportantFileWriter for a given JsonPrefStore.
834 ImportantFileWriter* GetImportantFileWriter(
835 scoped_refptr<JsonPrefStore> pref_store) {
836 return &(pref_store->writer_);
837 }
838
839 // Get the contents of kTestFile. Pumps the message loop before returning the
840 // result.
841 std::string GetTestFileContents() {
842 RunLoop().RunUntilIdle();
843 std::string file_contents;
844 ReadFileToString(test_file_, &file_contents);
845 return file_contents;
846 }
847
848 private:
849 base::FilePath test_file_;
850 };
851
852 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
853 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
854 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
855
856 // Set a normal pref and check that it gets scheduled to be written.
857 ASSERT_FALSE(file_writer->HasPendingWrite());
858 pref_store->SetValue("normal",
859 make_scoped_ptr(new base::StringValue("normal")),
860 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
861 ASSERT_TRUE(file_writer->HasPendingWrite());
862 file_writer->DoScheduledWrite();
863 ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
864 ASSERT_FALSE(file_writer->HasPendingWrite());
865
866 // Set a lossy pref and check that it is not scheduled to be written.
867 // SetValue/RemoveValue.
868 pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
869 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
870 ASSERT_FALSE(file_writer->HasPendingWrite());
871 pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
872 ASSERT_FALSE(file_writer->HasPendingWrite());
873
874 // SetValueSilently/RemoveValueSilently.
875 pref_store->SetValueSilently("lossy",
876 make_scoped_ptr(new base::StringValue("lossy")),
877 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
878 ASSERT_FALSE(file_writer->HasPendingWrite());
879 pref_store->RemoveValueSilently("lossy",
880 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
881 ASSERT_FALSE(file_writer->HasPendingWrite());
882
883 // ReportValueChanged.
884 pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
885 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
886 ASSERT_FALSE(file_writer->HasPendingWrite());
887 pref_store->ReportValueChanged("lossy",
888 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
889 ASSERT_FALSE(file_writer->HasPendingWrite());
890
891 // Call CommitPendingWrite and check that the lossy pref and the normal pref
892 // are there with the last values set above.
893 pref_store->CommitPendingWrite();
894 ASSERT_FALSE(file_writer->HasPendingWrite());
895 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
896 GetTestFileContents());
897 }
898
899 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
900 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
901 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
902
903 // Set a lossy pref and check that it is not scheduled to be written.
904 ASSERT_FALSE(file_writer->HasPendingWrite());
905 pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
906 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
907 ASSERT_FALSE(file_writer->HasPendingWrite());
908
909 // Set a normal pref and check that it is scheduled to be written.
910 pref_store->SetValue("normal",
911 make_scoped_ptr(new base::StringValue("normal")),
912 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
913 ASSERT_TRUE(file_writer->HasPendingWrite());
914
915 // Call DoScheduledWrite and check both prefs get written.
916 file_writer->DoScheduledWrite();
917 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
918 GetTestFileContents());
919 ASSERT_FALSE(file_writer->HasPendingWrite());
920 }
921
922 TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
923 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
924 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
925
926 // Set a normal pref and check that it is scheduled to be written.
927 ASSERT_FALSE(file_writer->HasPendingWrite());
928 pref_store->SetValue("normal",
929 make_scoped_ptr(new base::StringValue("normal")),
930 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
931 ASSERT_TRUE(file_writer->HasPendingWrite());
932
933 // Set a lossy pref and check that the write is still scheduled.
934 pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
935 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
936 ASSERT_TRUE(file_writer->HasPendingWrite());
937
938 // Call DoScheduledWrite and check both prefs get written.
939 file_writer->DoScheduledWrite();
940 ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
941 GetTestFileContents());
942 ASSERT_FALSE(file_writer->HasPendingWrite());
943 }
944
945 TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
946 scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
947 ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
948
949 // Set a lossy pref and check that it is not scheduled to be written.
950 pref_store->SetValue("lossy", make_scoped_ptr(new base::StringValue("lossy")),
951 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
952 ASSERT_FALSE(file_writer->HasPendingWrite());
953
954 // Schedule pending lossy writes and check that it is scheduled.
955 pref_store->SchedulePendingLossyWrites();
956 ASSERT_TRUE(file_writer->HasPendingWrite());
957
958 // Call CommitPendingWrite and check that the lossy pref is there with the
959 // last value set above.
960 pref_store->CommitPendingWrite();
961 ASSERT_FALSE(file_writer->HasPendingWrite());
962 ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
963 }
964
965 } // namespace base
OLDNEW
« no previous file with comments | « base/prefs/json_pref_store.cc ('k') | base/prefs/mock_pref_change_callback.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698