OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/json/json_reader.h" | |
10 #include "base/json/json_writer.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "base/task.h" | |
15 #include "chrome/browser/extensions/extension_settings.h" | |
16 #include "chrome/browser/extensions/extension_settings_storage_cache.h" | |
17 #include "chrome/browser/extensions/extension_settings_noop_storage.h" | |
18 #include "chrome/browser/extensions/extension_settings_sync_util.h" | |
19 #include "chrome/browser/extensions/syncable_extension_settings_storage.h" | |
20 #include "chrome/browser/extensions/test_extension_service.h" | |
21 #include "chrome/browser/sync/api/sync_change_processor.h" | |
22 #include "content/browser/browser_thread.h" | |
23 | |
akalin
2011/09/15 19:56:44
Add TODO somewhere to also write integration tests
not at google - send to devlin
2011/09/16 05:18:59
Done.
| |
24 namespace { | |
25 | |
26 // Gets the pretty-printed JSON for a value. | |
27 static std::string GetJson(const Value& value) { | |
28 std::string json; | |
29 base::JSONWriter::Write(&value, true, &json); | |
30 return json; | |
31 } | |
32 | |
33 // Returns whether two Values are equal. | |
34 testing::AssertionResult ValuesEq( | |
35 const char* expected_expr, | |
36 const char* actual_expr, | |
37 const Value* expected, | |
38 const Value* actual) { | |
39 if (expected == actual) { | |
40 return testing::AssertionSuccess(); | |
41 } | |
42 if (!expected && actual) { | |
43 return testing::AssertionFailure() << | |
44 "Expected NULL, actual: " << GetJson(*actual); | |
45 } | |
46 if (expected && !actual) { | |
47 return testing::AssertionFailure() << | |
48 "Expected: " << GetJson(*expected) << ", actual NULL"; | |
49 } | |
50 if (!expected->Equals(actual)) { | |
51 return testing::AssertionFailure() << | |
52 "Expected: " << GetJson(*expected) << ", actual: " << GetJson(*actual); | |
53 } | |
54 return testing::AssertionSuccess(); | |
55 } | |
56 | |
57 // Returns whether the result of a storage operation is an expected value. | |
58 // Logs when different. | |
59 testing::AssertionResult SettingsEq( | |
60 const char* expected_expr, | |
61 const char* actual_expr, | |
62 const DictionaryValue* expected, | |
63 const ExtensionSettingsStorage::Result actual) { | |
64 if (actual.HasError()) { | |
65 return testing::AssertionFailure() << | |
66 "Expected: " << GetJson(*expected) << | |
67 ", actual has error: " << actual.GetError(); | |
68 } | |
69 return ValuesEq( | |
70 expected_expr, actual_expr, expected, actual.GetSettings()); | |
71 } | |
72 | |
73 // SyncChangeProcessor which just records the changes made, accessed after | |
74 // being converted to the more useful ExtensionSettingSyncData via changes(). | |
75 class MockSyncChangeProcessor : public SyncChangeProcessor { | |
76 public: | |
77 virtual SyncError ProcessSyncChanges( | |
78 const tracked_objects::Location& from_here, | |
79 const SyncChangeList& change_list) OVERRIDE { | |
80 for (SyncChangeList::const_iterator it = change_list.begin(); | |
81 it != change_list.end(); ++it) { | |
82 ExtensionSettingSyncData data(*it); | |
83 DCHECK(data.value()); | |
akalin
2011/09/15 19:56:44
prefer
if (!data.value()) {
ADD_FAILURE();
c
not at google - send to devlin
2011/09/16 05:18:59
Done.
| |
84 changes_.push_back(data); | |
85 } | |
86 return SyncError(); | |
87 } | |
88 | |
89 const ExtensionSettingSyncDataList& changes() { return changes_; } | |
90 | |
91 void ClearChanges() { | |
92 changes_.clear(); | |
93 } | |
94 | |
95 // Returns the only change for a given extension setting. If there is not | |
96 // exactly 1 change for that key, a test assertion will fail. | |
97 ExtensionSettingSyncData GetOnlyChange( | |
98 const std::string& extension_id, const std::string& key) { | |
99 ExtensionSettingSyncDataList matching_changes; | |
100 for (ExtensionSettingSyncDataList::iterator it = changes_.begin(); | |
101 it != changes_.end(); ++it) { | |
102 if (it->extension_id() == extension_id && it->key() == key) { | |
103 matching_changes.push_back(*it); | |
104 } | |
105 } | |
106 DCHECK_EQ(1u, matching_changes.size()) << | |
akalin
2011/09/15 19:56:44
prefer:
if (matching_changes.size() != 1u) {
AD
not at google - send to devlin
2011/09/16 05:18:59
Done.
| |
107 "Not exactly 1 change for " << extension_id << "/" << key << | |
108 " (out of " << changes_.size() << ")"; | |
109 return matching_changes[0]; | |
110 } | |
111 | |
112 private: | |
113 ExtensionSettingSyncDataList changes_; | |
114 }; | |
115 | |
116 // Fake ExtensionService which just allows Extensions with a specific id to be | |
117 // added to it and returned. | |
118 class FakeExtensionService : public TestExtensionService { | |
119 public: | |
120 explicit FakeExtensionService(const FilePath& file_path) | |
121 : file_path_(file_path) {} | |
122 | |
123 virtual const ExtensionList* extensions() const OVERRIDE { | |
124 return &extensions_; | |
125 } | |
126 | |
127 virtual const ExtensionList* disabled_extensions() const OVERRIDE { | |
128 return &disabled_extensions_; | |
129 } | |
130 | |
131 virtual const ExtensionList* terminated_extensions() const OVERRIDE { | |
132 return &terminated_extensions_; | |
133 } | |
134 | |
135 // Adds an extension to those that will be returned from extensions(). | |
136 void AddExtension(const std::string& extension_id) { | |
137 DictionaryValue fake_manifest; | |
138 fake_manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0"); | |
139 fake_manifest.SetString(extension_manifest_keys::kName, "unused"); | |
140 | |
141 std::string error; | |
142 scoped_refptr<Extension> extension = Extension::CreateWithId( | |
143 file_path_.AppendASCII(extension_id), | |
144 Extension::INTERNAL, | |
145 fake_manifest, | |
146 Extension::STRICT_ERROR_CHECKS, | |
147 extension_id, | |
148 &error); | |
149 DCHECK(extension); | |
150 next_extension_list()->push_back(extension); | |
151 } | |
152 | |
153 private: | |
154 // Gets the next extension list to add the extension to. | |
155 ExtensionList* next_extension_list() { | |
156 static int next = 0; | |
akalin
2011/09/15 19:56:44
doesn't need to be static, just make it a member v
not at google - send to devlin
2011/09/16 05:18:59
:(
(Though don't need this any more after adding
| |
157 switch (next++ % 3) { | |
158 case 0: return &extensions_; | |
159 case 1: return &disabled_extensions_; | |
160 case 2: return &terminated_extensions_; | |
161 } | |
162 NOTREACHED(); | |
163 return NULL; | |
164 } | |
165 | |
166 FilePath file_path_; | |
167 ExtensionList extensions_; | |
168 ExtensionList disabled_extensions_; | |
169 ExtensionList terminated_extensions_; | |
170 }; | |
171 | |
172 } // namespace | |
173 | |
174 class ExtensionSettingsSyncUnittest : public testing::Test { | |
175 public: | |
176 virtual void SetUp() { | |
177 // Need these so that the DCHECKs for running on FILE or UI threads pass. | |
178 ui_message_loop_.reset(new MessageLoopForUI()); | |
179 ui_thread_.reset( | |
180 new BrowserThread(BrowserThread::UI, MessageLoop::current())); | |
181 file_thread_.reset( | |
182 new BrowserThread(BrowserThread::FILE, MessageLoop::current())); | |
183 sync_.reset(new MockSyncChangeProcessor()); | |
184 | |
185 FilePath temp_dir; | |
186 file_util::CreateNewTempDirectory(FilePath::StringType(), &temp_dir); | |
187 settings_ = new ExtensionSettings(temp_dir); | |
188 service_.reset(new FakeExtensionService(temp_dir)); | |
189 settings_->SetExtensionService(service_.get()); | |
190 } | |
191 | |
192 protected: | |
193 // Creates a new extension storage object and adds a record of the extension | |
194 // to the extension service. | |
195 SyncableExtensionSettingsStorage* GetStorage( | |
196 const std::string& extension_id) { | |
197 bool have_extension = false; | |
198 for (ExtensionList::const_iterator it = service_->extensions()->begin(); | |
199 it != service_->extensions()->end(); ++it) { | |
200 if ((*it)->id() == extension_id) { | |
201 have_extension = true; | |
202 break; | |
203 } | |
204 } | |
205 if (!have_extension) { | |
206 service_->AddExtension(extension_id); | |
207 } | |
208 return static_cast<SyncableExtensionSettingsStorage*>( | |
209 settings_->GetStorage(extension_id)); | |
210 } | |
211 | |
212 scoped_ptr<MockSyncChangeProcessor> sync_; | |
213 scoped_refptr<ExtensionSettings> settings_; | |
214 scoped_ptr<FakeExtensionService> service_; | |
215 | |
216 // Gets all the sync data from settings_ as a map from extension id to its | |
217 // sync data. | |
218 std::map<std::string, ExtensionSettingSyncDataList> GetAllSyncData() { | |
219 SyncDataList as_list = | |
220 settings_->GetAllSyncData(syncable::EXTENSION_SETTINGS); | |
221 std::map<std::string, ExtensionSettingSyncDataList> as_map; | |
222 for (SyncDataList::iterator it = as_list.begin(); | |
223 it != as_list.end(); ++it) { | |
224 ExtensionSettingSyncData sync_data(*it); | |
225 as_map[sync_data.extension_id()].push_back(sync_data); | |
226 } | |
227 return as_map; | |
228 } | |
229 | |
230 private: | |
231 // Need these so that the DCHECKs for running on FILE or UI threads pass. | |
232 scoped_ptr<MessageLoopForUI> ui_message_loop_; | |
akalin
2011/09/15 19:56:44
No need to use scoped_ptr, just set them up in con
not at google - send to devlin
2011/09/16 05:18:59
Done.
| |
233 scoped_ptr<BrowserThread> ui_thread_; | |
234 scoped_ptr<BrowserThread> file_thread_; | |
235 }; | |
236 | |
237 TEST_F(ExtensionSettingsSyncUnittest, NoDataDoesNotInvokeSync) { | |
238 ASSERT_EQ(0u, GetAllSyncData().size()); | |
239 | |
240 // Have one extension created before sync is set up, the other created after. | |
241 GetStorage("s1"); | |
242 ASSERT_EQ(0u, GetAllSyncData().size()); | |
243 | |
244 settings_->MergeDataAndStartSyncing( | |
245 syncable::EXTENSION_SETTINGS, | |
246 SyncDataList(), | |
247 sync_.get()); | |
248 | |
249 GetStorage("s2"); | |
250 ASSERT_EQ(0u, GetAllSyncData().size()); | |
251 | |
252 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
253 | |
254 ASSERT_EQ(0u, sync_->changes().size()); | |
255 ASSERT_EQ(0u, GetAllSyncData().size()); | |
256 } | |
257 | |
258 TEST_F(ExtensionSettingsSyncUnittest, InSyncDataDoesNotInvokeSync) { | |
259 StringValue value1("fooValue"); | |
260 ListValue value2; | |
261 value2.Append(StringValue::CreateStringValue("barValue")); | |
262 | |
263 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1"); | |
264 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2"); | |
265 | |
266 storage1->Set("foo", value1); | |
267 storage2->Set("bar", value2); | |
268 | |
269 std::map<std::string, ExtensionSettingSyncDataList> all_sync_data = | |
270 GetAllSyncData(); | |
271 ASSERT_EQ(2u, all_sync_data.size()); | |
272 ASSERT_EQ(1u, all_sync_data["s1"].size()); | |
273 ASSERT_PRED_FORMAT2(ValuesEq, &value1, all_sync_data["s1"][0].value()); | |
274 ASSERT_EQ(1u, all_sync_data["s2"].size()); | |
275 ASSERT_PRED_FORMAT2(ValuesEq, &value2, all_sync_data["s2"][0].value()); | |
276 | |
277 SyncDataList sync_data; | |
278 sync_data.push_back(extension_settings_sync_util::CreateData( | |
279 "s1", "foo", value1)); | |
280 sync_data.push_back(extension_settings_sync_util::CreateData( | |
281 "s2", "bar", value2)); | |
282 | |
283 settings_->MergeDataAndStartSyncing( | |
284 syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | |
285 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
286 | |
287 // Already in sync, so no changes. | |
288 ASSERT_EQ(0u, sync_->changes().size()); | |
289 } | |
290 | |
291 TEST_F(ExtensionSettingsSyncUnittest, LocalDataWithNoSyncDataIsPushedToSync) { | |
292 StringValue value1("fooValue"); | |
293 ListValue value2; | |
294 value2.Append(StringValue::CreateStringValue("barValue")); | |
295 | |
296 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1"); | |
297 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2"); | |
298 | |
299 storage1->Set("foo", value1); | |
300 storage2->Set("bar", value2); | |
301 | |
302 settings_->MergeDataAndStartSyncing( | |
303 syncable::EXTENSION_SETTINGS, SyncDataList(), sync_.get()); | |
304 | |
305 // All settings should have been pushed to sync. | |
306 ASSERT_EQ(2u, sync_->changes().size()); | |
307 ExtensionSettingSyncData change = sync_->GetOnlyChange("s1", "foo"); | |
308 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
309 ASSERT_TRUE(value1.Equals(change.value())); | |
310 change = sync_->GetOnlyChange("s2", "bar"); | |
311 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
312 ASSERT_TRUE(value2.Equals(change.value())); | |
313 | |
314 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
315 } | |
316 | |
317 TEST_F(ExtensionSettingsSyncUnittest, AnySyncDataOverwritesLocalData) { | |
318 StringValue value1("fooValue"); | |
319 ListValue value2; | |
320 value2.Append(StringValue::CreateStringValue("barValue")); | |
321 | |
322 // Maintain dictionaries mirrored to the expected values of the settings in | |
323 // each storage area. | |
324 DictionaryValue expected1, expected2; | |
325 | |
326 // Pre-populate one of the storage areas. | |
327 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1"); | |
328 storage1->Set("overwriteMe", value1); | |
329 | |
330 SyncDataList sync_data; | |
331 sync_data.push_back(extension_settings_sync_util::CreateData( | |
332 "s1", "foo", value1)); | |
333 sync_data.push_back(extension_settings_sync_util::CreateData( | |
334 "s2", "bar", value2)); | |
335 settings_->MergeDataAndStartSyncing( | |
336 syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | |
337 expected1.Set("foo", value1.DeepCopy()); | |
338 expected2.Set("bar", value2.DeepCopy()); | |
339 | |
340 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2"); | |
341 | |
342 // All changes should be local, so no sync changes. | |
343 ASSERT_EQ(0u, sync_->changes().size()); | |
344 | |
345 // Sync settings should have been pushed to local settings. | |
346 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get()); | |
347 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get()); | |
348 | |
349 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
350 } | |
351 | |
352 TEST_F(ExtensionSettingsSyncUnittest, ProcessSyncChanges) { | |
353 StringValue value1("fooValue"); | |
354 ListValue value2; | |
355 value2.Append(StringValue::CreateStringValue("barValue")); | |
356 | |
357 // Maintain dictionaries mirrored to the expected values of the settings in | |
358 // each storage area. | |
359 DictionaryValue expected1, expected2; | |
360 | |
361 // Make storage1 initialised from local data, storage2 initialised from sync. | |
362 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1"); | |
363 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2"); | |
364 | |
365 storage1->Set("foo", value1); | |
366 expected1.Set("foo", value1.DeepCopy()); | |
367 | |
368 SyncDataList sync_data; | |
369 sync_data.push_back(extension_settings_sync_util::CreateData( | |
370 "s2", "bar", value2)); | |
371 | |
372 settings_->MergeDataAndStartSyncing( | |
373 syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | |
374 expected2.Set("bar", value2.DeepCopy()); | |
375 | |
376 // Make sync add some settings. | |
377 SyncChangeList change_list; | |
378 change_list.push_back(extension_settings_sync_util::CreateAdd( | |
379 "s1", "bar", value2)); | |
380 change_list.push_back(extension_settings_sync_util::CreateAdd( | |
381 "s2", "foo", value1)); | |
382 settings_->ProcessSyncChanges(FROM_HERE, change_list); | |
383 expected1.Set("bar", value2.DeepCopy()); | |
384 expected2.Set("foo", value1.DeepCopy()); | |
385 | |
386 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get()); | |
387 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get()); | |
388 | |
389 // Make sync update some settings, storage1 the new setting, storage2 the | |
390 // initial setting. | |
391 change_list.clear(); | |
392 change_list.push_back(extension_settings_sync_util::CreateUpdate( | |
393 "s1", "bar", value2)); | |
394 change_list.push_back(extension_settings_sync_util::CreateUpdate( | |
395 "s2", "bar", value1)); | |
396 settings_->ProcessSyncChanges(FROM_HERE, change_list); | |
397 expected1.Set("bar", value2.DeepCopy()); | |
398 expected2.Set("bar", value1.DeepCopy()); | |
399 | |
400 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get()); | |
401 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get()); | |
402 | |
403 // Make sync remove some settings, storage1 the initial setting, storage2 the | |
404 // new setting. | |
405 change_list.clear(); | |
406 change_list.push_back(extension_settings_sync_util::CreateDelete( | |
407 "s1", "foo")); | |
408 change_list.push_back(extension_settings_sync_util::CreateDelete( | |
409 "s2", "foo")); | |
410 settings_->ProcessSyncChanges(FROM_HERE, change_list); | |
411 expected1.Remove("foo", NULL); | |
412 expected2.Remove("foo", NULL); | |
413 | |
414 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get()); | |
415 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get()); | |
416 | |
417 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
418 } | |
419 | |
420 TEST_F(ExtensionSettingsSyncUnittest, PushToSync) { | |
421 StringValue value1("fooValue"); | |
422 ListValue value2; | |
423 value2.Append(StringValue::CreateStringValue("barValue")); | |
424 | |
425 // Make storage1/2 initialised from local data, storage3/4 initialised from | |
426 // sync. | |
427 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1"); | |
428 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2"); | |
429 SyncableExtensionSettingsStorage* storage3 = GetStorage("s3"); | |
430 SyncableExtensionSettingsStorage* storage4 = GetStorage("s4"); | |
431 | |
432 storage1->Set("foo", value1); | |
433 storage2->Set("foo", value1); | |
434 | |
435 SyncDataList sync_data; | |
436 sync_data.push_back(extension_settings_sync_util::CreateData( | |
437 "s3", "bar", value2)); | |
438 sync_data.push_back(extension_settings_sync_util::CreateData( | |
439 "s4", "bar", value2)); | |
440 | |
441 settings_->MergeDataAndStartSyncing( | |
442 syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | |
443 | |
444 // Add something locally. | |
445 storage1->Set("bar", value2); | |
446 storage2->Set("bar", value2); | |
447 storage3->Set("foo", value1); | |
448 storage4->Set("foo", value1); | |
449 | |
450 ExtensionSettingSyncData change = sync_->GetOnlyChange("s1", "bar"); | |
451 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
452 ASSERT_TRUE(value2.Equals(change.value())); | |
453 sync_->GetOnlyChange("s2", "bar"); | |
454 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
455 ASSERT_TRUE(value2.Equals(change.value())); | |
456 change = sync_->GetOnlyChange("s3", "foo"); | |
457 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
458 ASSERT_TRUE(value1.Equals(change.value())); | |
459 change = sync_->GetOnlyChange("s4", "foo"); | |
460 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | |
461 ASSERT_TRUE(value1.Equals(change.value())); | |
462 | |
463 // Change something locally, storage1/3 the new setting and storage2/4 the | |
464 // initial setting, for all combinations of local vs sync intialisation and | |
465 // new vs initial. | |
466 sync_->ClearChanges(); | |
467 storage1->Set("bar", value1); | |
468 storage2->Set("foo", value2); | |
469 storage3->Set("bar", value1); | |
470 storage4->Set("foo", value2); | |
471 | |
472 change = sync_->GetOnlyChange("s1", "bar"); | |
473 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
474 ASSERT_TRUE(value1.Equals(change.value())); | |
475 change = sync_->GetOnlyChange("s2", "foo"); | |
476 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
477 ASSERT_TRUE(value2.Equals(change.value())); | |
478 change = sync_->GetOnlyChange("s3", "bar"); | |
479 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
480 ASSERT_TRUE(value1.Equals(change.value())); | |
481 change = sync_->GetOnlyChange("s4", "foo"); | |
482 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
483 ASSERT_TRUE(value2.Equals(change.value())); | |
484 | |
485 // Remove something locally, storage1/3 the new setting and storage2/4 the | |
486 // initial setting, for all combinations of local vs sync intialisation and | |
487 // new vs initial. | |
488 sync_->ClearChanges(); | |
489 storage1->Remove("foo"); | |
490 storage2->Remove("bar"); | |
491 storage3->Remove("foo"); | |
492 storage4->Remove("bar"); | |
493 | |
494 ASSERT_EQ( | |
495 SyncChange::ACTION_DELETE, | |
496 sync_->GetOnlyChange("s1", "foo").change_type()); | |
497 ASSERT_EQ( | |
498 SyncChange::ACTION_DELETE, | |
499 sync_->GetOnlyChange("s2", "bar").change_type()); | |
500 ASSERT_EQ( | |
501 SyncChange::ACTION_DELETE, | |
502 sync_->GetOnlyChange("s3", "foo").change_type()); | |
503 ASSERT_EQ( | |
504 SyncChange::ACTION_DELETE, | |
505 sync_->GetOnlyChange("s4", "bar").change_type()); | |
506 | |
507 // Remove some nonexistent settings. | |
508 sync_->ClearChanges(); | |
509 storage1->Remove("foo"); | |
510 storage2->Remove("bar"); | |
511 storage3->Remove("foo"); | |
512 storage4->Remove("bar"); | |
513 | |
514 ASSERT_EQ(0u, sync_->changes().size()); | |
515 | |
516 // Clear the rest of the settings. Add the removed ones back first so that | |
517 // more than one setting is cleared. | |
518 storage1->Set("foo", value1); | |
519 storage2->Set("bar", value2); | |
520 storage3->Set("foo", value1); | |
521 storage4->Set("bar", value2); | |
522 | |
523 sync_->ClearChanges(); | |
524 storage1->Clear(); | |
525 storage2->Clear(); | |
526 storage3->Clear(); | |
527 storage4->Clear(); | |
528 | |
529 ASSERT_EQ( | |
530 SyncChange::ACTION_DELETE, | |
531 sync_->GetOnlyChange("s1", "foo").change_type()); | |
532 ASSERT_EQ( | |
533 SyncChange::ACTION_DELETE, | |
534 sync_->GetOnlyChange("s1", "bar").change_type()); | |
535 ASSERT_EQ( | |
536 SyncChange::ACTION_DELETE, | |
537 sync_->GetOnlyChange("s2", "foo").change_type()); | |
538 ASSERT_EQ( | |
539 SyncChange::ACTION_DELETE, | |
540 sync_->GetOnlyChange("s2", "bar").change_type()); | |
541 ASSERT_EQ( | |
542 SyncChange::ACTION_DELETE, | |
543 sync_->GetOnlyChange("s3", "foo").change_type()); | |
544 ASSERT_EQ( | |
545 SyncChange::ACTION_DELETE, | |
546 sync_->GetOnlyChange("s3", "bar").change_type()); | |
547 ASSERT_EQ( | |
548 SyncChange::ACTION_DELETE, | |
549 sync_->GetOnlyChange("s4", "foo").change_type()); | |
550 ASSERT_EQ( | |
551 SyncChange::ACTION_DELETE, | |
552 sync_->GetOnlyChange("s4", "bar").change_type()); | |
553 | |
554 settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | |
555 } | |
OLD | NEW |