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/bind.h" | |
6 #include "base/files/scoped_temp_dir.h" | |
7 #include "base/json/json_reader.h" | |
8 #include "base/json/json_writer.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/message_loop.h" | |
11 #include "chrome/browser/extensions/api/storage/leveldb_settings_storage_factory
.h" | |
12 #include "chrome/browser/extensions/api/storage/settings_frontend.h" | |
13 #include "chrome/browser/extensions/api/storage/settings_storage_factory.h" | |
14 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" | |
15 #include "chrome/browser/extensions/api/storage/settings_test_util.h" | |
16 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" | |
17 #include "chrome/browser/extensions/extension_system.h" | |
18 #include "chrome/browser/extensions/test_extension_service.h" | |
19 #include "chrome/browser/value_store/testing_value_store.h" | |
20 #include "content/public/test/test_browser_thread.h" | |
21 #include "sync/api/sync_change_processor.h" | |
22 #include "sync/api/sync_error_factory.h" | |
23 #include "sync/api/sync_error_factory_mock.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 using content::BrowserThread; | |
27 | |
28 namespace extensions { | |
29 | |
30 namespace util = settings_test_util; | |
31 | |
32 namespace { | |
33 | |
34 // To save typing ValueStore::DEFAULTS everywhere. | |
35 const ValueStore::WriteOptions DEFAULTS = ValueStore::DEFAULTS; | |
36 | |
37 // Gets the pretty-printed JSON for a value. | |
38 static std::string GetJson(const Value& value) { | |
39 std::string json; | |
40 base::JSONWriter::WriteWithOptions(&value, | |
41 base::JSONWriter::OPTIONS_PRETTY_PRINT, | |
42 &json); | |
43 return json; | |
44 } | |
45 | |
46 // Returns whether two Values are equal. | |
47 testing::AssertionResult ValuesEq( | |
48 const char* _1, const char* _2, | |
49 const Value* expected, | |
50 const Value* actual) { | |
51 if (expected == actual) { | |
52 return testing::AssertionSuccess(); | |
53 } | |
54 if (!expected && actual) { | |
55 return testing::AssertionFailure() << | |
56 "Expected NULL, actual: " << GetJson(*actual); | |
57 } | |
58 if (expected && !actual) { | |
59 return testing::AssertionFailure() << | |
60 "Expected: " << GetJson(*expected) << ", actual NULL"; | |
61 } | |
62 if (!expected->Equals(actual)) { | |
63 return testing::AssertionFailure() << | |
64 "Expected: " << GetJson(*expected) << ", actual: " << GetJson(*actual); | |
65 } | |
66 return testing::AssertionSuccess(); | |
67 } | |
68 | |
69 // Returns whether the result of a storage operation is an expected value. | |
70 // Logs when different. | |
71 testing::AssertionResult SettingsEq( | |
72 const char* _1, const char* _2, | |
73 const DictionaryValue& expected, | |
74 ValueStore::ReadResult actual) { | |
75 if (actual->HasError()) { | |
76 return testing::AssertionFailure() << | |
77 "Expected: " << GetJson(expected) << | |
78 ", actual has error: " << actual->error(); | |
79 } | |
80 return ValuesEq(_1, _2, &expected, actual->settings().get()); | |
81 } | |
82 | |
83 // SyncChangeProcessor which just records the changes made, accessed after | |
84 // being converted to the more useful SettingSyncData via changes(). | |
85 class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { | |
86 public: | |
87 MockSyncChangeProcessor() : fail_all_requests_(false) {} | |
88 | |
89 // syncer::SyncChangeProcessor implementation. | |
90 virtual syncer::SyncError ProcessSyncChanges( | |
91 const tracked_objects::Location& from_here, | |
92 const syncer::SyncChangeList& change_list) OVERRIDE { | |
93 if (fail_all_requests_) { | |
94 return syncer::SyncError( | |
95 FROM_HERE, | |
96 "MockSyncChangeProcessor: configured to fail", | |
97 change_list[0].sync_data().GetDataType()); | |
98 } | |
99 for (syncer::SyncChangeList::const_iterator it = change_list.begin(); | |
100 it != change_list.end(); ++it) { | |
101 changes_.push_back(SettingSyncData(*it)); | |
102 } | |
103 return syncer::SyncError(); | |
104 } | |
105 | |
106 // Mock methods. | |
107 | |
108 const SettingSyncDataList& changes() { return changes_; } | |
109 | |
110 void ClearChanges() { | |
111 changes_.clear(); | |
112 } | |
113 | |
114 void SetFailAllRequests(bool fail_all_requests) { | |
115 fail_all_requests_ = fail_all_requests; | |
116 } | |
117 | |
118 // Returns the only change for a given extension setting. If there is not | |
119 // exactly 1 change for that key, a test assertion will fail. | |
120 SettingSyncData GetOnlyChange( | |
121 const std::string& extension_id, const std::string& key) { | |
122 SettingSyncDataList matching_changes; | |
123 for (SettingSyncDataList::iterator it = changes_.begin(); | |
124 it != changes_.end(); ++it) { | |
125 if (it->extension_id() == extension_id && it->key() == key) { | |
126 matching_changes.push_back(*it); | |
127 } | |
128 } | |
129 if (matching_changes.empty()) { | |
130 ADD_FAILURE() << "No matching changes for " << extension_id << "/" << | |
131 key << " (out of " << changes_.size() << ")"; | |
132 return SettingSyncData( | |
133 syncer::SyncChange::ACTION_INVALID, "", "", | |
134 scoped_ptr<Value>(new DictionaryValue())); | |
135 } | |
136 if (matching_changes.size() != 1u) { | |
137 ADD_FAILURE() << matching_changes.size() << " matching changes for " << | |
138 extension_id << "/" << key << " (out of " << changes_.size() << ")"; | |
139 } | |
140 return matching_changes[0]; | |
141 } | |
142 | |
143 private: | |
144 SettingSyncDataList changes_; | |
145 bool fail_all_requests_; | |
146 }; | |
147 | |
148 class SyncChangeProcessorDelegate : public syncer::SyncChangeProcessor { | |
149 public: | |
150 explicit SyncChangeProcessorDelegate(syncer::SyncChangeProcessor* recipient) | |
151 : recipient_(recipient) { | |
152 DCHECK(recipient_); | |
153 } | |
154 virtual ~SyncChangeProcessorDelegate() {} | |
155 | |
156 // syncer::SyncChangeProcessor implementation. | |
157 virtual syncer::SyncError ProcessSyncChanges( | |
158 const tracked_objects::Location& from_here, | |
159 const syncer::SyncChangeList& change_list) OVERRIDE { | |
160 return recipient_->ProcessSyncChanges(from_here, change_list); | |
161 } | |
162 | |
163 private: | |
164 // The recipient of all sync changes. | |
165 syncer::SyncChangeProcessor* recipient_; | |
166 | |
167 DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate); | |
168 }; | |
169 | |
170 // SettingsStorageFactory which always returns TestingValueStore objects, | |
171 // and allows individually created objects to be returned. | |
172 class TestingValueStoreFactory : public SettingsStorageFactory { | |
173 public: | |
174 TestingValueStore* GetExisting(const std::string& extension_id) { | |
175 DCHECK(created_.count(extension_id)); | |
176 return created_[extension_id]; | |
177 } | |
178 | |
179 // SettingsStorageFactory implementation. | |
180 virtual ValueStore* Create(const FilePath& base_path, | |
181 const std::string& extension_id) OVERRIDE { | |
182 TestingValueStore* new_storage = new TestingValueStore(); | |
183 DCHECK(!created_.count(extension_id)); | |
184 created_[extension_id] = new_storage; | |
185 return new_storage; | |
186 } | |
187 | |
188 private: | |
189 // SettingsStorageFactory is refcounted. | |
190 virtual ~TestingValueStoreFactory() {} | |
191 | |
192 // None of these storage areas are owned by this factory, so care must be | |
193 // taken when calling GetExisting. | |
194 std::map<std::string, TestingValueStore*> created_; | |
195 }; | |
196 | |
197 } // namespace | |
198 | |
199 class ExtensionSettingsSyncTest : public testing::Test { | |
200 public: | |
201 ExtensionSettingsSyncTest() | |
202 : ui_thread_(BrowserThread::UI, MessageLoop::current()), | |
203 file_thread_(BrowserThread::FILE, MessageLoop::current()), | |
204 storage_factory_(new util::ScopedSettingsStorageFactory()), | |
205 sync_processor_(new MockSyncChangeProcessor), | |
206 sync_processor_delegate_(new SyncChangeProcessorDelegate( | |
207 sync_processor_.get())) {} | |
208 | |
209 virtual void SetUp() OVERRIDE { | |
210 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
211 profile_.reset(new util::MockProfile(temp_dir_.path())); | |
212 storage_factory_->Reset(new LeveldbSettingsStorageFactory()); | |
213 frontend_.reset( | |
214 SettingsFrontend::Create(storage_factory_.get(), profile_.get())); | |
215 } | |
216 | |
217 virtual void TearDown() OVERRIDE { | |
218 frontend_.reset(); | |
219 profile_.reset(); | |
220 // Execute any pending deletion tasks. | |
221 message_loop_.RunUntilIdle(); | |
222 } | |
223 | |
224 protected: | |
225 // Adds a record of an extension or app to the extension service, then returns | |
226 // its storage area. | |
227 ValueStore* AddExtensionAndGetStorage( | |
228 const std::string& id, Extension::Type type) { | |
229 ExtensionServiceInterface* esi = | |
230 extensions::ExtensionSystem::Get(profile_.get())->extension_service(); | |
231 static_cast<extensions::settings_test_util::MockExtensionService*>(esi)-> | |
232 AddExtensionWithId(id, type); | |
233 return util::GetStorage(id, frontend_.get()); | |
234 } | |
235 | |
236 // Gets the syncer::SyncableService for the given sync type. | |
237 syncer::SyncableService* GetSyncableService(syncer::ModelType model_type) { | |
238 MessageLoop::current()->RunUntilIdle(); | |
239 return frontend_->GetBackendForSync(model_type); | |
240 } | |
241 | |
242 // Gets all the sync data from the SyncableService for a sync type as a map | |
243 // from extension id to its sync data. | |
244 std::map<std::string, SettingSyncDataList> GetAllSyncData( | |
245 syncer::ModelType model_type) { | |
246 syncer::SyncDataList as_list = | |
247 GetSyncableService(model_type)->GetAllSyncData(model_type); | |
248 std::map<std::string, SettingSyncDataList> as_map; | |
249 for (syncer::SyncDataList::iterator it = as_list.begin(); | |
250 it != as_list.end(); ++it) { | |
251 SettingSyncData sync_data(*it); | |
252 as_map[sync_data.extension_id()].push_back(sync_data); | |
253 } | |
254 return as_map; | |
255 } | |
256 | |
257 // Need these so that the DCHECKs for running on FILE or UI threads pass. | |
258 MessageLoop message_loop_; | |
259 content::TestBrowserThread ui_thread_; | |
260 content::TestBrowserThread file_thread_; | |
261 | |
262 base::ScopedTempDir temp_dir_; | |
263 scoped_ptr<util::MockProfile> profile_; | |
264 scoped_ptr<SettingsFrontend> frontend_; | |
265 scoped_refptr<util::ScopedSettingsStorageFactory> storage_factory_; | |
266 scoped_ptr<MockSyncChangeProcessor> sync_processor_; | |
267 scoped_ptr<SyncChangeProcessorDelegate> sync_processor_delegate_; | |
268 }; | |
269 | |
270 // Get a semblance of coverage for both EXTENSION_SETTINGS and APP_SETTINGS | |
271 // sync by roughly alternative which one to test. | |
272 | |
273 TEST_F(ExtensionSettingsSyncTest, NoDataDoesNotInvokeSync) { | |
274 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
275 Extension::Type type = Extension::TYPE_EXTENSION; | |
276 | |
277 EXPECT_EQ(0u, GetAllSyncData(model_type).size()); | |
278 | |
279 // Have one extension created before sync is set up, the other created after. | |
280 AddExtensionAndGetStorage("s1", type); | |
281 EXPECT_EQ(0u, GetAllSyncData(model_type).size()); | |
282 | |
283 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
284 model_type, | |
285 syncer::SyncDataList(), | |
286 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
287 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
288 | |
289 AddExtensionAndGetStorage("s2", type); | |
290 EXPECT_EQ(0u, GetAllSyncData(model_type).size()); | |
291 | |
292 GetSyncableService(model_type)->StopSyncing(model_type); | |
293 | |
294 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
295 EXPECT_EQ(0u, GetAllSyncData(model_type).size()); | |
296 } | |
297 | |
298 TEST_F(ExtensionSettingsSyncTest, InSyncDataDoesNotInvokeSync) { | |
299 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
300 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
301 | |
302 StringValue value1("fooValue"); | |
303 ListValue value2; | |
304 value2.Append(StringValue::CreateStringValue("barValue")); | |
305 | |
306 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
307 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
308 | |
309 storage1->Set(DEFAULTS, "foo", value1); | |
310 storage2->Set(DEFAULTS, "bar", value2); | |
311 | |
312 std::map<std::string, SettingSyncDataList> all_sync_data = | |
313 GetAllSyncData(model_type); | |
314 EXPECT_EQ(2u, all_sync_data.size()); | |
315 EXPECT_EQ(1u, all_sync_data["s1"].size()); | |
316 EXPECT_PRED_FORMAT2(ValuesEq, &value1, &all_sync_data["s1"][0].value()); | |
317 EXPECT_EQ(1u, all_sync_data["s2"].size()); | |
318 EXPECT_PRED_FORMAT2(ValuesEq, &value2, &all_sync_data["s2"][0].value()); | |
319 | |
320 syncer::SyncDataList sync_data; | |
321 sync_data.push_back(settings_sync_util::CreateData( | |
322 "s1", "foo", value1, model_type)); | |
323 sync_data.push_back(settings_sync_util::CreateData( | |
324 "s2", "bar", value2, model_type)); | |
325 | |
326 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
327 model_type, sync_data, | |
328 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
329 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
330 | |
331 // Already in sync, so no changes. | |
332 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
333 | |
334 // Regression test: not-changing the synced value shouldn't result in a sync | |
335 // change, and changing the synced value should result in an update. | |
336 storage1->Set(DEFAULTS, "foo", value1); | |
337 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
338 | |
339 storage1->Set(DEFAULTS, "foo", value2); | |
340 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
341 SettingSyncData change = sync_processor_->GetOnlyChange("s1", "foo"); | |
342 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type()); | |
343 EXPECT_TRUE(value2.Equals(&change.value())); | |
344 | |
345 GetSyncableService(model_type)->StopSyncing(model_type); | |
346 } | |
347 | |
348 TEST_F(ExtensionSettingsSyncTest, LocalDataWithNoSyncDataIsPushedToSync) { | |
349 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
350 Extension::Type type = Extension::TYPE_EXTENSION; | |
351 | |
352 StringValue value1("fooValue"); | |
353 ListValue value2; | |
354 value2.Append(StringValue::CreateStringValue("barValue")); | |
355 | |
356 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
357 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
358 | |
359 storage1->Set(DEFAULTS, "foo", value1); | |
360 storage2->Set(DEFAULTS, "bar", value2); | |
361 | |
362 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
363 model_type, | |
364 syncer::SyncDataList(), | |
365 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
366 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
367 | |
368 // All settings should have been pushed to sync. | |
369 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
370 SettingSyncData change = sync_processor_->GetOnlyChange("s1", "foo"); | |
371 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
372 EXPECT_TRUE(value1.Equals(&change.value())); | |
373 change = sync_processor_->GetOnlyChange("s2", "bar"); | |
374 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
375 EXPECT_TRUE(value2.Equals(&change.value())); | |
376 | |
377 GetSyncableService(model_type)->StopSyncing(model_type); | |
378 } | |
379 | |
380 TEST_F(ExtensionSettingsSyncTest, AnySyncDataOverwritesLocalData) { | |
381 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
382 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
383 | |
384 StringValue value1("fooValue"); | |
385 ListValue value2; | |
386 value2.Append(StringValue::CreateStringValue("barValue")); | |
387 | |
388 // Maintain dictionaries mirrored to the expected values of the settings in | |
389 // each storage area. | |
390 DictionaryValue expected1, expected2; | |
391 | |
392 // Pre-populate one of the storage areas. | |
393 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
394 storage1->Set(DEFAULTS, "overwriteMe", value1); | |
395 | |
396 syncer::SyncDataList sync_data; | |
397 sync_data.push_back(settings_sync_util::CreateData( | |
398 "s1", "foo", value1, model_type)); | |
399 sync_data.push_back(settings_sync_util::CreateData( | |
400 "s2", "bar", value2, model_type)); | |
401 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
402 model_type, sync_data, | |
403 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
404 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
405 expected1.Set("foo", value1.DeepCopy()); | |
406 expected2.Set("bar", value2.DeepCopy()); | |
407 | |
408 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
409 | |
410 // All changes should be local, so no sync changes. | |
411 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
412 | |
413 // Sync settings should have been pushed to local settings. | |
414 EXPECT_PRED_FORMAT2(SettingsEq, expected1, storage1->Get()); | |
415 EXPECT_PRED_FORMAT2(SettingsEq, expected2, storage2->Get()); | |
416 | |
417 GetSyncableService(model_type)->StopSyncing(model_type); | |
418 } | |
419 | |
420 TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) { | |
421 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
422 Extension::Type type = Extension::TYPE_EXTENSION; | |
423 | |
424 StringValue value1("fooValue"); | |
425 ListValue value2; | |
426 value2.Append(StringValue::CreateStringValue("barValue")); | |
427 | |
428 // Maintain dictionaries mirrored to the expected values of the settings in | |
429 // each storage area. | |
430 DictionaryValue expected1, expected2; | |
431 | |
432 // Make storage1 initialised from local data, storage2 initialised from sync. | |
433 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
434 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
435 | |
436 storage1->Set(DEFAULTS, "foo", value1); | |
437 expected1.Set("foo", value1.DeepCopy()); | |
438 | |
439 syncer::SyncDataList sync_data; | |
440 sync_data.push_back(settings_sync_util::CreateData( | |
441 "s2", "bar", value2, model_type)); | |
442 | |
443 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
444 model_type, sync_data, | |
445 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
446 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
447 expected2.Set("bar", value2.DeepCopy()); | |
448 | |
449 // Make sync add some settings. | |
450 syncer::SyncChangeList change_list; | |
451 change_list.push_back(settings_sync_util::CreateAdd( | |
452 "s1", "bar", value2, model_type)); | |
453 change_list.push_back(settings_sync_util::CreateAdd( | |
454 "s2", "foo", value1, model_type)); | |
455 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
456 expected1.Set("bar", value2.DeepCopy()); | |
457 expected2.Set("foo", value1.DeepCopy()); | |
458 | |
459 EXPECT_PRED_FORMAT2(SettingsEq, expected1, storage1->Get()); | |
460 EXPECT_PRED_FORMAT2(SettingsEq, expected2, storage2->Get()); | |
461 | |
462 // Make sync update some settings, storage1 the new setting, storage2 the | |
463 // initial setting. | |
464 change_list.clear(); | |
465 change_list.push_back(settings_sync_util::CreateUpdate( | |
466 "s1", "bar", value2, model_type)); | |
467 change_list.push_back(settings_sync_util::CreateUpdate( | |
468 "s2", "bar", value1, model_type)); | |
469 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
470 expected1.Set("bar", value2.DeepCopy()); | |
471 expected2.Set("bar", value1.DeepCopy()); | |
472 | |
473 EXPECT_PRED_FORMAT2(SettingsEq, expected1, storage1->Get()); | |
474 EXPECT_PRED_FORMAT2(SettingsEq, expected2, storage2->Get()); | |
475 | |
476 // Make sync remove some settings, storage1 the initial setting, storage2 the | |
477 // new setting. | |
478 change_list.clear(); | |
479 change_list.push_back(settings_sync_util::CreateDelete( | |
480 "s1", "foo", model_type)); | |
481 change_list.push_back(settings_sync_util::CreateDelete( | |
482 "s2", "foo", model_type)); | |
483 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
484 expected1.Remove("foo", NULL); | |
485 expected2.Remove("foo", NULL); | |
486 | |
487 EXPECT_PRED_FORMAT2(SettingsEq, expected1, storage1->Get()); | |
488 EXPECT_PRED_FORMAT2(SettingsEq, expected2, storage2->Get()); | |
489 | |
490 GetSyncableService(model_type)->StopSyncing(model_type); | |
491 } | |
492 | |
493 TEST_F(ExtensionSettingsSyncTest, PushToSync) { | |
494 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
495 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
496 | |
497 StringValue value1("fooValue"); | |
498 ListValue value2; | |
499 value2.Append(StringValue::CreateStringValue("barValue")); | |
500 | |
501 // Make storage1/2 initialised from local data, storage3/4 initialised from | |
502 // sync. | |
503 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
504 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
505 ValueStore* storage3 = AddExtensionAndGetStorage("s3", type); | |
506 ValueStore* storage4 = AddExtensionAndGetStorage("s4", type); | |
507 | |
508 storage1->Set(DEFAULTS, "foo", value1); | |
509 storage2->Set(DEFAULTS, "foo", value1); | |
510 | |
511 syncer::SyncDataList sync_data; | |
512 sync_data.push_back(settings_sync_util::CreateData( | |
513 "s3", "bar", value2, model_type)); | |
514 sync_data.push_back(settings_sync_util::CreateData( | |
515 "s4", "bar", value2, model_type)); | |
516 | |
517 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
518 model_type, sync_data, | |
519 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
520 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
521 | |
522 // Add something locally. | |
523 storage1->Set(DEFAULTS, "bar", value2); | |
524 storage2->Set(DEFAULTS, "bar", value2); | |
525 storage3->Set(DEFAULTS, "foo", value1); | |
526 storage4->Set(DEFAULTS, "foo", value1); | |
527 | |
528 SettingSyncData change = sync_processor_->GetOnlyChange("s1", "bar"); | |
529 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
530 EXPECT_TRUE(value2.Equals(&change.value())); | |
531 sync_processor_->GetOnlyChange("s2", "bar"); | |
532 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
533 EXPECT_TRUE(value2.Equals(&change.value())); | |
534 change = sync_processor_->GetOnlyChange("s3", "foo"); | |
535 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
536 EXPECT_TRUE(value1.Equals(&change.value())); | |
537 change = sync_processor_->GetOnlyChange("s4", "foo"); | |
538 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, change.change_type()); | |
539 EXPECT_TRUE(value1.Equals(&change.value())); | |
540 | |
541 // Change something locally, storage1/3 the new setting and storage2/4 the | |
542 // initial setting, for all combinations of local vs sync intialisation and | |
543 // new vs initial. | |
544 sync_processor_->ClearChanges(); | |
545 storage1->Set(DEFAULTS, "bar", value1); | |
546 storage2->Set(DEFAULTS, "foo", value2); | |
547 storage3->Set(DEFAULTS, "bar", value1); | |
548 storage4->Set(DEFAULTS, "foo", value2); | |
549 | |
550 change = sync_processor_->GetOnlyChange("s1", "bar"); | |
551 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type()); | |
552 EXPECT_TRUE(value1.Equals(&change.value())); | |
553 change = sync_processor_->GetOnlyChange("s2", "foo"); | |
554 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type()); | |
555 EXPECT_TRUE(value2.Equals(&change.value())); | |
556 change = sync_processor_->GetOnlyChange("s3", "bar"); | |
557 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type()); | |
558 EXPECT_TRUE(value1.Equals(&change.value())); | |
559 change = sync_processor_->GetOnlyChange("s4", "foo"); | |
560 EXPECT_EQ(syncer::SyncChange::ACTION_UPDATE, change.change_type()); | |
561 EXPECT_TRUE(value2.Equals(&change.value())); | |
562 | |
563 // Remove something locally, storage1/3 the new setting and storage2/4 the | |
564 // initial setting, for all combinations of local vs sync intialisation and | |
565 // new vs initial. | |
566 sync_processor_->ClearChanges(); | |
567 storage1->Remove("foo"); | |
568 storage2->Remove("bar"); | |
569 storage3->Remove("foo"); | |
570 storage4->Remove("bar"); | |
571 | |
572 EXPECT_EQ( | |
573 syncer::SyncChange::ACTION_DELETE, | |
574 sync_processor_->GetOnlyChange("s1", "foo").change_type()); | |
575 EXPECT_EQ( | |
576 syncer::SyncChange::ACTION_DELETE, | |
577 sync_processor_->GetOnlyChange("s2", "bar").change_type()); | |
578 EXPECT_EQ( | |
579 syncer::SyncChange::ACTION_DELETE, | |
580 sync_processor_->GetOnlyChange("s3", "foo").change_type()); | |
581 EXPECT_EQ( | |
582 syncer::SyncChange::ACTION_DELETE, | |
583 sync_processor_->GetOnlyChange("s4", "bar").change_type()); | |
584 | |
585 // Remove some nonexistent settings. | |
586 sync_processor_->ClearChanges(); | |
587 storage1->Remove("foo"); | |
588 storage2->Remove("bar"); | |
589 storage3->Remove("foo"); | |
590 storage4->Remove("bar"); | |
591 | |
592 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
593 | |
594 // Clear the rest of the settings. Add the removed ones back first so that | |
595 // more than one setting is cleared. | |
596 storage1->Set(DEFAULTS, "foo", value1); | |
597 storage2->Set(DEFAULTS, "bar", value2); | |
598 storage3->Set(DEFAULTS, "foo", value1); | |
599 storage4->Set(DEFAULTS, "bar", value2); | |
600 | |
601 sync_processor_->ClearChanges(); | |
602 storage1->Clear(); | |
603 storage2->Clear(); | |
604 storage3->Clear(); | |
605 storage4->Clear(); | |
606 | |
607 EXPECT_EQ( | |
608 syncer::SyncChange::ACTION_DELETE, | |
609 sync_processor_->GetOnlyChange("s1", "foo").change_type()); | |
610 EXPECT_EQ( | |
611 syncer::SyncChange::ACTION_DELETE, | |
612 sync_processor_->GetOnlyChange("s1", "bar").change_type()); | |
613 EXPECT_EQ( | |
614 syncer::SyncChange::ACTION_DELETE, | |
615 sync_processor_->GetOnlyChange("s2", "foo").change_type()); | |
616 EXPECT_EQ( | |
617 syncer::SyncChange::ACTION_DELETE, | |
618 sync_processor_->GetOnlyChange("s2", "bar").change_type()); | |
619 EXPECT_EQ( | |
620 syncer::SyncChange::ACTION_DELETE, | |
621 sync_processor_->GetOnlyChange("s3", "foo").change_type()); | |
622 EXPECT_EQ( | |
623 syncer::SyncChange::ACTION_DELETE, | |
624 sync_processor_->GetOnlyChange("s3", "bar").change_type()); | |
625 EXPECT_EQ( | |
626 syncer::SyncChange::ACTION_DELETE, | |
627 sync_processor_->GetOnlyChange("s4", "foo").change_type()); | |
628 EXPECT_EQ( | |
629 syncer::SyncChange::ACTION_DELETE, | |
630 sync_processor_->GetOnlyChange("s4", "bar").change_type()); | |
631 | |
632 GetSyncableService(model_type)->StopSyncing(model_type); | |
633 } | |
634 | |
635 TEST_F(ExtensionSettingsSyncTest, ExtensionAndAppSettingsSyncSeparately) { | |
636 StringValue value1("fooValue"); | |
637 ListValue value2; | |
638 value2.Append(StringValue::CreateStringValue("barValue")); | |
639 | |
640 // storage1 is an extension, storage2 is an app. | |
641 ValueStore* storage1 = AddExtensionAndGetStorage( | |
642 "s1", Extension::TYPE_EXTENSION); | |
643 ValueStore* storage2 = AddExtensionAndGetStorage( | |
644 "s2", Extension::TYPE_LEGACY_PACKAGED_APP); | |
645 | |
646 storage1->Set(DEFAULTS, "foo", value1); | |
647 storage2->Set(DEFAULTS, "bar", value2); | |
648 | |
649 std::map<std::string, SettingSyncDataList> extension_sync_data = | |
650 GetAllSyncData(syncer::EXTENSION_SETTINGS); | |
651 EXPECT_EQ(1u, extension_sync_data.size()); | |
652 EXPECT_EQ(1u, extension_sync_data["s1"].size()); | |
653 EXPECT_PRED_FORMAT2(ValuesEq, &value1, &extension_sync_data["s1"][0].value()); | |
654 | |
655 std::map<std::string, SettingSyncDataList> app_sync_data = | |
656 GetAllSyncData(syncer::APP_SETTINGS); | |
657 EXPECT_EQ(1u, app_sync_data.size()); | |
658 EXPECT_EQ(1u, app_sync_data["s2"].size()); | |
659 EXPECT_PRED_FORMAT2(ValuesEq, &value2, &app_sync_data["s2"][0].value()); | |
660 | |
661 // Stop each separately, there should be no changes either time. | |
662 syncer::SyncDataList sync_data; | |
663 sync_data.push_back(settings_sync_util::CreateData( | |
664 "s1", "foo", value1, syncer::EXTENSION_SETTINGS)); | |
665 | |
666 GetSyncableService(syncer::EXTENSION_SETTINGS)->MergeDataAndStartSyncing( | |
667 syncer::EXTENSION_SETTINGS, | |
668 sync_data, | |
669 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
670 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
671 GetSyncableService(syncer::EXTENSION_SETTINGS)-> | |
672 StopSyncing(syncer::EXTENSION_SETTINGS); | |
673 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
674 | |
675 sync_data.clear(); | |
676 sync_data.push_back(settings_sync_util::CreateData( | |
677 "s2", "bar", value2, syncer::APP_SETTINGS)); | |
678 | |
679 scoped_ptr<SyncChangeProcessorDelegate> app_settings_delegate_( | |
680 new SyncChangeProcessorDelegate(sync_processor_.get())); | |
681 GetSyncableService(syncer::APP_SETTINGS)->MergeDataAndStartSyncing( | |
682 syncer::APP_SETTINGS, | |
683 sync_data, | |
684 app_settings_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
685 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
686 GetSyncableService(syncer::APP_SETTINGS)-> | |
687 StopSyncing(syncer::APP_SETTINGS); | |
688 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
689 } | |
690 | |
691 TEST_F(ExtensionSettingsSyncTest, FailingStartSyncingDisablesSync) { | |
692 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
693 Extension::Type type = Extension::TYPE_EXTENSION; | |
694 | |
695 StringValue fooValue("fooValue"); | |
696 StringValue barValue("barValue"); | |
697 | |
698 // There is a bit of a convoluted method to get storage areas that can fail; | |
699 // hand out TestingValueStore object then toggle them failing/succeeding | |
700 // as necessary. | |
701 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
702 storage_factory_->Reset(testing_factory); | |
703 | |
704 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
705 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
706 | |
707 // Make bad fail for incoming sync changes. | |
708 testing_factory->GetExisting("bad")->SetFailAllRequests(true); | |
709 { | |
710 syncer::SyncDataList sync_data; | |
711 sync_data.push_back(settings_sync_util::CreateData( | |
712 "good", "foo", fooValue, model_type)); | |
713 sync_data.push_back(settings_sync_util::CreateData( | |
714 "bad", "foo", fooValue, model_type)); | |
715 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
716 model_type, | |
717 sync_data, | |
718 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
719 scoped_ptr<syncer::SyncErrorFactory>( | |
720 new syncer::SyncErrorFactoryMock())); | |
721 } | |
722 testing_factory->GetExisting("bad")->SetFailAllRequests(false); | |
723 | |
724 { | |
725 DictionaryValue dict; | |
726 dict.Set("foo", fooValue.DeepCopy()); | |
727 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
728 } | |
729 { | |
730 DictionaryValue dict; | |
731 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
732 } | |
733 | |
734 // Changes made to good should be sent to sync, changes from bad shouldn't. | |
735 sync_processor_->ClearChanges(); | |
736 good->Set(DEFAULTS, "bar", barValue); | |
737 bad->Set(DEFAULTS, "bar", barValue); | |
738 | |
739 EXPECT_EQ( | |
740 syncer::SyncChange::ACTION_ADD, | |
741 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
742 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
743 | |
744 { | |
745 DictionaryValue dict; | |
746 dict.Set("foo", fooValue.DeepCopy()); | |
747 dict.Set("bar", barValue.DeepCopy()); | |
748 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
749 } | |
750 { | |
751 DictionaryValue dict; | |
752 dict.Set("bar", barValue.DeepCopy()); | |
753 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
754 } | |
755 | |
756 // Changes received from sync should go to good but not bad (even when it's | |
757 // not failing). | |
758 { | |
759 syncer::SyncChangeList change_list; | |
760 change_list.push_back(settings_sync_util::CreateUpdate( | |
761 "good", "foo", barValue, model_type)); | |
762 // (Sending UPDATE here even though it's adding, since that's what the state | |
763 // of sync is. In any case, it won't work.) | |
764 change_list.push_back(settings_sync_util::CreateUpdate( | |
765 "bad", "foo", barValue, model_type)); | |
766 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
767 } | |
768 | |
769 { | |
770 DictionaryValue dict; | |
771 dict.Set("foo", barValue.DeepCopy()); | |
772 dict.Set("bar", barValue.DeepCopy()); | |
773 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
774 } | |
775 { | |
776 DictionaryValue dict; | |
777 dict.Set("bar", barValue.DeepCopy()); | |
778 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
779 } | |
780 | |
781 // Changes made to bad still shouldn't go to sync, even though it didn't fail | |
782 // last time. | |
783 sync_processor_->ClearChanges(); | |
784 good->Set(DEFAULTS, "bar", fooValue); | |
785 bad->Set(DEFAULTS, "bar", fooValue); | |
786 | |
787 EXPECT_EQ( | |
788 syncer::SyncChange::ACTION_UPDATE, | |
789 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
790 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
791 | |
792 { | |
793 DictionaryValue dict; | |
794 dict.Set("foo", barValue.DeepCopy()); | |
795 dict.Set("bar", fooValue.DeepCopy()); | |
796 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
797 } | |
798 { | |
799 DictionaryValue dict; | |
800 dict.Set("bar", fooValue.DeepCopy()); | |
801 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
802 } | |
803 | |
804 // Failing ProcessSyncChanges shouldn't go to the storage. | |
805 testing_factory->GetExisting("bad")->SetFailAllRequests(true); | |
806 { | |
807 syncer::SyncChangeList change_list; | |
808 change_list.push_back(settings_sync_util::CreateUpdate( | |
809 "good", "foo", fooValue, model_type)); | |
810 // (Ditto.) | |
811 change_list.push_back(settings_sync_util::CreateUpdate( | |
812 "bad", "foo", fooValue, model_type)); | |
813 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
814 } | |
815 testing_factory->GetExisting("bad")->SetFailAllRequests(false); | |
816 | |
817 { | |
818 DictionaryValue dict; | |
819 dict.Set("foo", fooValue.DeepCopy()); | |
820 dict.Set("bar", fooValue.DeepCopy()); | |
821 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
822 } | |
823 { | |
824 DictionaryValue dict; | |
825 dict.Set("bar", fooValue.DeepCopy()); | |
826 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
827 } | |
828 | |
829 // Restarting sync should make bad start syncing again. | |
830 sync_processor_->ClearChanges(); | |
831 GetSyncableService(model_type)->StopSyncing(model_type); | |
832 sync_processor_delegate_.reset(new SyncChangeProcessorDelegate( | |
833 sync_processor_.get())); | |
834 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
835 model_type, | |
836 syncer::SyncDataList(), | |
837 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
838 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
839 | |
840 // Local settings will have been pushed to sync, since it's empty (in this | |
841 // test; presumably it wouldn't be live, since we've been getting changes). | |
842 EXPECT_EQ( | |
843 syncer::SyncChange::ACTION_ADD, | |
844 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
845 EXPECT_EQ( | |
846 syncer::SyncChange::ACTION_ADD, | |
847 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
848 EXPECT_EQ( | |
849 syncer::SyncChange::ACTION_ADD, | |
850 sync_processor_->GetOnlyChange("bad", "bar").change_type()); | |
851 EXPECT_EQ(3u, sync_processor_->changes().size()); | |
852 | |
853 // Live local changes now get pushed, too. | |
854 sync_processor_->ClearChanges(); | |
855 good->Set(DEFAULTS, "bar", barValue); | |
856 bad->Set(DEFAULTS, "bar", barValue); | |
857 | |
858 EXPECT_EQ( | |
859 syncer::SyncChange::ACTION_UPDATE, | |
860 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
861 EXPECT_EQ( | |
862 syncer::SyncChange::ACTION_UPDATE, | |
863 sync_processor_->GetOnlyChange("bad", "bar").change_type()); | |
864 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
865 | |
866 // And ProcessSyncChanges work, too. | |
867 { | |
868 syncer::SyncChangeList change_list; | |
869 change_list.push_back(settings_sync_util::CreateUpdate( | |
870 "good", "bar", fooValue, model_type)); | |
871 change_list.push_back(settings_sync_util::CreateUpdate( | |
872 "bad", "bar", fooValue, model_type)); | |
873 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
874 } | |
875 | |
876 { | |
877 DictionaryValue dict; | |
878 dict.Set("foo", fooValue.DeepCopy()); | |
879 dict.Set("bar", fooValue.DeepCopy()); | |
880 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
881 } | |
882 { | |
883 DictionaryValue dict; | |
884 dict.Set("bar", fooValue.DeepCopy()); | |
885 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
886 } | |
887 } | |
888 | |
889 TEST_F(ExtensionSettingsSyncTest, FailingProcessChangesDisablesSync) { | |
890 // The test above tests a failing ProcessSyncChanges too, but here test with | |
891 // an initially passing MergeDataAndStartSyncing. | |
892 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
893 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
894 | |
895 StringValue fooValue("fooValue"); | |
896 StringValue barValue("barValue"); | |
897 | |
898 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
899 storage_factory_->Reset(testing_factory); | |
900 | |
901 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
902 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
903 | |
904 // Unlike before, initially succeeding MergeDataAndStartSyncing. | |
905 { | |
906 syncer::SyncDataList sync_data; | |
907 sync_data.push_back(settings_sync_util::CreateData( | |
908 "good", "foo", fooValue, model_type)); | |
909 sync_data.push_back(settings_sync_util::CreateData( | |
910 "bad", "foo", fooValue, model_type)); | |
911 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
912 model_type, | |
913 sync_data, | |
914 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
915 scoped_ptr<syncer::SyncErrorFactory>( | |
916 new syncer::SyncErrorFactoryMock())); | |
917 } | |
918 | |
919 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
920 | |
921 { | |
922 DictionaryValue dict; | |
923 dict.Set("foo", fooValue.DeepCopy()); | |
924 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
925 } | |
926 { | |
927 DictionaryValue dict; | |
928 dict.Set("foo", fooValue.DeepCopy()); | |
929 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
930 } | |
931 | |
932 // Now fail ProcessSyncChanges for bad. | |
933 testing_factory->GetExisting("bad")->SetFailAllRequests(true); | |
934 { | |
935 syncer::SyncChangeList change_list; | |
936 change_list.push_back(settings_sync_util::CreateAdd( | |
937 "good", "bar", barValue, model_type)); | |
938 change_list.push_back(settings_sync_util::CreateAdd( | |
939 "bad", "bar", barValue, model_type)); | |
940 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
941 } | |
942 testing_factory->GetExisting("bad")->SetFailAllRequests(false); | |
943 | |
944 { | |
945 DictionaryValue dict; | |
946 dict.Set("foo", fooValue.DeepCopy()); | |
947 dict.Set("bar", barValue.DeepCopy()); | |
948 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
949 } | |
950 { | |
951 DictionaryValue dict; | |
952 dict.Set("foo", fooValue.DeepCopy()); | |
953 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
954 } | |
955 | |
956 // No more changes sent to sync for bad. | |
957 sync_processor_->ClearChanges(); | |
958 good->Set(DEFAULTS, "foo", barValue); | |
959 bad->Set(DEFAULTS, "foo", barValue); | |
960 | |
961 EXPECT_EQ( | |
962 syncer::SyncChange::ACTION_UPDATE, | |
963 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
964 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
965 | |
966 // No more changes received from sync should go to bad. | |
967 { | |
968 syncer::SyncChangeList change_list; | |
969 change_list.push_back(settings_sync_util::CreateAdd( | |
970 "good", "foo", fooValue, model_type)); | |
971 change_list.push_back(settings_sync_util::CreateAdd( | |
972 "bad", "foo", fooValue, model_type)); | |
973 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
974 } | |
975 | |
976 { | |
977 DictionaryValue dict; | |
978 dict.Set("foo", fooValue.DeepCopy()); | |
979 dict.Set("bar", barValue.DeepCopy()); | |
980 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
981 } | |
982 { | |
983 DictionaryValue dict; | |
984 dict.Set("foo", barValue.DeepCopy()); | |
985 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
986 } | |
987 } | |
988 | |
989 TEST_F(ExtensionSettingsSyncTest, FailingGetAllSyncDataDoesntStopSync) { | |
990 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
991 Extension::Type type = Extension::TYPE_EXTENSION; | |
992 | |
993 StringValue fooValue("fooValue"); | |
994 StringValue barValue("barValue"); | |
995 | |
996 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
997 storage_factory_->Reset(testing_factory); | |
998 | |
999 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
1000 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
1001 | |
1002 good->Set(DEFAULTS, "foo", fooValue); | |
1003 bad->Set(DEFAULTS, "foo", fooValue); | |
1004 | |
1005 // Even though bad will fail to get all sync data, sync data should still | |
1006 // include that from good. | |
1007 testing_factory->GetExisting("bad")->SetFailAllRequests(true); | |
1008 { | |
1009 syncer::SyncDataList all_sync_data = | |
1010 GetSyncableService(model_type)->GetAllSyncData(model_type); | |
1011 EXPECT_EQ(1u, all_sync_data.size()); | |
1012 EXPECT_EQ("good/foo", all_sync_data[0].GetTag()); | |
1013 } | |
1014 testing_factory->GetExisting("bad")->SetFailAllRequests(false); | |
1015 | |
1016 // Sync shouldn't be disabled for good (nor bad -- but this is unimportant). | |
1017 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1018 model_type, | |
1019 syncer::SyncDataList(), | |
1020 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1021 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1022 | |
1023 EXPECT_EQ( | |
1024 syncer::SyncChange::ACTION_ADD, | |
1025 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1026 EXPECT_EQ( | |
1027 syncer::SyncChange::ACTION_ADD, | |
1028 sync_processor_->GetOnlyChange("bad", "foo").change_type()); | |
1029 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
1030 | |
1031 sync_processor_->ClearChanges(); | |
1032 good->Set(DEFAULTS, "bar", barValue); | |
1033 bad->Set(DEFAULTS, "bar", barValue); | |
1034 | |
1035 EXPECT_EQ( | |
1036 syncer::SyncChange::ACTION_ADD, | |
1037 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1038 EXPECT_EQ( | |
1039 syncer::SyncChange::ACTION_ADD, | |
1040 sync_processor_->GetOnlyChange("bad", "bar").change_type()); | |
1041 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
1042 } | |
1043 | |
1044 TEST_F(ExtensionSettingsSyncTest, FailureToReadChangesToPushDisablesSync) { | |
1045 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
1046 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
1047 | |
1048 StringValue fooValue("fooValue"); | |
1049 StringValue barValue("barValue"); | |
1050 | |
1051 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
1052 storage_factory_->Reset(testing_factory); | |
1053 | |
1054 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
1055 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
1056 | |
1057 good->Set(DEFAULTS, "foo", fooValue); | |
1058 bad->Set(DEFAULTS, "foo", fooValue); | |
1059 | |
1060 // good will successfully push foo:fooValue to sync, but bad will fail to | |
1061 // get them so won't. | |
1062 testing_factory->GetExisting("bad")->SetFailAllRequests(true); | |
1063 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1064 model_type, | |
1065 syncer::SyncDataList(), | |
1066 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1067 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1068 testing_factory->GetExisting("bad")->SetFailAllRequests(false); | |
1069 | |
1070 EXPECT_EQ( | |
1071 syncer::SyncChange::ACTION_ADD, | |
1072 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1073 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
1074 | |
1075 // bad should now be disabled for sync. | |
1076 sync_processor_->ClearChanges(); | |
1077 good->Set(DEFAULTS, "bar", barValue); | |
1078 bad->Set(DEFAULTS, "bar", barValue); | |
1079 | |
1080 EXPECT_EQ( | |
1081 syncer::SyncChange::ACTION_ADD, | |
1082 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1083 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
1084 | |
1085 { | |
1086 syncer::SyncChangeList change_list; | |
1087 change_list.push_back(settings_sync_util::CreateUpdate( | |
1088 "good", "foo", barValue, model_type)); | |
1089 // (Sending ADD here even though it's updating, since that's what the state | |
1090 // of sync is. In any case, it won't work.) | |
1091 change_list.push_back(settings_sync_util::CreateAdd( | |
1092 "bad", "foo", barValue, model_type)); | |
1093 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
1094 } | |
1095 | |
1096 { | |
1097 DictionaryValue dict; | |
1098 dict.Set("foo", barValue.DeepCopy()); | |
1099 dict.Set("bar", barValue.DeepCopy()); | |
1100 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
1101 } | |
1102 { | |
1103 DictionaryValue dict; | |
1104 dict.Set("foo", fooValue.DeepCopy()); | |
1105 dict.Set("bar", barValue.DeepCopy()); | |
1106 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
1107 } | |
1108 | |
1109 // Re-enabling sync without failing should cause the local changes from bad | |
1110 // to be pushed to sync successfully, as should future changes to bad. | |
1111 sync_processor_->ClearChanges(); | |
1112 GetSyncableService(model_type)->StopSyncing(model_type); | |
1113 sync_processor_delegate_.reset(new SyncChangeProcessorDelegate( | |
1114 sync_processor_.get())); | |
1115 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1116 model_type, | |
1117 syncer::SyncDataList(), | |
1118 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1119 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1120 | |
1121 EXPECT_EQ( | |
1122 syncer::SyncChange::ACTION_ADD, | |
1123 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1124 EXPECT_EQ( | |
1125 syncer::SyncChange::ACTION_ADD, | |
1126 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1127 EXPECT_EQ( | |
1128 syncer::SyncChange::ACTION_ADD, | |
1129 sync_processor_->GetOnlyChange("bad", "foo").change_type()); | |
1130 EXPECT_EQ( | |
1131 syncer::SyncChange::ACTION_ADD, | |
1132 sync_processor_->GetOnlyChange("bad", "bar").change_type()); | |
1133 EXPECT_EQ(4u, sync_processor_->changes().size()); | |
1134 | |
1135 sync_processor_->ClearChanges(); | |
1136 good->Set(DEFAULTS, "bar", fooValue); | |
1137 bad->Set(DEFAULTS, "bar", fooValue); | |
1138 | |
1139 EXPECT_EQ( | |
1140 syncer::SyncChange::ACTION_UPDATE, | |
1141 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1142 EXPECT_EQ( | |
1143 syncer::SyncChange::ACTION_UPDATE, | |
1144 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1145 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
1146 } | |
1147 | |
1148 TEST_F(ExtensionSettingsSyncTest, FailureToPushLocalStateDisablesSync) { | |
1149 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
1150 Extension::Type type = Extension::TYPE_EXTENSION; | |
1151 | |
1152 StringValue fooValue("fooValue"); | |
1153 StringValue barValue("barValue"); | |
1154 | |
1155 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
1156 storage_factory_->Reset(testing_factory); | |
1157 | |
1158 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
1159 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
1160 | |
1161 // Only set bad; setting good will cause it to fail below. | |
1162 bad->Set(DEFAULTS, "foo", fooValue); | |
1163 | |
1164 sync_processor_->SetFailAllRequests(true); | |
1165 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1166 model_type, | |
1167 syncer::SyncDataList(), | |
1168 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1169 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1170 sync_processor_->SetFailAllRequests(false); | |
1171 | |
1172 // Changes from good will be send to sync, changes from bad won't. | |
1173 sync_processor_->ClearChanges(); | |
1174 good->Set(DEFAULTS, "foo", barValue); | |
1175 bad->Set(DEFAULTS, "foo", barValue); | |
1176 | |
1177 EXPECT_EQ( | |
1178 syncer::SyncChange::ACTION_ADD, | |
1179 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1180 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
1181 | |
1182 // Changes from sync will be sent to good, not to bad. | |
1183 { | |
1184 syncer::SyncChangeList change_list; | |
1185 change_list.push_back(settings_sync_util::CreateAdd( | |
1186 "good", "bar", barValue, model_type)); | |
1187 change_list.push_back(settings_sync_util::CreateAdd( | |
1188 "bad", "bar", barValue, model_type)); | |
1189 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
1190 } | |
1191 | |
1192 { | |
1193 DictionaryValue dict; | |
1194 dict.Set("foo", barValue.DeepCopy()); | |
1195 dict.Set("bar", barValue.DeepCopy()); | |
1196 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
1197 } | |
1198 { | |
1199 DictionaryValue dict; | |
1200 dict.Set("foo", barValue.DeepCopy()); | |
1201 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
1202 } | |
1203 | |
1204 // Restarting sync makes everything work again. | |
1205 sync_processor_->ClearChanges(); | |
1206 GetSyncableService(model_type)->StopSyncing(model_type); | |
1207 sync_processor_delegate_.reset(new SyncChangeProcessorDelegate( | |
1208 sync_processor_.get())); | |
1209 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1210 model_type, | |
1211 syncer::SyncDataList(), | |
1212 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1213 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1214 | |
1215 EXPECT_EQ( | |
1216 syncer::SyncChange::ACTION_ADD, | |
1217 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1218 EXPECT_EQ( | |
1219 syncer::SyncChange::ACTION_ADD, | |
1220 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1221 EXPECT_EQ( | |
1222 syncer::SyncChange::ACTION_ADD, | |
1223 sync_processor_->GetOnlyChange("bad", "foo").change_type()); | |
1224 EXPECT_EQ(3u, sync_processor_->changes().size()); | |
1225 | |
1226 sync_processor_->ClearChanges(); | |
1227 good->Set(DEFAULTS, "foo", fooValue); | |
1228 bad->Set(DEFAULTS, "foo", fooValue); | |
1229 | |
1230 EXPECT_EQ( | |
1231 syncer::SyncChange::ACTION_UPDATE, | |
1232 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1233 EXPECT_EQ( | |
1234 syncer::SyncChange::ACTION_UPDATE, | |
1235 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1236 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
1237 } | |
1238 | |
1239 TEST_F(ExtensionSettingsSyncTest, FailureToPushLocalChangeDisablesSync) { | |
1240 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
1241 Extension::Type type = Extension::TYPE_EXTENSION; | |
1242 | |
1243 StringValue fooValue("fooValue"); | |
1244 StringValue barValue("barValue"); | |
1245 | |
1246 TestingValueStoreFactory* testing_factory = new TestingValueStoreFactory(); | |
1247 storage_factory_->Reset(testing_factory); | |
1248 | |
1249 ValueStore* good = AddExtensionAndGetStorage("good", type); | |
1250 ValueStore* bad = AddExtensionAndGetStorage("bad", type); | |
1251 | |
1252 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1253 model_type, | |
1254 syncer::SyncDataList(), | |
1255 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1256 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1257 | |
1258 // bad will fail to send changes. | |
1259 good->Set(DEFAULTS, "foo", fooValue); | |
1260 sync_processor_->SetFailAllRequests(true); | |
1261 bad->Set(DEFAULTS, "foo", fooValue); | |
1262 sync_processor_->SetFailAllRequests(false); | |
1263 | |
1264 EXPECT_EQ( | |
1265 syncer::SyncChange::ACTION_ADD, | |
1266 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1267 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
1268 | |
1269 // No further changes should be sent from bad. | |
1270 sync_processor_->ClearChanges(); | |
1271 good->Set(DEFAULTS, "foo", barValue); | |
1272 bad->Set(DEFAULTS, "foo", barValue); | |
1273 | |
1274 EXPECT_EQ( | |
1275 syncer::SyncChange::ACTION_UPDATE, | |
1276 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1277 EXPECT_EQ(1u, sync_processor_->changes().size()); | |
1278 | |
1279 // Changes from sync will be sent to good, not to bad. | |
1280 { | |
1281 syncer::SyncChangeList change_list; | |
1282 change_list.push_back(settings_sync_util::CreateAdd( | |
1283 "good", "bar", barValue, model_type)); | |
1284 change_list.push_back(settings_sync_util::CreateAdd( | |
1285 "bad", "bar", barValue, model_type)); | |
1286 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
1287 } | |
1288 | |
1289 { | |
1290 DictionaryValue dict; | |
1291 dict.Set("foo", barValue.DeepCopy()); | |
1292 dict.Set("bar", barValue.DeepCopy()); | |
1293 EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get()); | |
1294 } | |
1295 { | |
1296 DictionaryValue dict; | |
1297 dict.Set("foo", barValue.DeepCopy()); | |
1298 EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get()); | |
1299 } | |
1300 | |
1301 // Restarting sync makes everything work again. | |
1302 sync_processor_->ClearChanges(); | |
1303 GetSyncableService(model_type)->StopSyncing(model_type); | |
1304 sync_processor_delegate_.reset(new SyncChangeProcessorDelegate( | |
1305 sync_processor_.get())); | |
1306 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1307 model_type, | |
1308 syncer::SyncDataList(), | |
1309 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1310 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1311 | |
1312 EXPECT_EQ( | |
1313 syncer::SyncChange::ACTION_ADD, | |
1314 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1315 EXPECT_EQ( | |
1316 syncer::SyncChange::ACTION_ADD, | |
1317 sync_processor_->GetOnlyChange("good", "bar").change_type()); | |
1318 EXPECT_EQ( | |
1319 syncer::SyncChange::ACTION_ADD, | |
1320 sync_processor_->GetOnlyChange("bad", "foo").change_type()); | |
1321 EXPECT_EQ(3u, sync_processor_->changes().size()); | |
1322 | |
1323 sync_processor_->ClearChanges(); | |
1324 good->Set(DEFAULTS, "foo", fooValue); | |
1325 bad->Set(DEFAULTS, "foo", fooValue); | |
1326 | |
1327 EXPECT_EQ( | |
1328 syncer::SyncChange::ACTION_UPDATE, | |
1329 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1330 EXPECT_EQ( | |
1331 syncer::SyncChange::ACTION_UPDATE, | |
1332 sync_processor_->GetOnlyChange("good", "foo").change_type()); | |
1333 EXPECT_EQ(2u, sync_processor_->changes().size()); | |
1334 } | |
1335 | |
1336 TEST_F(ExtensionSettingsSyncTest, | |
1337 LargeOutgoingChangeRejectedButIncomingAccepted) { | |
1338 syncer::ModelType model_type = syncer::APP_SETTINGS; | |
1339 Extension::Type type = Extension::TYPE_LEGACY_PACKAGED_APP; | |
1340 | |
1341 // This value should be larger than the limit in settings_backend.cc. | |
1342 std::string string_5k; | |
1343 for (size_t i = 0; i < 5000; ++i) { | |
1344 string_5k.append("a"); | |
1345 } | |
1346 StringValue large_value(string_5k); | |
1347 | |
1348 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1349 model_type, | |
1350 syncer::SyncDataList(), | |
1351 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1352 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); | |
1353 | |
1354 // Large local change rejected and doesn't get sent out. | |
1355 ValueStore* storage1 = AddExtensionAndGetStorage("s1", type); | |
1356 EXPECT_TRUE(storage1->Set(DEFAULTS, "large_value", large_value)->HasError()); | |
1357 EXPECT_EQ(0u, sync_processor_->changes().size()); | |
1358 | |
1359 // Large incoming change should still get accepted. | |
1360 ValueStore* storage2 = AddExtensionAndGetStorage("s2", type); | |
1361 { | |
1362 syncer::SyncChangeList change_list; | |
1363 change_list.push_back(settings_sync_util::CreateAdd( | |
1364 "s1", "large_value", large_value, model_type)); | |
1365 change_list.push_back(settings_sync_util::CreateAdd( | |
1366 "s2", "large_value", large_value, model_type)); | |
1367 GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list); | |
1368 } | |
1369 { | |
1370 DictionaryValue expected; | |
1371 expected.Set("large_value", large_value.DeepCopy()); | |
1372 EXPECT_PRED_FORMAT2(SettingsEq, expected, storage1->Get()); | |
1373 EXPECT_PRED_FORMAT2(SettingsEq, expected, storage2->Get()); | |
1374 } | |
1375 | |
1376 GetSyncableService(model_type)->StopSyncing(model_type); | |
1377 } | |
1378 | |
1379 TEST_F(ExtensionSettingsSyncTest, Dots) { | |
1380 syncer::ModelType model_type = syncer::EXTENSION_SETTINGS; | |
1381 Extension::Type type = Extension::TYPE_EXTENSION; | |
1382 | |
1383 ValueStore* storage = AddExtensionAndGetStorage("ext", type); | |
1384 | |
1385 { | |
1386 syncer::SyncDataList sync_data_list; | |
1387 scoped_ptr<Value> string_value(Value::CreateStringValue("value")); | |
1388 sync_data_list.push_back(settings_sync_util::CreateData( | |
1389 "ext", "key.with.dot", *string_value, model_type)); | |
1390 | |
1391 GetSyncableService(model_type)->MergeDataAndStartSyncing( | |
1392 model_type, | |
1393 sync_data_list, | |
1394 sync_processor_delegate_.PassAs<syncer::SyncChangeProcessor>(), | |
1395 scoped_ptr<syncer::SyncErrorFactory>( | |
1396 new syncer::SyncErrorFactoryMock())); | |
1397 } | |
1398 | |
1399 // Test dots in keys that come from sync. | |
1400 { | |
1401 ValueStore::ReadResult data = storage->Get(); | |
1402 ASSERT_FALSE(data->HasError()); | |
1403 | |
1404 DictionaryValue expected_data; | |
1405 expected_data.SetWithoutPathExpansion( | |
1406 "key.with.dot", | |
1407 Value::CreateStringValue("value")); | |
1408 EXPECT_TRUE(Value::Equals(&expected_data, data->settings().get())); | |
1409 } | |
1410 | |
1411 // Test dots in keys going to sync. | |
1412 { | |
1413 scoped_ptr<Value> string_value(Value::CreateStringValue("spot")); | |
1414 storage->Set(DEFAULTS, "key.with.spot", *string_value); | |
1415 | |
1416 ASSERT_EQ(1u, sync_processor_->changes().size()); | |
1417 SettingSyncData sync_data = sync_processor_->changes()[0]; | |
1418 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, sync_data.change_type()); | |
1419 EXPECT_EQ("ext", sync_data.extension_id()); | |
1420 EXPECT_EQ("key.with.spot", sync_data.key()); | |
1421 EXPECT_TRUE(sync_data.value().Equals(string_value.get())); | |
1422 } | |
1423 } | |
1424 | |
1425 } // namespace extensions | |
OLD | NEW |