| 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_helper.h" | 
|  | 19 #include "chrome/browser/extensions/syncable_extension_settings_storage.h" | 
|  | 20 #include "chrome/browser/sync/api/sync_change_processor.h" | 
|  | 21 #include "content/browser/browser_thread.h" | 
|  | 22 | 
|  | 23 namespace { | 
|  | 24 | 
|  | 25 // Define macro to get the __LINE__ expansion. | 
|  | 26 #define NEW_CALLBACK(expected) \ | 
|  | 27     (new AssertEqualsCallback((expected), __LINE__)) | 
|  | 28 | 
|  | 29 // SyncChangeProcessor which just records the changes made, accessed after | 
|  | 30 // being converted to the more useful ExtensionSettingSyncData via changes(). | 
|  | 31 class MockSyncChangeProcessor : public SyncChangeProcessor { | 
|  | 32  public: | 
|  | 33   virtual SyncError ProcessSyncChanges( | 
|  | 34       const tracked_objects::Location& from_here, | 
|  | 35       const SyncChangeList& change_list) OVERRIDE { | 
|  | 36     for (SyncChangeList::const_iterator it = change_list.begin(); | 
|  | 37         it != change_list.end(); ++it) { | 
|  | 38       ExtensionSettingsSyncData data(*it); | 
|  | 39       DCHECK(data.value() != NULL); | 
|  | 40       changes_.push_back(data); | 
|  | 41     } | 
|  | 42     return SyncError(); | 
|  | 43   } | 
|  | 44 | 
|  | 45   const ExtensionSettingsSyncDataList& changes() { return changes_; } | 
|  | 46 | 
|  | 47   void ClearChanges() { | 
|  | 48     changes_.clear(); | 
|  | 49   } | 
|  | 50 | 
|  | 51   // Returns the only change for a given extension setting.  If there is not | 
|  | 52   // exactly 1 change for that key, a test assertion will fail. | 
|  | 53   ExtensionSettingsSyncData GetOnlyChange( | 
|  | 54       const std::string& extension_id, const std::string& key) { | 
|  | 55     ExtensionSettingsSyncDataList matching_changes; | 
|  | 56     for (ExtensionSettingsSyncDataList::iterator it = changes_.begin(); | 
|  | 57         it != changes_.end(); ++it) { | 
|  | 58       if (it->extension_id() == extension_id && it->key() == key) { | 
|  | 59         matching_changes.push_back(*it); | 
|  | 60       } | 
|  | 61     } | 
|  | 62     DCHECK_EQ(1u, matching_changes.size()) << | 
|  | 63         "Not exactly 1 change for " << extension_id << "/" << key << | 
|  | 64         " (out of " << changes_.size() << ")"; | 
|  | 65     return matching_changes[0]; | 
|  | 66   } | 
|  | 67 | 
|  | 68  private: | 
|  | 69   ExtensionSettingsSyncDataList changes_; | 
|  | 70 }; | 
|  | 71 | 
|  | 72 // Callback from storage methods which performs the test assertions. | 
|  | 73 // TODO(kalman): share this with extension_settings_storage_unittest somehow. | 
|  | 74 class AssertEqualsCallback : public ExtensionSettingsStorage::Callback { | 
|  | 75  public: | 
|  | 76   AssertEqualsCallback(DictionaryValue* expected, int line) | 
|  | 77       : expected_(expected), line_(line), called_(false) { | 
|  | 78   } | 
|  | 79 | 
|  | 80   ~AssertEqualsCallback() { | 
|  | 81     // Need to DCHECK since ASSERT_* can't be used from destructors. | 
|  | 82     DCHECK(called_); | 
|  | 83   } | 
|  | 84 | 
|  | 85   virtual void OnSuccess(DictionaryValue* actual) OVERRIDE { | 
|  | 86     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  | 87     ASSERT_FALSE(called_) << "Callback has already been called"; | 
|  | 88     called_ = true; | 
|  | 89     if (expected_ == NULL) { | 
|  | 90       ASSERT_TRUE(actual == NULL) << "Values are different:\n" << | 
|  | 91           "Line:     " << line_ << "\n" << | 
|  | 92           "Expected: NULL\n" << | 
|  | 93           "Got:      " << GetJson(actual); | 
|  | 94     } else { | 
|  | 95       ASSERT_TRUE(expected_->Equals(actual)) << "Values are different:\n" << | 
|  | 96           "Line:     " << line_ << "\n" << | 
|  | 97           "Expected: " << GetJson(expected_) << | 
|  | 98           "Got:      " << GetJson(actual); | 
|  | 99       delete actual; | 
|  | 100     } | 
|  | 101   } | 
|  | 102 | 
|  | 103   virtual void OnFailure(const std::string& message) OVERRIDE { | 
|  | 104     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  | 105     ASSERT_FALSE(called_) << "Callback has already been called"; | 
|  | 106     called_ = true; | 
|  | 107     // No tests allow failure (yet). | 
|  | 108     ASSERT_TRUE(false) << "Callback failed on line " << line_; | 
|  | 109   } | 
|  | 110 | 
|  | 111  private: | 
|  | 112   std::string GetJson(Value* value) { | 
|  | 113     std::string json; | 
|  | 114     base::JSONWriter::Write(value, true, &json); | 
|  | 115     return json; | 
|  | 116   } | 
|  | 117 | 
|  | 118   DictionaryValue* expected_; | 
|  | 119   int line_; | 
|  | 120   bool called_; | 
|  | 121 }; | 
|  | 122 | 
|  | 123 }  // namespace | 
|  | 124 | 
|  | 125 class ExtensionSettingsSyncUnittest : public testing::Test { | 
|  | 126  public: | 
|  | 127   virtual void SetUp() { | 
|  | 128     ui_message_loop_.reset(new MessageLoopForUI()); | 
|  | 129     // Use the same message loop for the UI and FILE threads, giving a test | 
|  | 130     // pattern where storage API calls get posted to the same message loop (the | 
|  | 131     // current one), then all run with MessageLoop::current()->RunAllPending(). | 
|  | 132     ui_thread_.reset( | 
|  | 133         new BrowserThread(BrowserThread::UI, MessageLoop::current())); | 
|  | 134     file_thread_.reset( | 
|  | 135         new BrowserThread(BrowserThread::FILE, MessageLoop::current())); | 
|  | 136     sync_.reset(new MockSyncChangeProcessor()); | 
|  | 137 | 
|  | 138     FilePath temp_dir; | 
|  | 139     file_util::CreateNewTempDirectory(FilePath::StringType(), &temp_dir); | 
|  | 140     settings_ = new ExtensionSettings(temp_dir); | 
|  | 141   } | 
|  | 142 | 
|  | 143  protected: | 
|  | 144   void GetStorage( | 
|  | 145       const std::string& extension_id, | 
|  | 146       SyncableExtensionSettingsStorage** storage) { | 
|  | 147     settings_->GetStorage( | 
|  | 148         extension_id, | 
|  | 149         base::Bind( | 
|  | 150             &ExtensionSettingsSyncUnittest::AssignStorage, | 
|  | 151             base::Unretained(this), | 
|  | 152             storage)); | 
|  | 153     MessageLoop::current()->RunAllPending(); | 
|  | 154   } | 
|  | 155 | 
|  | 156   scoped_ptr<MockSyncChangeProcessor> sync_; | 
|  | 157   scoped_refptr<ExtensionSettings> settings_; | 
|  | 158 | 
|  | 159  private: | 
|  | 160   void AssignStorage( | 
|  | 161       SyncableExtensionSettingsStorage** assign_to, | 
|  | 162       SyncableExtensionSettingsStorage* storage) { | 
|  | 163     DCHECK(storage != NULL); | 
|  | 164     *assign_to = storage; | 
|  | 165   } | 
|  | 166 | 
|  | 167   scoped_ptr<MessageLoopForUI> ui_message_loop_; | 
|  | 168   scoped_ptr<BrowserThread> ui_thread_; | 
|  | 169   scoped_ptr<BrowserThread> file_thread_; | 
|  | 170 }; | 
|  | 171 | 
|  | 172 TEST_F(ExtensionSettingsSyncUnittest, NoDataDoesNotInvokeSync) { | 
|  | 173   SyncableExtensionSettingsStorage* storage1; | 
|  | 174   SyncableExtensionSettingsStorage* storage2; | 
|  | 175   DictionaryValue empty_dict; | 
|  | 176 | 
|  | 177   // Have one extension created before sync is set up, the other created after. | 
|  | 178   GetStorage("storage1", &storage1); | 
|  | 179   settings_->MergeDataAndStartSyncing( | 
|  | 180       syncable::EXTENSION_SETTINGS, | 
|  | 181       SyncDataList(), | 
|  | 182       sync_.get()); | 
|  | 183   MessageLoop::current()->RunAllPending(); | 
|  | 184   GetStorage("storage2", &storage2); | 
|  | 185 | 
|  | 186   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 187   MessageLoop::current()->RunAllPending(); | 
|  | 188 | 
|  | 189   ASSERT_EQ(0u, sync_->changes().size()); | 
|  | 190 } | 
|  | 191 | 
|  | 192 TEST_F(ExtensionSettingsSyncUnittest, InSyncDataDoesNotInvokeSync) { | 
|  | 193   StringValue value1("fooValue"); | 
|  | 194   ListValue value2; | 
|  | 195   value2.Append(StringValue::CreateStringValue("barValue")); | 
|  | 196 | 
|  | 197   SyncableExtensionSettingsStorage* storage1; | 
|  | 198   SyncableExtensionSettingsStorage* storage2; | 
|  | 199 | 
|  | 200   GetStorage("storage1", &storage1); | 
|  | 201   GetStorage("storage2", &storage2); | 
|  | 202 | 
|  | 203   storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 204   storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 205   MessageLoop::current()->RunAllPending(); | 
|  | 206 | 
|  | 207   SyncDataList sync_data; | 
|  | 208   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 209       "storage1", "foo", value1)); | 
|  | 210   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 211       "storage2", "bar", value2)); | 
|  | 212 | 
|  | 213   settings_->MergeDataAndStartSyncing( | 
|  | 214       syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | 
|  | 215   MessageLoop::current()->RunAllPending(); | 
|  | 216   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 217   MessageLoop::current()->RunAllPending(); | 
|  | 218 | 
|  | 219   // Already in sync, so no changes. | 
|  | 220   ASSERT_EQ(0u, sync_->changes().size()); | 
|  | 221 } | 
|  | 222 | 
|  | 223 TEST_F(ExtensionSettingsSyncUnittest, LocalDataWithNoSyncDataIsPushedToSync) { | 
|  | 224   StringValue value1("fooValue"); | 
|  | 225   ListValue value2; | 
|  | 226   value2.Append(StringValue::CreateStringValue("barValue")); | 
|  | 227 | 
|  | 228   SyncableExtensionSettingsStorage* storage1; | 
|  | 229   SyncableExtensionSettingsStorage* storage2; | 
|  | 230 | 
|  | 231   GetStorage("storage1", &storage1); | 
|  | 232   GetStorage("storage2", &storage2); | 
|  | 233 | 
|  | 234   storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 235   storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 236   MessageLoop::current()->RunAllPending(); | 
|  | 237 | 
|  | 238   settings_->MergeDataAndStartSyncing( | 
|  | 239       syncable::EXTENSION_SETTINGS, SyncDataList(), sync_.get()); | 
|  | 240   MessageLoop::current()->RunAllPending(); | 
|  | 241 | 
|  | 242   // All settings should have been pushed to sync. | 
|  | 243   ASSERT_EQ(2u, sync_->changes().size()); | 
|  | 244   ExtensionSettingsSyncData change = sync_->GetOnlyChange("storage1", "foo"); | 
|  | 245   ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 246   ASSERT_TRUE(value1.Equals(change.value())); | 
|  | 247   change = sync_->GetOnlyChange("storage2", "bar"); | 
|  | 248   ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 249   ASSERT_TRUE(value2.Equals(change.value())); | 
|  | 250 | 
|  | 251   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 252   MessageLoop::current()->RunAllPending(); | 
|  | 253 } | 
|  | 254 | 
|  | 255 TEST_F(ExtensionSettingsSyncUnittest, AnySyncDataOverwritesLocalData) { | 
|  | 256   StringValue value1("fooValue"); | 
|  | 257   ListValue value2; | 
|  | 258   value2.Append(StringValue::CreateStringValue("barValue")); | 
|  | 259 | 
|  | 260   SyncableExtensionSettingsStorage* storage1; | 
|  | 261   SyncableExtensionSettingsStorage* storage2; | 
|  | 262 | 
|  | 263   // Pre-populate one of the storage areas. | 
|  | 264   GetStorage("storage1", &storage1); | 
|  | 265   storage1->Set( | 
|  | 266       "overwriteMe", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 267   MessageLoop::current()->RunAllPending(); | 
|  | 268 | 
|  | 269   SyncDataList sync_data; | 
|  | 270   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 271       "storage1", "foo", value1)); | 
|  | 272   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 273       "storage2", "bar", value2)); | 
|  | 274   settings_->MergeDataAndStartSyncing( | 
|  | 275       syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | 
|  | 276   MessageLoop::current()->RunAllPending(); | 
|  | 277 | 
|  | 278   GetStorage("storage2", &storage2); | 
|  | 279 | 
|  | 280   // All changes should be local, so no sync changes. | 
|  | 281   ASSERT_EQ(0u, sync_->changes().size()); | 
|  | 282 | 
|  | 283   // Sync settings should have been pushed to local settings. | 
|  | 284   DictionaryValue settings1; | 
|  | 285   settings1.Set("foo", value1.DeepCopy()); | 
|  | 286   DictionaryValue settings2; | 
|  | 287   settings2.Set("bar", value2.DeepCopy()); | 
|  | 288   storage1->Get(NEW_CALLBACK(&settings1)); | 
|  | 289   storage2->Get(NEW_CALLBACK(&settings2)); | 
|  | 290   MessageLoop::current()->RunAllPending(); | 
|  | 291 | 
|  | 292   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 293   MessageLoop::current()->RunAllPending(); | 
|  | 294 } | 
|  | 295 | 
|  | 296 TEST_F(ExtensionSettingsSyncUnittest, ProcessSyncChanges) { | 
|  | 297   StringValue value1("fooValue"); | 
|  | 298   ListValue value2; | 
|  | 299   value2.Append(StringValue::CreateStringValue("barValue")); | 
|  | 300 | 
|  | 301   SyncableExtensionSettingsStorage* storage1; | 
|  | 302   SyncableExtensionSettingsStorage* storage2; | 
|  | 303   // Maintain dictionaries mirrored to the expected values of the settings in | 
|  | 304   // each storage area. | 
|  | 305   // TODO rename these. | 
|  | 306   DictionaryValue settings1, settings2; | 
|  | 307 | 
|  | 308   // Make storage1 initialised from local data, storage2 initialised from sync. | 
|  | 309   GetStorage("storage1", &storage1); | 
|  | 310   GetStorage("storage2", &storage2); | 
|  | 311 | 
|  | 312   storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 313   settings1.Set("foo", value1.DeepCopy()); | 
|  | 314   MessageLoop::current()->RunAllPending(); | 
|  | 315 | 
|  | 316   SyncDataList sync_data; | 
|  | 317   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 318       "storage2", "bar", value2)); | 
|  | 319   settings2.Set("bar", value2.DeepCopy()); | 
|  | 320 | 
|  | 321   settings_->MergeDataAndStartSyncing( | 
|  | 322       syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | 
|  | 323   MessageLoop::current()->RunAllPending(); | 
|  | 324 | 
|  | 325   // Make sync add some settings. | 
|  | 326   SyncChangeList change_list; | 
|  | 327   change_list.push_back(ExtensionSettingsSyncHelper::CreateAdd( | 
|  | 328       "storage1", "bar", value2)); | 
|  | 329   settings1.Set("bar", value2.DeepCopy()); | 
|  | 330   change_list.push_back(ExtensionSettingsSyncHelper::CreateAdd( | 
|  | 331       "storage2", "foo", value1)); | 
|  | 332   settings2.Set("foo", value1.DeepCopy()); | 
|  | 333   settings_->ProcessSyncChanges(FROM_HERE, change_list); | 
|  | 334   MessageLoop::current()->RunAllPending(); | 
|  | 335 | 
|  | 336   storage1->Get(NEW_CALLBACK(&settings1)); | 
|  | 337   storage2->Get(NEW_CALLBACK(&settings2)); | 
|  | 338   MessageLoop::current()->RunAllPending(); | 
|  | 339 | 
|  | 340   // Make sync update some settings, storage1 the new setting, storage2 the | 
|  | 341   // initial setting. | 
|  | 342   change_list.clear(); | 
|  | 343   change_list.push_back(ExtensionSettingsSyncHelper::CreateUpdate( | 
|  | 344       "storage1", "bar", value2)); | 
|  | 345   settings1.Set("bar", value2.DeepCopy()); | 
|  | 346   change_list.push_back(ExtensionSettingsSyncHelper::CreateUpdate( | 
|  | 347       "storage2", "bar", value1)); | 
|  | 348   settings2.Set("bar", value1.DeepCopy()); | 
|  | 349   settings_->ProcessSyncChanges(FROM_HERE, change_list); | 
|  | 350   MessageLoop::current()->RunAllPending(); | 
|  | 351 | 
|  | 352   storage1->Get(NEW_CALLBACK(&settings1)); | 
|  | 353   storage2->Get(NEW_CALLBACK(&settings2)); | 
|  | 354   MessageLoop::current()->RunAllPending(); | 
|  | 355 | 
|  | 356   // Make sync remove some settings, storage1 the initial setting, storage2 the | 
|  | 357   // new setting. | 
|  | 358   change_list.clear(); | 
|  | 359   change_list.push_back(ExtensionSettingsSyncHelper::CreateDelete( | 
|  | 360       "storage1", "foo")); | 
|  | 361   settings1.Remove("foo", NULL); | 
|  | 362   change_list.push_back(ExtensionSettingsSyncHelper::CreateDelete( | 
|  | 363       "storage2", "foo")); | 
|  | 364   settings2.Remove("foo", NULL); | 
|  | 365   settings_->ProcessSyncChanges(FROM_HERE, change_list); | 
|  | 366   MessageLoop::current()->RunAllPending(); | 
|  | 367 | 
|  | 368   storage1->Get(NEW_CALLBACK(&settings1)); | 
|  | 369   storage2->Get(NEW_CALLBACK(&settings2)); | 
|  | 370   MessageLoop::current()->RunAllPending(); | 
|  | 371 | 
|  | 372   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 373   MessageLoop::current()->RunAllPending(); | 
|  | 374 } | 
|  | 375 | 
|  | 376 TEST_F(ExtensionSettingsSyncUnittest, PushToSync) { | 
|  | 377   StringValue value1("fooValue"); | 
|  | 378   ListValue value2; | 
|  | 379   value2.Append(StringValue::CreateStringValue("barValue")); | 
|  | 380 | 
|  | 381   SyncableExtensionSettingsStorage* storage1; | 
|  | 382   SyncableExtensionSettingsStorage* storage2; | 
|  | 383   SyncableExtensionSettingsStorage* storage3; | 
|  | 384   SyncableExtensionSettingsStorage* storage4; | 
|  | 385 | 
|  | 386   // Make storage1/2 initialised from local data, storage3/4 initialised from | 
|  | 387   // sync. | 
|  | 388   GetStorage("storage1", &storage1); | 
|  | 389   GetStorage("storage2", &storage2); | 
|  | 390   GetStorage("storage3", &storage3); | 
|  | 391   GetStorage("storage4", &storage4); | 
|  | 392 | 
|  | 393   storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 394   storage2->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 395   MessageLoop::current()->RunAllPending(); | 
|  | 396 | 
|  | 397   SyncDataList sync_data; | 
|  | 398   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 399       "storage3", "bar", value2)); | 
|  | 400   sync_data.push_back(ExtensionSettingsSyncHelper::CreateData( | 
|  | 401       "storage4", "bar", value2)); | 
|  | 402 | 
|  | 403   settings_->MergeDataAndStartSyncing( | 
|  | 404       syncable::EXTENSION_SETTINGS, sync_data, sync_.get()); | 
|  | 405   MessageLoop::current()->RunAllPending(); | 
|  | 406 | 
|  | 407   // Add something locally. | 
|  | 408   storage1->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 409   storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 410   storage3->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 411   storage4->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 412   MessageLoop::current()->RunAllPending(); | 
|  | 413 | 
|  | 414   ExtensionSettingsSyncData change = sync_->GetOnlyChange("storage1", "bar"); | 
|  | 415     ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 416     ASSERT_TRUE(value2.Equals(change.value())); | 
|  | 417   sync_->GetOnlyChange("storage2", "bar"); | 
|  | 418     ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 419     ASSERT_TRUE(value2.Equals(change.value())); | 
|  | 420   change = sync_->GetOnlyChange("storage3", "foo"); | 
|  | 421     ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 422     ASSERT_TRUE(value1.Equals(change.value())); | 
|  | 423   change = sync_->GetOnlyChange("storage4", "foo"); | 
|  | 424     ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type()); | 
|  | 425     ASSERT_TRUE(value1.Equals(change.value())); | 
|  | 426 | 
|  | 427   // Change something locally, storage1/3 the new setting and storage2/4 the | 
|  | 428   // initial setting, for all combinations of local vs sync intialisation and | 
|  | 429   // new vs initial. | 
|  | 430   sync_->ClearChanges(); | 
|  | 431   storage1->Set("bar", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 432   storage2->Set("foo", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 433   storage3->Set("bar", value1, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 434   storage4->Set("foo", value2, new ExtensionSettingsStorage::NoopCallback()); | 
|  | 435   MessageLoop::current()->RunAllPending(); | 
|  | 436 | 
|  | 437   change = sync_->GetOnlyChange("storage1", "bar"); | 
|  | 438     ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | 
|  | 439     ASSERT_TRUE(value1.Equals(change.value())); | 
|  | 440   change = sync_->GetOnlyChange("storage2", "foo"); | 
|  | 441     ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | 
|  | 442     ASSERT_TRUE(value2.Equals(change.value())); | 
|  | 443   change = sync_->GetOnlyChange("storage3", "bar"); | 
|  | 444     ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | 
|  | 445     ASSERT_TRUE(value1.Equals(change.value())); | 
|  | 446   change = sync_->GetOnlyChange("storage4", "foo"); | 
|  | 447     ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | 
|  | 448     ASSERT_TRUE(value2.Equals(change.value())); | 
|  | 449 | 
|  | 450   // Remove something locally, storage1/3 the new setting and storage2/4 the | 
|  | 451   // initial setting, for all combinations of local vs sync intialisation and | 
|  | 452   // new vs initial. | 
|  | 453   sync_->ClearChanges(); | 
|  | 454   storage1->Remove("foo", new ExtensionSettingsStorage::NoopCallback()); | 
|  | 455   storage2->Remove("bar", new ExtensionSettingsStorage::NoopCallback()); | 
|  | 456   storage3->Remove("foo", new ExtensionSettingsStorage::NoopCallback()); | 
|  | 457   storage4->Remove("bar", new ExtensionSettingsStorage::NoopCallback()); | 
|  | 458   MessageLoop::current()->RunAllPending(); | 
|  | 459 | 
|  | 460   change = sync_->GetOnlyChange("storage1", "foo"); | 
|  | 461     ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type()); | 
|  | 462   change = sync_->GetOnlyChange("storage2", "bar"); | 
|  | 463     ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type()); | 
|  | 464   change = sync_->GetOnlyChange("storage3", "foo"); | 
|  | 465     ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type()); | 
|  | 466   change = sync_->GetOnlyChange("storage4", "bar"); | 
|  | 467     ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type()); | 
|  | 468 | 
|  | 469   // XXX CLEAR | 
|  | 470 | 
|  | 471   settings_->StopSyncing(syncable::EXTENSION_SETTINGS); | 
|  | 472   MessageLoop::current()->RunAllPending(); | 
|  | 473 } | 
| OLD | NEW | 
|---|