OLD | NEW |
| (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 | |
OLD | NEW |