12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/engine/apply_updates_and_resolve_conflicts_command.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/engine/syncer.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/test/test_entry_factory.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/bookmark_specifics.pb.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/password_specifics.pb.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/mutable_entry.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_id.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_read_transaction.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_util.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_write_transaction.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/test/engine/fake_model_worker.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/test/engine/syncer_command_test.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/test/engine/test_id_factory.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/test/fake_sync_encryption_handler.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/cryptographer.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::Id; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::MutableEntry; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::UNITTEST; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::WriteTransaction; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics result; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddDefaultFieldValue(BOOKMARKS, &result); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A test fixture for tests exercising ApplyUpdatesAndResolveConflictsCommand. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ApplyUpdatesAndResolveConflictsCommandTest : public SyncerCommandTest { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyUpdatesAndResolveConflictsCommandTest() {} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~ApplyUpdatesAndResolveConflictsCommandTest() {} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void SetUp() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) workers()->clear(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable_routing_info()->clear(); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) workers()->push_back( 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_scoped_refptr(new FakeModelWorker(GROUP_UI))); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) workers()->push_back( 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD))); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*mutable_routing_info())[BOOKMARKS] = GROUP_UI; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*mutable_routing_info())[PASSWORDS] = GROUP_PASSWORD; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*mutable_routing_info())[NIGORI] = GROUP_PASSIVE; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SyncerCommandTest::SetUp(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_.reset(new TestEntryFactory(directory())); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectNoGroupsToChange(apply_updates_command_); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ApplyUpdatesAndResolveConflictsCommandTest); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ApplyUpdatesAndResolveConflictsCommand apply_updates_command_; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<TestEntryFactory> entry_factory_; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, Simple) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string root_server_id = syncable::GetNullId().GetServerId(); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "parent", DefaultBookmarkSpecifics(), root_server_id); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "child", DefaultBookmarkSpecifics(), "parent"); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, status.num_encryption_conflicts()) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Simple update shouldn't result in conflicts"; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, status.num_hierarchy_conflicts()) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Simple update shouldn't result in conflicts"; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(2, status.num_updates_applied()) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "All items should have been successfully applied"; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateWithChildrenBeforeParents) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set a bunch of updates which are difficult to apply in the order 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they're received due to dependencies on other unseen items. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string root_server_id = syncable::GetNullId().GetServerId(); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "a_child_created_first", DefaultBookmarkSpecifics(), "parent"); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "x_child_created_first", DefaultBookmarkSpecifics(), "parent"); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "parent", DefaultBookmarkSpecifics(), root_server_id); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "a_child_created_second", DefaultBookmarkSpecifics(), "parent"); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedNewBookmarkItemWithParent( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "x_child_created_second", DefaultBookmarkSpecifics(), "parent"); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(5, status.num_updates_applied()) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "All updates should have been successfully applied"; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on an item that has both 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// local and remote modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expect the command to detect that this update can't be applied because it is 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in a CONFLICT state. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, SimpleConflict) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry_factory_->CreateUnappliedAndUnsyncedBookmarkItem("item"); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_server_overwrites()) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Unsynced and unapplied item conflict should be resolved"; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, status.num_updates_applied()) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Update should not be applied; we should override the server."; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on an item that has both 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// local and remote modifications *and* the remote modification cannot be 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// applied without violating the tree constraints. We expect the command to 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// detect that this update can't be applied and that this situation can't be 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resolved with the simple conflict processing logic; it is in a 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CONFLICT_HIERARCHY state. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, HierarchyAndSimpleConflict) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a simply-conflicting item. It will start with valid parent ids. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 handle = entry_factory_->CreateUnappliedAndUnsyncedBookmarkItem( 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "orphaned_by_server"); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manually set the SERVER_PARENT_ID to bad value. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A bad parent indicates a hierarchy conflict. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(entry.good()); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_PARENT_ID, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestIdFactory::MakeServer("bogus_parent")); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_hierarchy_conflicts()); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on an item with remote 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modifications that would create a directory loop if the update were applied. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We expect the command to detect that this update can't be applied because it 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is in a CONFLICT_HIERARCHY state. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HierarchyConflictDirectoryLoop) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Item 'X' locally has parent of 'root'. Server is updating it to have 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parent of 'Y'. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create it as a child of root node. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 handle = entry_factory_->CreateSyncedItem("X", BOOKMARKS, true); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(entry.good()); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Re-parent from root to "Y" 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_PARENT_ID, TestIdFactory::MakeServer("Y")); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Item 'Y' is child of 'X'. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnsyncedItem( 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestIdFactory::MakeServer("Y"), TestIdFactory::MakeServer("X"), "Y", true, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOKMARKS, NULL); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the server's update were applied, we would have X be a child of Y, and Y 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a child of X. That's a directory loop. The UpdateApplicator should 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // prevent the update from being applied and note that this is a hierarchy 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // conflict. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This should count as a hierarchy conflict. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_hierarchy_conflicts()); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on a directory where the 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// server sent us an update to add a child to a locally deleted (and unsynced) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parent. We expect the command to not apply the update and to indicate the 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// update is in a CONFLICT_HIERARCHY state. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HierarchyConflictDeletedParent) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a locally deleted parent item. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 parent_handle; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnsyncedItem( 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Id::CreateFromServerId("parent"), TestIdFactory::root(), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "parent", true, BOOKMARKS, &parent_handle); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::IS_DEL, true); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an incoming child from the server. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "child", DefaultBookmarkSpecifics(), "parent"); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The server's update may seem valid to some other client, but on this client 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that new item's parent no longer exists. The update should not be applied 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the update applicator should indicate this is a hierarchy conflict. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_hierarchy_conflicts()); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on a directory where the 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// server is trying to delete a folder that has a recently added (and unsynced) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// child. We expect the command to not apply the update because it is in a 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CONFLICT_HIERARCHY state. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HierarchyConflictDeleteNonEmptyDirectory) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a server-deleted directory. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create it as a child of root node. 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 handle = entry_factory_->CreateSyncedItem("parent", BOOKMARKS, true); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(entry.good()); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete it on the server. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_PARENT_ID, TestIdFactory::root()); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry.Put(syncable::SERVER_IS_DEL, true); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a local child of the server-deleted directory. 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnsyncedItem( 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestIdFactory::MakeServer("child"), TestIdFactory::MakeServer("parent"), 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "child", false, BOOKMARKS, NULL); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The server's request to delete the directory must be ignored, otherwise our 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unsynced new child would be orphaned. This is a hierarchy conflict. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This should count as a hierarchy conflict. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_hierarchy_conflicts()); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs the ApplyUpdatesAndResolveConflictsCommand on a server-created item that 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// has a locally unknown parent. We expect the command to not apply the update 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because the item is in a CONFLICT_HIERARCHY state. 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HierarchyConflictUnknownParent) { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We shouldn't be able to do anything with either of these items. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "some_item", DefaultBookmarkSpecifics(), "unknown_parent"); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "some_other_item", DefaultBookmarkSpecifics(), "some_item"); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(2, status.num_hierarchy_conflicts()) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "All updates with an unknown ancestors should be in conflict"; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, status.num_updates_applied()) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "No item with an unknown ancestor should be applied"; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, ItemsBothKnownAndUnknown) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See what happens when there's a mixture of good and bad updates. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string root_server_id = syncable::GetNullId().GetServerId(); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "first_unknown_item", DefaultBookmarkSpecifics(), "unknown_parent"); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "first_known_item", DefaultBookmarkSpecifics(), root_server_id); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "second_unknown_item", DefaultBookmarkSpecifics(), "unknown_parent"); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "second_known_item", DefaultBookmarkSpecifics(), "first_known_item"); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "third_known_item", DefaultBookmarkSpecifics(), "fourth_known_item"); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "fourth_known_item", DefaultBookmarkSpecifics(), root_server_id); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_UI); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(2, status.num_hierarchy_conflicts()) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "The updates with unknown ancestors should be in conflict"; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(4, status.num_updates_applied()) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "The updates with known ancestors should be successfully applied"; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, DecryptablePassword) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decryptable password updates should be applied. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cryptographer* cryptographer; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Storing the cryptographer separately is bad, but for this test we 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // know it's safe. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::ReadTransaction trans(FROM_HERE, directory()); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer = directory()->GetCryptographer(&trans); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeyParams params = {"localhost", "dummy", "foobar"}; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer->AddKey(params); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics specifics; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::PasswordSpecificsData data; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data.set_origin("http://example.com"); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer->Encrypt(data, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.mutable_password()->mutable_encrypted()); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItem("item", specifics, false); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_updates_applied()) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "The updates that can be decrypted should be applied"; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, UndecryptableData) { 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Undecryptable updates should not be applied. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics encrypted_bookmark; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted_bookmark.mutable_encrypted(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddDefaultFieldValue(BOOKMARKS, &encrypted_bookmark); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string root_server_id = syncable::GetNullId().GetServerId(); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItemWithParent( 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "folder", encrypted_bookmark, root_server_id); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItem("item2", encrypted_bookmark, false); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics encrypted_password; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encrypted_password.mutable_password(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItem("item3", encrypted_password, false); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(3, status.num_encryption_conflicts()) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Updates that can't be decrypted should be in encryption conflict"; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, status.num_updates_applied()) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "No update that can't be decrypted should be applied"; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ApplyUpdatesAndResolveConflictsCommandTest, SomeUndecryptablePassword) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cryptographer* cryptographer; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only decryptable password updates should be applied. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics specifics; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::PasswordSpecificsData data; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data.set_origin("http://example.com/1"); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncable::ReadTransaction trans(FROM_HERE, directory()); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer = directory()->GetCryptographer(&trans); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeyParams params = {"localhost", "dummy", "foobar"}; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer->AddKey(params); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cryptographer->Encrypt(data, 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.mutable_password()->mutable_encrypted()); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItem("item1", specifics, false); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new cryptographer, independent of the one in the session. 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Cryptographer other_cryptographer(cryptographer->encryptor()); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeyParams params = {"localhost", "dummy", "bazqux"}; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other_cryptographer.AddKey(params); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::EntitySpecifics specifics; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::PasswordSpecificsData data; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data.set_origin("http://example.com/2"); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other_cryptographer.Encrypt(data, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.mutable_password()->mutable_encrypted()); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry_factory_->CreateUnappliedNewItem("item2", specifics, false); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apply_updates_command_.ExecuteImpl(session()); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sessions::StatusController& status = session()->status_controller(); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_encryption_conflicts()) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "The updates that can't be decrypted should be in encryption " 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "conflict"; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, status.num_updates_applied()) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "The undecryptable password update shouldn't be applied"; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace syncer 417