Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1320)

Unified Diff: chrome/browser/extensions/settings/settings_sync_unittest.cc

Issue 8539037: Extension Settings API: make it so that when changes received from Sync fail to (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: disable all sync, not just outgoing Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/settings/settings_sync_unittest.cc
diff --git a/chrome/browser/extensions/settings/settings_sync_unittest.cc b/chrome/browser/extensions/settings/settings_sync_unittest.cc
index 5cf90399648e184e3f7f231f17f3de6334968f02..2f22f57c89e6696fca0376fcc72a06772ad85a8a 100644
--- a/chrome/browser/extensions/settings/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/settings/settings_sync_unittest.cc
@@ -11,19 +11,22 @@
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
#include "base/task.h"
+#include "chrome/browser/extensions/settings/failing_settings_storage.h"
#include "chrome/browser/extensions/settings/settings_frontend.h"
#include "chrome/browser/extensions/settings/settings_storage_cache.h"
+#include "chrome/browser/extensions/settings/settings_storage_factory.h"
#include "chrome/browser/extensions/settings/settings_sync_util.h"
-#include "chrome/browser/extensions/settings/syncable_settings_storage.h"
#include "chrome/browser/extensions/settings/settings_test_util.h"
+#include "chrome/browser/extensions/settings/syncable_settings_storage.h"
+#include "chrome/browser/extensions/settings/testing_settings_storage.h"
#include "chrome/browser/sync/api/sync_change_processor.h"
#include "content/test/test_browser_thread.h"
-namespace extensions {
+// TODO(kalman): Integration tests for sync.
using content::BrowserThread;
-// TODO(kalman): Integration tests for sync.
+namespace extensions {
using namespace settings_test_util;
@@ -77,9 +80,18 @@ testing::AssertionResult SettingsEq(
// being converted to the more useful SettingSyncData via changes().
class MockSyncChangeProcessor : public SyncChangeProcessor {
public:
+ MockSyncChangeProcessor() : fail_all_requests_(false) {}
+
+ // SyncChangeProcessor implementation.
virtual SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const SyncChangeList& change_list) OVERRIDE {
+ if (fail_all_requests_) {
+ return SyncError(
+ FROM_HERE,
+ "MockSyncChangeProcessor: configured to fail",
+ change_list[0].sync_data().GetDataType());
+ }
for (SyncChangeList::const_iterator it = change_list.begin();
it != change_list.end(); ++it) {
changes_.push_back(SettingSyncData(*it));
@@ -87,12 +99,18 @@ class MockSyncChangeProcessor : public SyncChangeProcessor {
return SyncError();
}
+ // Mock methods.
+
const SettingSyncDataList& changes() { return changes_; }
void ClearChanges() {
changes_.clear();
}
+ void SetFailAllRequests(bool fail_all_requests) {
+ fail_all_requests_ = fail_all_requests;
+ }
+
// Returns the only change for a given extension setting. If there is not
// exactly 1 change for that key, a test assertion will fail.
SettingSyncData GetOnlyChange(
@@ -119,6 +137,31 @@ class MockSyncChangeProcessor : public SyncChangeProcessor {
private:
SettingSyncDataList changes_;
+ bool fail_all_requests_;
+};
+
+// SettingsStorageFactory which always returns TestingSettingsStorage objects,
+// and allows individually created objects to be returned.
+class TestingSettingsStorageFactory : public SettingsStorageFactory {
+ public:
+ TestingSettingsStorage* GetExisting(const std::string& extension_id) {
+ DCHECK(created_.count(extension_id));
+ return created_[extension_id];
+ }
+
+ // SettingsStorageFactory implementation.
+ virtual SettingsStorage* Create(
+ const FilePath& base_path, const std::string& extension_id) OVERRIDE {
+ TestingSettingsStorage* new_storage = new TestingSettingsStorage();
+ DCHECK(!created_.count(extension_id));
+ created_[extension_id] = new_storage;
+ return new_storage;
+ }
+
+ private:
+ // None of these storage areas are owned by this factory, so care must be
+ // taken when calling GetExisting.
+ std::map<std::string, TestingSettingsStorage*> created_;
};
void AssignSettingsService(SyncableService** dst, SyncableService* src) {
@@ -136,7 +179,9 @@ class ExtensionSettingsSyncTest : public testing::Test {
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
profile_.reset(new MockProfile(temp_dir_.path()));
- frontend_.reset(SettingsFrontend::Create(profile_.get()));
+ storage_factory_ =
+ new ScopedSettingsStorageFactory(new SettingsLeveldbStorage::Factory());
+ frontend_.reset(SettingsFrontend::Create(storage_factory_, profile_.get()));
}
virtual void TearDown() OVERRIDE {
@@ -186,6 +231,9 @@ class ExtensionSettingsSyncTest : public testing::Test {
MockSyncChangeProcessor sync_;
scoped_ptr<MockProfile> profile_;
scoped_ptr<SettingsFrontend> frontend_;
+
+ // Owned by |frontend_|.
+ ScopedSettingsStorageFactory* storage_factory_;
};
// Get a semblance of coverage for both EXTENSION_SETTINGS and APP_SETTINGS
@@ -587,4 +635,615 @@ TEST_F(ExtensionSettingsSyncTest, ExtensionAndAppSettingsSyncSeparately) {
ASSERT_EQ(0u, sync_.changes().size());
}
+TEST_F(ExtensionSettingsSyncTest, FailingStartSyncingDisablesSync) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ // There is a bit of a convoluted method to get storage areas that can fail;
+ // hand out TestingSettingsStorage object then toggle them failing/succeeding
+ // as necessary.
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ // Make bad fail for incoming sync changes.
+ testing_factory->GetExisting("bad")->SetFailAllRequests(true);
+ {
+ SyncDataList sync_data;
+ sync_data.push_back(
+ settings_sync_util::CreateData("good", "foo", fooValue));
+ sync_data.push_back(
+ settings_sync_util::CreateData("bad", "foo", fooValue));
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
+ }
+ testing_factory->GetExisting("bad")->SetFailAllRequests(false);
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Changes made to good should be sent to sync, changes from bad shouldn't.
+ sync_.ClearChanges();
+ good->Set("bar", barValue);
+ bad->Set("bar", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Changes received from sync should go to good but not bad (even when it's
+ // not failing).
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("good", "foo", barValue));
+ // (Sending UPDATE here even though it's adding, since that's what the state
+ // of sync is. In any case, it won't work.)
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("bad", "foo", barValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Changes made to bad still shouldn't go to sync, even though it didn't fail
+ // last time.
+ sync_.ClearChanges();
+ good->Set("bar", fooValue);
+ bad->Set("bar", fooValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Failing ProcessSyncChanges shouldn't go to the storage.
+ testing_factory->GetExisting("bad")->SetFailAllRequests(true);
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("good", "foo", fooValue));
+ // (Ditto.)
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("bad", "foo", fooValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+ testing_factory->GetExisting("bad")->SetFailAllRequests(false);
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Restarting sync should make bad start syncing again.
+ sync_.ClearChanges();
+ GetSyncableService(model_type)->StopSyncing(model_type);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ // Local settings will have been pushed to sync, since it's empty (in this
+ // test; presumably it wouldn't be live, since we've been getting changes).
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "bar").change_type());
+ EXPECT_EQ(3u, sync_.changes().size());
+
+ // Live local changes now get pushed, too.
+ sync_.ClearChanges();
+ good->Set("bar", barValue);
+ bad->Set("bar", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("bad", "bar").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+
+ // And ProcessSyncChanges work, too.
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("good", "bar", fooValue));
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("bad", "bar", fooValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("bar", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+}
+
+TEST_F(ExtensionSettingsSyncTest, FailingProcessChangesDisablesSync) {
+ // The test above tests a failing ProcessSyncChanges too, but here test with
+ // an initially passing MergeDataAndStartSyncing.
+ syncable::ModelType model_type = syncable::APP_SETTINGS;
+ Extension::Type type = Extension::TYPE_PACKAGED_APP;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ // Unlike before, initially succeeding MergeDataAndStartSyncing.
+ {
+ SyncDataList sync_data;
+ sync_data.push_back(
+ settings_sync_util::CreateData("good", "foo", fooValue));
+ sync_data.push_back(
+ settings_sync_util::CreateData("bad", "foo", fooValue));
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
+ }
+
+ EXPECT_EQ(0u, sync_.changes().size());
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Now fail ProcessSyncChanges for bad.
+ testing_factory->GetExisting("bad")->SetFailAllRequests(true);
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateAdd("good", "bar", barValue));
+ change_list.push_back(
+ settings_sync_util::CreateAdd("bad", "bar", barValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+ testing_factory->GetExisting("bad")->SetFailAllRequests(false);
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // No more changes sent to sync for bad.
+ sync_.ClearChanges();
+ good->Set("foo", barValue);
+ bad->Set("foo", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ // No more changes received from sync should go to bad.
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateAdd("good", "foo", fooValue));
+ change_list.push_back(
+ settings_sync_util::CreateAdd("bad", "foo", fooValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+}
+
+TEST_F(ExtensionSettingsSyncTest, FailingGetAllSyncDataDoesntStopSync) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ good->Set("foo", fooValue);
+ bad->Set("foo", fooValue);
+
+ // Even though bad will fail to get all sync data, sync data should still
+ // include that from good.
+ testing_factory->GetExisting("bad")->SetFailAllRequests(true);
+ {
+ SyncDataList all_sync_data =
+ GetSyncableService(model_type)->GetAllSyncData(model_type);
+ EXPECT_EQ(1u, all_sync_data.size());
+ EXPECT_EQ("good/foo", all_sync_data[0].GetTag());
+ }
+ testing_factory->GetExisting("bad")->SetFailAllRequests(false);
+
+ // Sync shouldn't be disabled for good (nor bad -- but this is unimportant).
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "foo").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+
+ sync_.ClearChanges();
+ good->Set("bar", barValue);
+ bad->Set("bar", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "bar").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+}
+
+TEST_F(ExtensionSettingsSyncTest, FailureToReadChangesToPushDisablesSync) {
+ syncable::ModelType model_type = syncable::APP_SETTINGS;
+ Extension::Type type = Extension::TYPE_PACKAGED_APP;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ good->Set("foo", fooValue);
+ bad->Set("foo", fooValue);
+
+ // good will successfully push foo:fooValue to sync, but bad will fail to
+ // get them so won't.
+ testing_factory->GetExisting("bad")->SetFailAllRequests(true);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+ testing_factory->GetExisting("bad")->SetFailAllRequests(false);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ // bad should now be disabled for sync.
+ sync_.ClearChanges();
+ good->Set("bar", barValue);
+ bad->Set("bar", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateUpdate("good", "foo", barValue));
+ // (Sending ADD here even though it's updating, since that's what the state
+ // of sync is. In any case, it won't work.)
+ change_list.push_back(
+ settings_sync_util::CreateAdd("bad", "foo", barValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", fooValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Re-enabling sync without failing should cause the local changes from bad
+ // to be pushed to sync successfully, as should future changes to bad.
+ sync_.ClearChanges();
+ GetSyncableService(model_type)->StopSyncing(model_type);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "bar").change_type());
+ EXPECT_EQ(4u, sync_.changes().size());
+
+ sync_.ClearChanges();
+ good->Set("bar", fooValue);
+ bad->Set("bar", fooValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+}
+
+TEST_F(ExtensionSettingsSyncTest, FailureToPushLocalStateDisablesSync) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ // Only set bad; setting good will cause it to fail below.
+ bad->Set("foo", fooValue);
+
+ sync_.SetFailAllRequests(true);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+ sync_.SetFailAllRequests(false);
+
+ // Changes from good will be send to sync, changes from bad won't.
+ sync_.ClearChanges();
+ good->Set("foo", barValue);
+ bad->Set("foo", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ // Changes from sync will be sent to good, not to bad.
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateAdd("good", "bar", barValue));
+ change_list.push_back(
+ settings_sync_util::CreateAdd("bad", "bar", barValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Restarting sync makes everything work again.
+ sync_.ClearChanges();
+ GetSyncableService(model_type)->StopSyncing(model_type);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "foo").change_type());
+ EXPECT_EQ(3u, sync_.changes().size());
+
+ sync_.ClearChanges();
+ good->Set("foo", fooValue);
+ bad->Set("foo", fooValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+}
+
+TEST_F(ExtensionSettingsSyncTest, FailureToPushLocalChangeDisablesSync) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
+ StringValue fooValue("fooValue");
+ StringValue barValue("barValue");
+
+ TestingSettingsStorageFactory* testing_factory =
+ new TestingSettingsStorageFactory();
+ storage_factory_->Reset(testing_factory);
+
+ SettingsStorage* good = AddExtensionAndGetStorage("good", type);
+ SettingsStorage* bad = AddExtensionAndGetStorage("bad", type);
+
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ // bad will fail to send changes.
+ good->Set("foo", fooValue);
+ sync_.SetFailAllRequests(true);
+ bad->Set("foo", fooValue);
+ sync_.SetFailAllRequests(false);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ // No further changes should be sent from bad.
+ sync_.ClearChanges();
+ good->Set("foo", barValue);
+ bad->Set("foo", barValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(1u, sync_.changes().size());
+
+ // Changes from sync will be sent to good, not to bad.
+ {
+ SyncChangeList change_list;
+ change_list.push_back(
+ settings_sync_util::CreateAdd("good", "bar", barValue));
+ change_list.push_back(
+ settings_sync_util::CreateAdd("bad", "bar", barValue));
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ dict.Set("bar", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, good->Get());
+ }
+ {
+ DictionaryValue dict;
+ dict.Set("foo", barValue.DeepCopy());
+ EXPECT_PRED_FORMAT2(SettingsEq, dict, bad->Get());
+ }
+
+ // Restarting sync makes everything work again.
+ sync_.ClearChanges();
+ GetSyncableService(model_type)->StopSyncing(model_type);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("good", "bar").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_ADD,
+ sync_.GetOnlyChange("bad", "foo").change_type());
+ EXPECT_EQ(3u, sync_.changes().size());
+
+ sync_.ClearChanges();
+ good->Set("foo", fooValue);
+ bad->Set("foo", fooValue);
+
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(
+ SyncChange::ACTION_UPDATE,
+ sync_.GetOnlyChange("good", "foo").change_type());
+ EXPECT_EQ(2u, sync_.changes().size());
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698