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.
6 #include "chrome/browser/sync/invalidations/invalidator_storage.h"
8 #include "base/message_loop.h"
9 #include "base/string_number_conversions.h"
10 #include "base/string_util.h"
11 #include "chrome/common/pref_names.h"
12 #include "chrome/test/base/testing_pref_service.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using syncer::InvalidationStateMap
;
20 bool operator==(const InvalidationState
& lhs
, const InvalidationState
& rhs
) {
21 return lhs
.version
== rhs
.version
;
26 namespace browser_sync
{
30 const char kSourceKey
[] = "source";
31 const char kNameKey
[] = "name";
32 const char kMaxVersionKey
[] = "max-version";
34 const int kChromeSyncSourceId
= 1004;
38 class InvalidatorStorageTest
: public testing::Test
{
40 InvalidatorStorageTest()
41 : kBookmarksId_(kChromeSyncSourceId
, "BOOKMARK"),
42 kPreferencesId_(kChromeSyncSourceId
, "PREFERENCE"),
43 kAppNotificationsId_(kChromeSyncSourceId
, "APP_NOTIFICATION"),
44 kAutofillId_(kChromeSyncSourceId
, "AUTOFILL") {}
47 TestingPrefService pref_service_
;
49 const invalidation::ObjectId kBookmarksId_
;
50 const invalidation::ObjectId kPreferencesId_
;
51 const invalidation::ObjectId kAppNotificationsId_
;
52 const invalidation::ObjectId kAutofillId_
;
58 // Set max versions for various keys and verify that they are written and read
60 TEST_F(InvalidatorStorageTest
, MaxInvalidationVersions
) {
61 InvalidatorStorage
storage(&pref_service_
);
63 InvalidationStateMap expected_max_versions
;
64 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
66 expected_max_versions
[kBookmarksId_
].version
= 2;
67 storage
.SetMaxVersion(kBookmarksId_
, 2);
68 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
70 expected_max_versions
[kPreferencesId_
].version
= 5;
71 storage
.SetMaxVersion(kPreferencesId_
, 5);
72 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
74 expected_max_versions
[kAppNotificationsId_
].version
= 3;
75 storage
.SetMaxVersion(kAppNotificationsId_
, 3);
76 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
78 expected_max_versions
[kAppNotificationsId_
].version
= 4;
79 storage
.SetMaxVersion(kAppNotificationsId_
, 4);
80 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
83 // Forgetting an entry should cause that entry to be deleted.
84 TEST_F(InvalidatorStorageTest
, Forget
) {
85 InvalidatorStorage
storage(&pref_service_
);
86 EXPECT_TRUE(storage
.GetAllInvalidationStates().empty());
88 InvalidationStateMap expected_max_versions
;
89 expected_max_versions
[kBookmarksId_
].version
= 2;
90 expected_max_versions
[kPreferencesId_
].version
= 5;
91 storage
.SetMaxVersion(kBookmarksId_
, 2);
92 storage
.SetMaxVersion(kPreferencesId_
, 5);
93 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
95 expected_max_versions
.erase(kPreferencesId_
);
96 syncer::ObjectIdSet to_forget
;
97 to_forget
.insert(kPreferencesId_
);
98 storage
.Forget(to_forget
);
99 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
102 // Clearing the storage should erase all version map entries and the bootstrap
104 TEST_F(InvalidatorStorageTest
, Clear
) {
105 InvalidatorStorage
storage(&pref_service_
);
106 EXPECT_TRUE(storage
.GetAllInvalidationStates().empty());
107 EXPECT_TRUE(storage
.GetBootstrapData().empty());
109 storage
.SetBootstrapData("test");
110 EXPECT_EQ("test", storage
.GetBootstrapData());
112 InvalidationStateMap expected_max_versions
;
113 expected_max_versions
[kAppNotificationsId_
].version
= 3;
114 storage
.SetMaxVersion(kAppNotificationsId_
, 3);
115 EXPECT_EQ(expected_max_versions
, storage
.GetAllInvalidationStates());
120 EXPECT_TRUE(storage
.GetAllInvalidationStates().empty());
121 EXPECT_TRUE(storage
.GetBootstrapData().empty());
124 TEST_F(InvalidatorStorageTest
, SerializeEmptyMap
) {
125 InvalidationStateMap empty_map
;
126 base::ListValue list
;
127 InvalidatorStorage::SerializeToList(empty_map
, &list
);
128 EXPECT_TRUE(list
.empty());
131 // Make sure we don't choke on a variety of malformed input.
132 TEST_F(InvalidatorStorageTest
, DeserializeFromListInvalidFormat
) {
133 InvalidationStateMap map
;
134 base::ListValue list_with_invalid_format
;
135 DictionaryValue
* value
;
137 // The various cases below use distinct values to make it easier to track down
139 value
= new DictionaryValue();
140 list_with_invalid_format
.Append(value
);
142 value
= new DictionaryValue();
143 value
->SetString("completely", "invalid");
144 list_with_invalid_format
.Append(value
);
146 // Missing two required fields
147 value
= new DictionaryValue();
148 value
->SetString(kSourceKey
, "10");
149 list_with_invalid_format
.Append(value
);
151 value
= new DictionaryValue();
152 value
->SetString(kNameKey
, "missing source and version");
153 list_with_invalid_format
.Append(value
);
155 value
= new DictionaryValue();
156 value
->SetString(kMaxVersionKey
, "3");
157 list_with_invalid_format
.Append(value
);
159 // Missing one required field
160 value
= new DictionaryValue();
161 value
->SetString(kSourceKey
, "14");
162 value
->SetString(kNameKey
, "missing version");
163 list_with_invalid_format
.Append(value
);
165 value
= new DictionaryValue();
166 value
->SetString(kSourceKey
, "233");
167 value
->SetString(kMaxVersionKey
, "5");
168 list_with_invalid_format
.Append(value
);
170 value
= new DictionaryValue();
171 value
->SetString(kNameKey
, "missing source");
172 value
->SetString(kMaxVersionKey
, "25");
173 list_with_invalid_format
.Append(value
);
175 // Invalid values in fields
176 value
= new DictionaryValue();
177 value
->SetString(kSourceKey
, "a");
178 value
->SetString(kNameKey
, "bad source");
179 value
->SetString(kMaxVersionKey
, "12");
180 list_with_invalid_format
.Append(value
);
182 value
= new DictionaryValue();
183 value
->SetString(kSourceKey
, "1");
184 value
->SetString(kNameKey
, "bad max version");
185 value
->SetString(kMaxVersionKey
, "a");
186 list_with_invalid_format
.Append(value
);
188 // And finally something that should work.
189 invalidation::ObjectId
valid_id(42, "this should work");
190 value
= new DictionaryValue();
191 value
->SetString(kSourceKey
, "42");
192 value
->SetString(kNameKey
, valid_id
.name());
193 value
->SetString(kMaxVersionKey
, "20");
194 list_with_invalid_format
.Append(value
);
196 InvalidatorStorage::DeserializeFromList(list_with_invalid_format
, &map
);
198 EXPECT_EQ(1U, map
.size());
199 EXPECT_EQ(20, map
[valid_id
].version
);
202 // Tests behavior when there are duplicate entries for a single key. The value
203 // of the last entry with that key should be used in the version map.
204 TEST_F(InvalidatorStorageTest
, DeserializeFromListWithDuplicates
) {
205 InvalidationStateMap map
;
206 base::ListValue list
;
207 DictionaryValue
* value
;
209 value
= new DictionaryValue();
210 value
->SetString(kSourceKey
, base::IntToString(kBookmarksId_
.source()));
211 value
->SetString(kNameKey
, kBookmarksId_
.name());
212 value
->SetString(kMaxVersionKey
, "20");
214 value
= new DictionaryValue();
215 value
->SetString(kSourceKey
, base::IntToString(kAutofillId_
.source()));
216 value
->SetString(kNameKey
, kAutofillId_
.name());
217 value
->SetString(kMaxVersionKey
, "10");
219 value
= new DictionaryValue();
220 value
->SetString(kSourceKey
, base::IntToString(kBookmarksId_
.source()));
221 value
->SetString(kNameKey
, kBookmarksId_
.name());
222 value
->SetString(kMaxVersionKey
, "15");
225 InvalidatorStorage::DeserializeFromList(list
, &map
);
226 EXPECT_EQ(2U, map
.size());
227 EXPECT_EQ(10, map
[kAutofillId_
].version
);
228 EXPECT_EQ(15, map
[kBookmarksId_
].version
);
231 TEST_F(InvalidatorStorageTest
, DeserializeFromEmptyList
) {
232 InvalidationStateMap map
;
233 base::ListValue list
;
234 InvalidatorStorage::DeserializeFromList(list
, &map
);
235 EXPECT_TRUE(map
.empty());
238 // Tests that deserializing a well-formed value results in the expected version
240 TEST_F(InvalidatorStorageTest
, DeserializeFromListBasic
) {
241 InvalidationStateMap map
;
242 base::ListValue list
;
243 DictionaryValue
* value
;
245 value
= new DictionaryValue();
246 value
->SetString(kSourceKey
, base::IntToString(kAutofillId_
.source()));
247 value
->SetString(kNameKey
, kAutofillId_
.name());
248 value
->SetString(kMaxVersionKey
, "10");
250 value
= new DictionaryValue();
251 value
->SetString(kSourceKey
, base::IntToString(kBookmarksId_
.source()));
252 value
->SetString(kNameKey
, kBookmarksId_
.name());
253 value
->SetString(kMaxVersionKey
, "15");
256 InvalidatorStorage::DeserializeFromList(list
, &map
);
257 EXPECT_EQ(2U, map
.size());
258 EXPECT_EQ(10, map
[kAutofillId_
].version
);
259 EXPECT_EQ(15, map
[kBookmarksId_
].version
);
262 // Tests for legacy deserialization code.
263 TEST_F(InvalidatorStorageTest
, DeserializeMapOutOfRange
) {
264 InvalidationStateMap map
;
265 base::DictionaryValue dict_with_out_of_range_type
;
267 dict_with_out_of_range_type
.SetString(
268 base::IntToString(syncer::TOP_LEVEL_FOLDER
), "100");
269 dict_with_out_of_range_type
.SetString(
270 base::IntToString(syncer::BOOKMARKS
), "5");
272 InvalidatorStorage::DeserializeMap(&dict_with_out_of_range_type
, &map
);
274 EXPECT_EQ(1U, map
.size());
275 EXPECT_EQ(5, map
[kBookmarksId_
].version
);
278 TEST_F(InvalidatorStorageTest
, DeserializeMapInvalidFormat
) {
279 InvalidationStateMap map
;
280 base::DictionaryValue dict_with_invalid_format
;
282 dict_with_invalid_format
.SetString("whoops", "5");
283 dict_with_invalid_format
.SetString("ohnoes", "whoops");
284 dict_with_invalid_format
.SetString(
285 base::IntToString(syncer::BOOKMARKS
), "ohnoes");
286 dict_with_invalid_format
.SetString(
287 base::IntToString(syncer::AUTOFILL
), "10");
289 InvalidatorStorage::DeserializeMap(&dict_with_invalid_format
, &map
);
291 EXPECT_EQ(1U, map
.size());
292 EXPECT_EQ(10, map
[kAutofillId_
].version
);
295 TEST_F(InvalidatorStorageTest
, DeserializeMapEmptyDictionary
) {
296 InvalidationStateMap map
;
297 base::DictionaryValue dict
;
298 InvalidatorStorage::DeserializeMap(&dict
, &map
);
299 EXPECT_TRUE(map
.empty());
302 TEST_F(InvalidatorStorageTest
, DeserializeMapBasic
) {
303 InvalidationStateMap map
;
304 base::DictionaryValue dict
;
306 dict
.SetString(base::IntToString(syncer::AUTOFILL
), "10");
307 dict
.SetString(base::IntToString(syncer::BOOKMARKS
), "15");
309 InvalidatorStorage::DeserializeMap(&dict
, &map
);
310 EXPECT_EQ(2U, map
.size());
311 EXPECT_EQ(10, map
[kAutofillId_
].version
);
312 EXPECT_EQ(15, map
[kBookmarksId_
].version
);
315 // Test that the migration code for the legacy preference works as expected.
316 // Migration should happen on construction of InvalidatorStorage.
317 TEST_F(InvalidatorStorageTest
, MigrateLegacyPreferences
) {
318 base::DictionaryValue
* legacy_dict
= new DictionaryValue
;
319 legacy_dict
->SetString(base::IntToString(syncer::AUTOFILL
), "10");
320 legacy_dict
->SetString(base::IntToString(syncer::BOOKMARKS
), "32");
321 legacy_dict
->SetString(base::IntToString(syncer::PREFERENCES
), "54");
322 pref_service_
.SetUserPref(prefs::kSyncMaxInvalidationVersions
, legacy_dict
);
323 InvalidatorStorage
storage(&pref_service_
);
325 // Legacy pref should be cleared.
326 const base::DictionaryValue
* dict
=
327 pref_service_
.GetDictionary(prefs::kSyncMaxInvalidationVersions
);
328 EXPECT_TRUE(dict
->empty());
330 // Validate the new pref is set correctly.
331 InvalidationStateMap map
;
332 const base::ListValue
* list
=
333 pref_service_
.GetList(prefs::kInvalidatorMaxInvalidationVersions
);
334 InvalidatorStorage::DeserializeFromList(*list
, &map
);
336 EXPECT_EQ(3U, map
.size());
337 EXPECT_EQ(10, map
[kAutofillId_
].version
);
338 EXPECT_EQ(32, map
[kBookmarksId_
].version
);
339 EXPECT_EQ(54, map
[kPreferencesId_
].version
);
342 TEST_F(InvalidatorStorageTest
, SetGetBootstrapData
) {
343 InvalidatorStorage
storage(&pref_service_
);
344 const std::string
mess("n\0tK\0\0l\344", 8);
345 ASSERT_FALSE(IsStringUTF8(mess
));
347 storage
.SetBootstrapData(mess
);
348 EXPECT_EQ(mess
, storage
.GetBootstrapData());
351 } // namespace browser_sync