Index: chrome/browser/sync/engine/apply_updates_command_unittest.cc |
diff --git a/chrome/browser/sync/engine/apply_updates_command_unittest.cc b/chrome/browser/sync/engine/apply_updates_command_unittest.cc |
deleted file mode 100644 |
index 1672d6e534859aee90dbb3d8c7350f3a518077a1..0000000000000000000000000000000000000000 |
--- a/chrome/browser/sync/engine/apply_updates_command_unittest.cc |
+++ /dev/null |
@@ -1,1007 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include <string> |
- |
-#include "base/format_macros.h" |
-#include "base/location.h" |
-#include "base/stringprintf.h" |
-#include "chrome/browser/sync/engine/apply_updates_command.h" |
-#include "chrome/browser/sync/engine/nigori_util.h" |
-#include "chrome/browser/sync/engine/syncer.h" |
-#include "chrome/browser/sync/engine/syncer_util.h" |
-#include "chrome/browser/sync/sessions/sync_session.h" |
-#include "chrome/browser/sync/syncable/syncable.h" |
-#include "chrome/browser/sync/syncable/syncable_id.h" |
-#include "chrome/browser/sync/test/engine/fake_model_worker.h" |
-#include "chrome/browser/sync/test/engine/syncer_command_test.h" |
-#include "chrome/browser/sync/test/engine/test_id_factory.h" |
-#include "chrome/browser/sync/test/fake_encryptor.h" |
-#include "chrome/browser/sync/util/cryptographer.h" |
-#include "sync/protocol/bookmark_specifics.pb.h" |
-#include "sync/protocol/password_specifics.pb.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace browser_sync { |
- |
-using sessions::SyncSession; |
-using std::string; |
-using syncable::Entry; |
-using syncable::Id; |
-using syncable::MutableEntry; |
-using syncable::ReadTransaction; |
-using syncable::UNITTEST; |
-using syncable::WriteTransaction; |
- |
-namespace { |
-sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { |
- sync_pb::EntitySpecifics result; |
- AddDefaultFieldValue(syncable::BOOKMARKS, &result); |
- return result; |
-} |
-} // namespace |
- |
-// A test fixture for tests exercising ApplyUpdatesCommand. |
-class ApplyUpdatesCommandTest : public SyncerCommandTest { |
- public: |
- protected: |
- ApplyUpdatesCommandTest() : next_revision_(1) {} |
- virtual ~ApplyUpdatesCommandTest() {} |
- |
- virtual void SetUp() { |
- workers()->clear(); |
- mutable_routing_info()->clear(); |
- workers()->push_back( |
- make_scoped_refptr(new FakeModelWorker(GROUP_UI))); |
- workers()->push_back( |
- make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD))); |
- (*mutable_routing_info())[syncable::BOOKMARKS] = GROUP_UI; |
- (*mutable_routing_info())[syncable::PASSWORDS] = GROUP_PASSWORD; |
- (*mutable_routing_info())[syncable::NIGORI] = GROUP_PASSIVE; |
- SyncerCommandTest::SetUp(); |
- ExpectNoGroupsToChange(apply_updates_command_); |
- } |
- |
- // Create a new unapplied folder node with a parent. |
- void CreateUnappliedNewItemWithParent( |
- const string& item_id, |
- const sync_pb::EntitySpecifics& specifics, |
- const string& parent_id) { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, |
- Id::CreateFromServerId(item_id)); |
- ASSERT_TRUE(entry.good()); |
- entry.Put(syncable::SERVER_VERSION, next_revision_++); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- |
- entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id); |
- entry.Put(syncable::SERVER_PARENT_ID, Id::CreateFromServerId(parent_id)); |
- entry.Put(syncable::SERVER_IS_DIR, true); |
- entry.Put(syncable::SERVER_SPECIFICS, specifics); |
- } |
- |
- // Create a new unapplied update without a parent. |
- void CreateUnappliedNewItem(const string& item_id, |
- const sync_pb::EntitySpecifics& specifics, |
- bool is_unique) { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, |
- Id::CreateFromServerId(item_id)); |
- ASSERT_TRUE(entry.good()); |
- entry.Put(syncable::SERVER_VERSION, next_revision_++); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id); |
- entry.Put(syncable::SERVER_PARENT_ID, syncable::GetNullId()); |
- entry.Put(syncable::SERVER_IS_DIR, false); |
- entry.Put(syncable::SERVER_SPECIFICS, specifics); |
- if (is_unique) // For top-level nodes. |
- entry.Put(syncable::UNIQUE_SERVER_TAG, item_id); |
- } |
- |
- // Create an unsynced item in the database. If item_id is a local ID, it |
- // will be treated as a create-new. Otherwise, if it's a server ID, we'll |
- // fake the server data so that it looks like it exists on the server. |
- // Returns the methandle of the created item in |metahandle_out| if not NULL. |
- void CreateUnsyncedItem(const Id& item_id, |
- const Id& parent_id, |
- const string& name, |
- bool is_folder, |
- syncable::ModelType model_type, |
- int64* metahandle_out) { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- Id predecessor_id; |
- ASSERT_TRUE( |
- directory()->GetLastChildIdForTest(&trans, parent_id, &predecessor_id)); |
- MutableEntry entry(&trans, syncable::CREATE, parent_id, name); |
- ASSERT_TRUE(entry.good()); |
- entry.Put(syncable::ID, item_id); |
- entry.Put(syncable::BASE_VERSION, |
- item_id.ServerKnows() ? next_revision_++ : 0); |
- entry.Put(syncable::IS_UNSYNCED, true); |
- entry.Put(syncable::IS_DIR, is_folder); |
- entry.Put(syncable::IS_DEL, false); |
- entry.Put(syncable::PARENT_ID, parent_id); |
- CHECK(entry.PutPredecessor(predecessor_id)); |
- sync_pb::EntitySpecifics default_specifics; |
- syncable::AddDefaultFieldValue(model_type, &default_specifics); |
- entry.Put(syncable::SPECIFICS, default_specifics); |
- if (item_id.ServerKnows()) { |
- entry.Put(syncable::SERVER_SPECIFICS, default_specifics); |
- entry.Put(syncable::SERVER_IS_DIR, is_folder); |
- entry.Put(syncable::SERVER_PARENT_ID, parent_id); |
- entry.Put(syncable::SERVER_IS_DEL, false); |
- } |
- if (metahandle_out) |
- *metahandle_out = entry.Get(syncable::META_HANDLE); |
- } |
- |
- // Creates an item that is both unsynced an an unapplied update. Returns the |
- // metahandle of the created item. |
- int64 CreateUnappliedAndUnsyncedItem(const string& name, |
- syncable::ModelType model_type) { |
- int64 metahandle = 0; |
- CreateUnsyncedItem(id_factory_.MakeServer(name), id_factory_.root(), name, |
- false, model_type, &metahandle); |
- |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_HANDLE, metahandle); |
- if (!entry.good()) { |
- ADD_FAILURE(); |
- return syncable::kInvalidMetaHandle; |
- } |
- |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- entry.Put(syncable::SERVER_VERSION, GetNextRevision()); |
- |
- return metahandle; |
- } |
- |
- |
- // Creates an item that has neither IS_UNSYNED or IS_UNAPPLIED_UPDATE. The |
- // item is known to both the server and client. Returns the metahandle of |
- // the created item. |
- int64 CreateSyncedItem(const std::string& name, syncable::ModelType |
- model_type, bool is_folder) { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- |
- syncable::Id parent_id(id_factory_.root()); |
- syncable::Id item_id(id_factory_.MakeServer(name)); |
- int64 version = GetNextRevision(); |
- |
- sync_pb::EntitySpecifics default_specifics; |
- syncable::AddDefaultFieldValue(model_type, &default_specifics); |
- |
- MutableEntry entry(&trans, syncable::CREATE, parent_id, name); |
- if (!entry.good()) { |
- ADD_FAILURE(); |
- return syncable::kInvalidMetaHandle; |
- } |
- |
- entry.Put(syncable::ID, item_id); |
- entry.Put(syncable::BASE_VERSION, version); |
- entry.Put(syncable::IS_UNSYNCED, false); |
- entry.Put(syncable::NON_UNIQUE_NAME, name); |
- entry.Put(syncable::IS_DIR, is_folder); |
- entry.Put(syncable::IS_DEL, false); |
- entry.Put(syncable::PARENT_ID, parent_id); |
- |
- if (!entry.PutPredecessor(id_factory_.root())) { |
- ADD_FAILURE(); |
- return syncable::kInvalidMetaHandle; |
- } |
- entry.Put(syncable::SPECIFICS, default_specifics); |
- |
- entry.Put(syncable::SERVER_VERSION, GetNextRevision()); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- entry.Put(syncable::SERVER_NON_UNIQUE_NAME, "X"); |
- entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y")); |
- entry.Put(syncable::SERVER_IS_DIR, is_folder); |
- entry.Put(syncable::SERVER_IS_DEL, false); |
- entry.Put(syncable::SERVER_SPECIFICS, default_specifics); |
- entry.Put(syncable::SERVER_PARENT_ID, parent_id); |
- |
- return entry.Get(syncable::META_HANDLE); |
- } |
- |
- int64 GetNextRevision() { |
- return next_revision_++; |
- } |
- |
- ApplyUpdatesCommand apply_updates_command_; |
- FakeEncryptor encryptor_; |
- TestIdFactory id_factory_; |
- private: |
- int64 next_revision_; |
- DISALLOW_COPY_AND_ASSIGN(ApplyUpdatesCommandTest); |
-}; |
- |
-TEST_F(ApplyUpdatesCommandTest, Simple) { |
- string root_server_id = syncable::GetNullId().GetServerId(); |
- CreateUnappliedNewItemWithParent("parent", |
- DefaultBookmarkSpecifics(), |
- root_server_id); |
- CreateUnappliedNewItemWithParent("child", |
- DefaultBookmarkSpecifics(), |
- "parent"); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "Simple update shouldn't result in conflicts"; |
- EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "Simple update shouldn't result in conflicts"; |
- EXPECT_EQ(0, status->conflict_progress()->HierarchyConflictingItemsSize()) |
- << "Simple update shouldn't result in conflicts"; |
- EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "All items should have been successfully applied"; |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, UpdateWithChildrenBeforeParents) { |
- // Set a bunch of updates which are difficult to apply in the order |
- // they're received due to dependencies on other unseen items. |
- string root_server_id = syncable::GetNullId().GetServerId(); |
- CreateUnappliedNewItemWithParent("a_child_created_first", |
- DefaultBookmarkSpecifics(), |
- "parent"); |
- CreateUnappliedNewItemWithParent("x_child_created_first", |
- DefaultBookmarkSpecifics(), |
- "parent"); |
- CreateUnappliedNewItemWithParent("parent", |
- DefaultBookmarkSpecifics(), |
- root_server_id); |
- CreateUnappliedNewItemWithParent("a_child_created_second", |
- DefaultBookmarkSpecifics(), |
- "parent"); |
- CreateUnappliedNewItemWithParent("x_child_created_second", |
- DefaultBookmarkSpecifics(), |
- "parent"); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(5, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "Simple update shouldn't result in conflicts, even if out-of-order"; |
- EXPECT_EQ(5, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "All updates should have been successfully applied"; |
-} |
- |
-// Runs the ApplyUpdatesCommand on an item that has both local and remote |
-// modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We expect the command |
-// to detect that this update can't be applied because it is in a CONFLICT |
-// state. |
-TEST_F(ApplyUpdatesCommandTest, SimpleConflict) { |
- CreateUnappliedAndUnsyncedItem("item", syncable::BOOKMARKS); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(1, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "Unsynced and unapplied item should be a simple conflict"; |
-} |
- |
-// Runs the ApplyUpdatesCommand on an item that has both local and remote |
-// modifications *and* the remote modification cannot be applied without |
-// violating the tree constraints. We expect the command to detect that this |
-// update can't be applied and that this situation can't be resolved with the |
-// simple conflict processing logic; it is in a CONFLICT_HIERARCHY state. |
-TEST_F(ApplyUpdatesCommandTest, HierarchyAndSimpleConflict) { |
- // Create a simply-conflicting item. It will start with valid parent ids. |
- int64 handle = CreateUnappliedAndUnsyncedItem("orphaned_by_server", |
- syncable::BOOKMARKS); |
- { |
- // Manually set the SERVER_PARENT_ID to bad value. |
- // A bad parent indicates a hierarchy conflict. |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
- ASSERT_TRUE(entry.good()); |
- |
- entry.Put(syncable::SERVER_PARENT_ID, |
- id_factory_.MakeServer("bogus_parent")); |
- } |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); |
- |
- // An update that is both a simple conflict and a hierarchy conflict should be |
- // treated as a hierarchy conflict. |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); |
-} |
- |
- |
-// Runs the ApplyUpdatesCommand on an item with remote modifications that would |
-// create a directory loop if the update were applied. We expect the command to |
-// detect that this update can't be applied because it is in a |
-// CONFLICT_HIERARCHY state. |
-TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDirectoryLoop) { |
- // Item 'X' locally has parent of 'root'. Server is updating it to have |
- // parent of 'Y'. |
- { |
- // Create it as a child of root node. |
- int64 handle = CreateSyncedItem("X", syncable::BOOKMARKS, true); |
- |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
- ASSERT_TRUE(entry.good()); |
- |
- // Re-parent from root to "Y" |
- entry.Put(syncable::SERVER_VERSION, GetNextRevision()); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y")); |
- } |
- |
- // Item 'Y' is child of 'X'. |
- CreateUnsyncedItem(id_factory_.MakeServer("Y"), id_factory_.MakeServer("X"), |
- "Y", true, syncable::BOOKMARKS, NULL); |
- |
- // If the server's update were applied, we would have X be a child of Y, and Y |
- // as a child of X. That's a directory loop. The UpdateApplicator should |
- // prevent the update from being applied and note that this is a hierarchy |
- // conflict. |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); |
- |
- // This should count as a hierarchy conflict. |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); |
-} |
- |
-// Runs the ApplyUpdatesCommand on a directory where the server sent us an |
-// update to add a child to a locally deleted (and unsynced) parent. We expect |
-// the command to not apply the update and to indicate the update is in a |
-// CONFLICT_HIERARCHY state. |
-TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeletedParent) { |
- // Create a locally deleted parent item. |
- int64 parent_handle; |
- CreateUnsyncedItem(Id::CreateFromServerId("parent"), id_factory_.root(), |
- "parent", true, syncable::BOOKMARKS, &parent_handle); |
- { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle); |
- entry.Put(syncable::IS_DEL, true); |
- } |
- |
- // Create an incoming child from the server. |
- CreateUnappliedNewItemWithParent("child", DefaultBookmarkSpecifics(), |
- "parent"); |
- |
- // The server's update may seem valid to some other client, but on this client |
- // that new item's parent no longer exists. The update should not be applied |
- // and the update applicator should indicate this is a hierarchy conflict. |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- |
- // This should count as a hierarchy conflict. |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); |
-} |
- |
-// Runs the ApplyUpdatesCommand on a directory where the server is trying to |
-// delete a folder that has a recently added (and unsynced) child. We expect |
-// the command to not apply the update because it is in a CONFLICT_HIERARCHY |
-// state. |
-TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeleteNonEmptyDirectory) { |
- // Create a server-deleted directory. |
- { |
- // Create it as a child of root node. |
- int64 handle = CreateSyncedItem("parent", syncable::BOOKMARKS, true); |
- |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
- ASSERT_TRUE(entry.good()); |
- |
- // Delete it on the server. |
- entry.Put(syncable::SERVER_VERSION, GetNextRevision()); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- entry.Put(syncable::SERVER_PARENT_ID, id_factory_.root()); |
- entry.Put(syncable::SERVER_IS_DEL, true); |
- } |
- |
- // Create a local child of the server-deleted directory. |
- CreateUnsyncedItem(id_factory_.MakeServer("child"), |
- id_factory_.MakeServer("parent"), "child", false, |
- syncable::BOOKMARKS, NULL); |
- |
- // The server's request to delete the directory must be ignored, otherwise our |
- // unsynced new child would be orphaned. This is a hierarchy conflict. |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- |
- // This should count as a hierarchy conflict. |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); |
-} |
- |
-// Runs the ApplyUpdatesCommand on a server-created item that has a locally |
-// unknown parent. We expect the command to not apply the update because the |
-// item is in a CONFLICT_HIERARCHY state. |
-TEST_F(ApplyUpdatesCommandTest, HierarchyConflictUnknownParent) { |
- // We shouldn't be able to do anything with either of these items. |
- CreateUnappliedNewItemWithParent("some_item", |
- DefaultBookmarkSpecifics(), |
- "unknown_parent"); |
- CreateUnappliedNewItemWithParent("some_other_item", |
- DefaultBookmarkSpecifics(), |
- "some_item"); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "Updates with unknown parent should not be treated as 'simple'" |
- << " conflicts"; |
- EXPECT_EQ(2, status->conflict_progress()->HierarchyConflictingItemsSize()) |
- << "All updates with an unknown ancestors should be in conflict"; |
- EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "No item with an unknown ancestor should be applied"; |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, ItemsBothKnownAndUnknown) { |
- // See what happens when there's a mixture of good and bad updates. |
- string root_server_id = syncable::GetNullId().GetServerId(); |
- CreateUnappliedNewItemWithParent("first_unknown_item", |
- DefaultBookmarkSpecifics(), |
- "unknown_parent"); |
- CreateUnappliedNewItemWithParent("first_known_item", |
- DefaultBookmarkSpecifics(), |
- root_server_id); |
- CreateUnappliedNewItemWithParent("second_unknown_item", |
- DefaultBookmarkSpecifics(), |
- "unknown_parent"); |
- CreateUnappliedNewItemWithParent("second_known_item", |
- DefaultBookmarkSpecifics(), |
- "first_known_item"); |
- CreateUnappliedNewItemWithParent("third_known_item", |
- DefaultBookmarkSpecifics(), |
- "fourth_known_item"); |
- CreateUnappliedNewItemWithParent("fourth_known_item", |
- DefaultBookmarkSpecifics(), |
- root_server_id); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(6, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(2, status->conflict_progress()->HierarchyConflictingItemsSize()) |
- << "The updates with unknown ancestors should be in conflict"; |
- EXPECT_EQ(4, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The updates with known ancestors should be successfully applied"; |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, DecryptablePassword) { |
- // Decryptable password updates should be applied. |
- Cryptographer* cryptographer; |
- { |
- // Storing the cryptographer separately is bad, but for this test we |
- // know it's safe. |
- ReadTransaction trans(FROM_HERE, directory()); |
- cryptographer = directory()->GetCryptographer(&trans); |
- } |
- |
- browser_sync::KeyParams params = {"localhost", "dummy", "foobar"}; |
- cryptographer->AddKey(params); |
- |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::PasswordSpecificsData data; |
- data.set_origin("http://example.com"); |
- |
- cryptographer->Encrypt(data, |
- specifics.mutable_password()->mutable_encrypted()); |
- CreateUnappliedNewItem("item", specifics, false); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "No update should be in conflict because they're all decryptable"; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The updates that can be decrypted should be applied"; |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, UndecryptableData) { |
- // Undecryptable updates should not be applied. |
- sync_pb::EntitySpecifics encrypted_bookmark; |
- encrypted_bookmark.mutable_encrypted(); |
- AddDefaultFieldValue(syncable::BOOKMARKS, &encrypted_bookmark); |
- string root_server_id = syncable::GetNullId().GetServerId(); |
- CreateUnappliedNewItemWithParent("folder", |
- encrypted_bookmark, |
- root_server_id); |
- CreateUnappliedNewItem("item2", encrypted_bookmark, false); |
- sync_pb::EntitySpecifics encrypted_password; |
- encrypted_password.mutable_password(); |
- CreateUnappliedNewItem("item3", encrypted_password, false); |
- |
- ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- EXPECT_TRUE(status->HasConflictingUpdates()) |
- << "Updates that can't be decrypted should trigger the syncer to have " |
- << "conflicting updates."; |
- { |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The updates that can't be decrypted should not be in regular " |
- << "conflict"; |
- EXPECT_EQ(2, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "The updates that can't be decrypted should be in encryption " |
- << "conflict"; |
- EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "No update that can't be decrypted should be applied"; |
- } |
- { |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The updates that can't be decrypted should not be in regular " |
- << "conflict"; |
- EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "The updates that can't be decrypted should be in encryption " |
- << "conflict"; |
- EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "No update that can't be decrypted should be applied"; |
- } |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, SomeUndecryptablePassword) { |
- // Only decryptable password updates should be applied. |
- { |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::PasswordSpecificsData data; |
- data.set_origin("http://example.com/1"); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- Cryptographer* cryptographer = directory()->GetCryptographer(&trans); |
- |
- KeyParams params = {"localhost", "dummy", "foobar"}; |
- cryptographer->AddKey(params); |
- |
- cryptographer->Encrypt(data, |
- specifics.mutable_password()->mutable_encrypted()); |
- } |
- CreateUnappliedNewItem("item1", specifics, false); |
- } |
- { |
- // Create a new cryptographer, independent of the one in the session. |
- Cryptographer cryptographer(&encryptor_); |
- KeyParams params = {"localhost", "dummy", "bazqux"}; |
- cryptographer.AddKey(params); |
- |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::PasswordSpecificsData data; |
- data.set_origin("http://example.com/2"); |
- |
- cryptographer.Encrypt(data, |
- specifics.mutable_password()->mutable_encrypted()); |
- CreateUnappliedNewItem("item2", specifics, false); |
- } |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- EXPECT_TRUE(status->HasConflictingUpdates()) |
- << "Updates that can't be decrypted should trigger the syncer to have " |
- << "conflicting updates."; |
- { |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The updates that can't be decrypted should not be in regular " |
- << "conflict"; |
- EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "The updates that can't be decrypted should be in encryption " |
- << "conflict"; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The undecryptable password update shouldn't be applied"; |
- } |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, NigoriUpdate) { |
- // Storing the cryptographer separately is bad, but for this test we |
- // know it's safe. |
- Cryptographer* cryptographer; |
- syncable::ModelTypeSet encrypted_types; |
- encrypted_types.Put(syncable::PASSWORDS); |
- encrypted_types.Put(syncable::NIGORI); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- cryptographer = directory()->GetCryptographer(&trans); |
- EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
- } |
- |
- // Nigori node updates should update the Cryptographer. |
- Cryptographer other_cryptographer(&encryptor_); |
- KeyParams params = {"localhost", "dummy", "foobar"}; |
- other_cryptographer.AddKey(params); |
- |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
- other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
- nigori->set_encrypt_bookmarks(true); |
- encrypted_types.Put(syncable::BOOKMARKS); |
- CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), |
- specifics, true); |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The nigori update shouldn't be in conflict"; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The nigori update should be applied"; |
- |
- EXPECT_FALSE(cryptographer->is_ready()); |
- EXPECT_TRUE(cryptographer->has_pending_keys()); |
- EXPECT_TRUE( |
- cryptographer->GetEncryptedTypes() |
- .Equals(syncable::ModelTypeSet::All())); |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, NigoriUpdateForDisabledTypes) { |
- // Storing the cryptographer separately is bad, but for this test we |
- // know it's safe. |
- Cryptographer* cryptographer; |
- syncable::ModelTypeSet encrypted_types; |
- encrypted_types.Put(syncable::PASSWORDS); |
- encrypted_types.Put(syncable::NIGORI); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- cryptographer = directory()->GetCryptographer(&trans); |
- EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
- } |
- |
- // Nigori node updates should update the Cryptographer. |
- Cryptographer other_cryptographer(&encryptor_); |
- KeyParams params = {"localhost", "dummy", "foobar"}; |
- other_cryptographer.AddKey(params); |
- |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
- other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
- nigori->set_encrypt_sessions(true); |
- nigori->set_encrypt_themes(true); |
- encrypted_types.Put(syncable::SESSIONS); |
- encrypted_types.Put(syncable::THEMES); |
- CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), |
- specifics, true); |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The nigori update shouldn't be in conflict"; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The nigori update should be applied"; |
- |
- EXPECT_FALSE(cryptographer->is_ready()); |
- EXPECT_TRUE(cryptographer->has_pending_keys()); |
- EXPECT_TRUE( |
- cryptographer->GetEncryptedTypes() |
- .Equals(syncable::ModelTypeSet::All())); |
-} |
- |
-// Create some local unsynced and unencrypted data. Apply a nigori update that |
-// turns on encryption for the unsynced data. Ensure we properly encrypt the |
-// data as part of the nigori update. Apply another nigori update with no |
-// changes. Ensure we ignore already-encrypted unsynced data and that nothing |
-// breaks. |
-TEST_F(ApplyUpdatesCommandTest, EncryptUnsyncedChanges) { |
- // Storing the cryptographer separately is bad, but for this test we |
- // know it's safe. |
- Cryptographer* cryptographer; |
- syncable::ModelTypeSet encrypted_types; |
- encrypted_types.Put(syncable::PASSWORDS); |
- encrypted_types.Put(syncable::NIGORI); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- cryptographer = directory()->GetCryptographer(&trans); |
- EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
- |
- // With default encrypted_types, this should be true. |
- EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_TRUE(handles.empty()); |
- } |
- |
- // Create unsynced bookmarks without encryption. |
- // First item is a folder |
- Id folder_id = id_factory_.NewLocalId(); |
- CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", |
- true, syncable::BOOKMARKS, NULL); |
- // Next five items are children of the folder |
- size_t i; |
- size_t batch_s = 5; |
- for (i = 0; i < batch_s; ++i) { |
- CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, |
- base::StringPrintf("Item %"PRIuS"", i), false, |
- syncable::BOOKMARKS, NULL); |
- } |
- // Next five items are children of the root. |
- for (; i < 2*batch_s; ++i) { |
- CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(), |
- base::StringPrintf("Item %"PRIuS"", i), false, |
- syncable::BOOKMARKS, NULL); |
- } |
- |
- KeyParams params = {"localhost", "dummy", "foobar"}; |
- cryptographer->AddKey(params); |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
- cryptographer->GetKeys(nigori->mutable_encrypted()); |
- nigori->set_encrypt_bookmarks(true); |
- encrypted_types.Put(syncable::BOOKMARKS); |
- CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), |
- specifics, true); |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- EXPECT_TRUE(cryptographer->is_ready()); |
- |
- { |
- // Ensure we have unsynced nodes that aren't properly encrypted. |
- ReadTransaction trans(FROM_HERE, directory()); |
- EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_EQ(2*batch_s+1, handles.size()); |
- } |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- { |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "No updates should be in conflict"; |
- EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "No updates should be in conflict"; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The nigori update should be applied"; |
- } |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- EXPECT_TRUE(cryptographer->is_ready()); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- |
- // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes |
- // should be encrypted now. |
- EXPECT_TRUE(syncable::ModelTypeSet::All().Equals( |
- cryptographer->GetEncryptedTypes())); |
- EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_EQ(2*batch_s+1, handles.size()); |
- } |
- |
- // Simulate another nigori update that doesn't change anything. |
- { |
- WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
- MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG, |
- syncable::ModelTypeToRootTag(syncable::NIGORI)); |
- ASSERT_TRUE(entry.good()); |
- entry.Put(syncable::SERVER_VERSION, GetNextRevision()); |
- entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
- } |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
- apply_updates_command_.ExecuteImpl(session()); |
- { |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "No updates should be in conflict"; |
- EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "No updates should be in conflict"; |
- EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The nigori update should be applied"; |
- } |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- EXPECT_TRUE(cryptographer->is_ready()); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- |
- // All our changes should still be encrypted. |
- EXPECT_TRUE(syncable::ModelTypeSet::All().Equals( |
- cryptographer->GetEncryptedTypes())); |
- EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_EQ(2*batch_s+1, handles.size()); |
- } |
-} |
- |
-TEST_F(ApplyUpdatesCommandTest, CannotEncryptUnsyncedChanges) { |
- // Storing the cryptographer separately is bad, but for this test we |
- // know it's safe. |
- Cryptographer* cryptographer; |
- syncable::ModelTypeSet encrypted_types; |
- encrypted_types.Put(syncable::PASSWORDS); |
- encrypted_types.Put(syncable::NIGORI); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- cryptographer = directory()->GetCryptographer(&trans); |
- EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
- |
- // With default encrypted_types, this should be true. |
- EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_TRUE(handles.empty()); |
- } |
- |
- // Create unsynced bookmarks without encryption. |
- // First item is a folder |
- Id folder_id = id_factory_.NewLocalId(); |
- CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", true, |
- syncable::BOOKMARKS, NULL); |
- // Next five items are children of the folder |
- size_t i; |
- size_t batch_s = 5; |
- for (i = 0; i < batch_s; ++i) { |
- CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, |
- base::StringPrintf("Item %"PRIuS"", i), false, |
- syncable::BOOKMARKS, NULL); |
- } |
- // Next five items are children of the root. |
- for (; i < 2*batch_s; ++i) { |
- CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(), |
- base::StringPrintf("Item %"PRIuS"", i), false, |
- syncable::BOOKMARKS, NULL); |
- } |
- |
- // We encrypt with new keys, triggering the local cryptographer to be unready |
- // and unable to decrypt data (once updated). |
- Cryptographer other_cryptographer(&encryptor_); |
- KeyParams params = {"localhost", "dummy", "foobar"}; |
- other_cryptographer.AddKey(params); |
- sync_pb::EntitySpecifics specifics; |
- sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
- other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
- nigori->set_encrypt_bookmarks(true); |
- encrypted_types.Put(syncable::BOOKMARKS); |
- CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), |
- specifics, true); |
- EXPECT_FALSE(cryptographer->has_pending_keys()); |
- |
- { |
- // Ensure we have unsynced nodes that aren't properly encrypted. |
- ReadTransaction trans(FROM_HERE, directory()); |
- EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_EQ(2*batch_s+1, handles.size()); |
- } |
- |
- ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
- apply_updates_command_.ExecuteImpl(session()); |
- |
- sessions::StatusController* status = session()->mutable_status_controller(); |
- sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
- ASSERT_TRUE(status->update_progress()); |
- EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
- << "All updates should have been attempted"; |
- ASSERT_TRUE(status->conflict_progress()); |
- EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
- << "The unsynced changes don't trigger a blocking conflict with the " |
- << "nigori update."; |
- EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) |
- << "The unsynced changes don't trigger an encryption conflict with the " |
- << "nigori update."; |
- EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
- << "The nigori update should be applied"; |
- EXPECT_FALSE(cryptographer->is_ready()); |
- EXPECT_TRUE(cryptographer->has_pending_keys()); |
- { |
- ReadTransaction trans(FROM_HERE, directory()); |
- |
- // Since we have pending keys, we would have failed to encrypt, but the |
- // cryptographer should be updated. |
- EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
- EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals( |
- syncable::ModelTypeSet().All())); |
- EXPECT_FALSE(cryptographer->is_ready()); |
- EXPECT_TRUE(cryptographer->has_pending_keys()); |
- |
- Syncer::UnsyncedMetaHandles handles; |
- SyncerUtil::GetUnsyncedEntries(&trans, &handles); |
- EXPECT_EQ(2*batch_s+1, handles.size()); |
- } |
-} |
- |
-} // namespace browser_sync |