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

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

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

Powered by Google App Engine
This is Rietveld 408576698