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