1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <string> 6dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/format_macros.h" 8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/string_util.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/apply_updates_command.h" 10dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/sync/engine/syncer.h" 11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/sync/engine/syncer_util.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/sessions/sync_session.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h" 15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/sync/syncable/nigori_util.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable_id.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/test/sync/engine/syncer_command_test.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/test/sync/engine/test_id_factory.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync { 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::SyncSession; 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::string; 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Entry; 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenusing syncable::GetEncryptedDataTypes; 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Id; 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::MutableEntry; 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::ReadTransaction; 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::ScopedDirLookup; 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::UNITTEST; 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::WriteTransaction; 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A test fixture for tests exercising ApplyUpdatesCommand. 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ApplyUpdatesCommandTest : public SyncerCommandTest { 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ApplyUpdatesCommandTest() : next_revision_(1) {} 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~ApplyUpdatesCommandTest() {} 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void SetUp() { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch workers()->clear(); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mutable_routing_info()->clear(); 45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // GROUP_PASSIVE worker. 46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch workers()->push_back(make_scoped_refptr(new ModelSafeWorker())); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*mutable_routing_info())[syncable::BOOKMARKS] = GROUP_PASSIVE; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*mutable_routing_info())[syncable::PASSWORDS] = GROUP_PASSIVE; 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (*mutable_routing_info())[syncable::NIGORI] = GROUP_PASSIVE; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SyncerCommandTest::SetUp(); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Create a new unapplied bookmark node with a parent. 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void CreateUnappliedNewItemWithParent(const string& item_id, 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string& parent_id) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT_TRUE(dir.good()); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Id::CreateFromServerId(item_id)); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT_TRUE(entry.good()); 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_VERSION, next_revision_++); 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_PARENT_ID, Id::CreateFromServerId(parent_id)); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_IS_DIR, true); 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics default_bookmark_specifics; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_bookmark_specifics.MutableExtension(sync_pb::bookmark); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_SPECIFICS, default_bookmark_specifics); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Create a new unapplied update without a parent. 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void CreateUnappliedNewItem(const string& item_id, 75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const sync_pb::EntitySpecifics& specifics, 76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool is_unique) { 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT_TRUE(dir.good()); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Id::CreateFromServerId(item_id)); 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT_TRUE(entry.good()); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_VERSION, next_revision_++); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_PARENT_ID, syncable::kNullId); 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_IS_DIR, false); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.Put(syncable::SERVER_SPECIFICS, specifics); 89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (is_unique) // For top-level nodes. 90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::UNIQUE_SERVER_TAG, item_id); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Create an unsynced item in the database. If item_id is a local ID, it 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // will be treated as a create-new. Otherwise, if it's a server ID, we'll 95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // fake the server data so that it looks like it exists on the server. 96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Returns the methandle of the created item in |metahandle_out| if not NULL. 97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen void CreateUnsyncedItem(const Id& item_id, 98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const Id& parent_id, 99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const string& name, 100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool is_folder, 101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::ModelType model_type, 102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int64* metahandle_out) { 103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); 106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Id predecessor_id = dir->GetLastChildId(&trans, parent_id); 107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen MutableEntry entry(&trans, syncable::CREATE, parent_id, name); 108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(entry.good()); 109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::ID, item_id); 110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::BASE_VERSION, 111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen item_id.ServerKnows() ? next_revision_++ : 0); 112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::IS_UNSYNCED, true); 113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::IS_DIR, is_folder); 114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::IS_DEL, false); 115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::PARENT_ID, parent_id); 116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.PutPredecessor(predecessor_id); 117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::EntitySpecifics default_specifics; 118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::AddDefaultExtensionValue(model_type, &default_specifics); 119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::SPECIFICS, default_specifics); 120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (item_id.ServerKnows()) { 121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::SERVER_SPECIFICS, default_specifics); 122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::SERVER_IS_DIR, is_folder); 123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::SERVER_PARENT_ID, parent_id); 124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry.Put(syncable::SERVER_IS_DEL, false); 125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (metahandle_out) 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen *metahandle_out = entry.Get(syncable::META_HANDLE); 128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ApplyUpdatesCommand apply_updates_command_; 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen TestIdFactory id_factory_; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 next_revision_; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(ApplyUpdatesCommandTest); 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, Simple) { 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string root_server_id = syncable::kNullId.GetServerId(); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("parent", root_server_id); 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("child", "parent"); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->update_progress().AppliedUpdatesSize()) 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->conflict_progress().ConflictingItemsSize()) 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "Simple update shouldn't result in conflicts"; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->update_progress().SuccessfullyAppliedUpdateCount()) 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All items should have been successfully applied"; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, UpdateWithChildrenBeforeParents) { 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set a bunch of updates which are difficult to apply in the order 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // they're received due to dependencies on other unseen items. 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string root_server_id = syncable::kNullId.GetServerId(); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("a_child_created_first", "parent"); 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("x_child_created_first", "parent"); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("parent", root_server_id); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("a_child_created_second", "parent"); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("x_child_created_second", "parent"); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(5, status->update_progress().AppliedUpdatesSize()) 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->conflict_progress().ConflictingItemsSize()) 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "Simple update shouldn't result in conflicts, even if out-of-order"; 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(5, status->update_progress().SuccessfullyAppliedUpdateCount()) 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been successfully applied"; 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, NestedItemsWithUnknownParent) { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We shouldn't be able to do anything with either of these items. 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("some_item", "unknown_parent"); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("some_other_item", "some_item"); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->update_progress().AppliedUpdatesSize()) 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->conflict_progress().ConflictingItemsSize()) 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates with an unknown ancestors should be in conflict"; 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->update_progress().SuccessfullyAppliedUpdateCount()) 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "No item with an unknown ancestor should be applied"; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, ItemsBothKnownAndUnknown) { 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See what happens when there's a mixture of good and bad updates. 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch string root_server_id = syncable::kNullId.GetServerId(); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("first_unknown_item", "unknown_parent"); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("first_known_item", root_server_id); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("second_unknown_item", "unknown_parent"); 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("second_known_item", "first_known_item"); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("third_known_item", "fourth_known_item"); 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateUnappliedNewItemWithParent("fourth_known_item", root_server_id); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(6, status->update_progress().AppliedUpdatesSize()) 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->conflict_progress().ConflictingItemsSize()) 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The updates with unknown ancestors should be in conflict"; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(4, status->update_progress().SuccessfullyAppliedUpdateCount()) 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The updates with known ancestors should be successfully applied"; 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, DecryptablePassword) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Decryptable password updates should be applied. 218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Cryptographer* cryptographer; 219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen { 220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Storing the cryptographer separately is bad, but for this test we 221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // know it's safe. 222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(dir.good()); 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer = 226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen session()->context()->directory_manager()->GetCryptographer(&trans); 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_sync::KeyParams params = {"localhost", "dummy", "foobar"}; 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cryptographer->AddKey(params); 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics specifics; 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::PasswordSpecificsData data; 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data.set_origin("http://example.com"); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cryptographer->Encrypt(data, 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch specifics.MutableExtension(sync_pb::password)->mutable_encrypted()); 238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem("item", specifics, false); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().AppliedUpdatesSize()) 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->conflict_progress().ConflictingItemsSize()) 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "No update should be in conflict because they're all decryptable"; 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().SuccessfullyAppliedUpdateCount()) 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The updates that can be decrypted should be applied"; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, UndecryptablePassword) { 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Undecryptable password updates should not be applied. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics specifics; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch specifics.MutableExtension(sync_pb::password); 256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem("item", specifics, false); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().AppliedUpdatesSize()) 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->conflict_progress().ConflictingItemsSize()) 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The updates that can't be decrypted should be in conflict"; 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->update_progress().SuccessfullyAppliedUpdateCount()) 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "No update that can't be decrypted should be applied"; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, SomeUndecryptablePassword) { 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only decryptable password updates should be applied. 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics specifics; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::PasswordSpecificsData data; 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data.set_origin("http://example.com/1"); 276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen { 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT_TRUE(dir.good()); 279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Cryptographer* cryptographer = 281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen session()->context()->directory_manager()->GetCryptographer(&trans); 282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen KeyParams params = {"localhost", "dummy", "foobar"}; 284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer->AddKey(params); 285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer->Encrypt(data, 287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen specifics.MutableExtension(sync_pb::password)->mutable_encrypted()); 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 289dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem("item1", specifics, false); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a new cryptographer, independent of the one in the session. 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cryptographer cryptographer; 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KeyParams params = {"localhost", "dummy", "bazqux"}; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cryptographer.AddKey(params); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics specifics; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::PasswordSpecificsData data; 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data.set_origin("http://example.com/2"); 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cryptographer.Encrypt(data, 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch specifics.MutableExtension(sync_pb::password)->mutable_encrypted()); 303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem("item2", specifics, false); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(2, status->update_progress().AppliedUpdatesSize()) 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->conflict_progress().ConflictingItemsSize()) 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The decryptable password update should be applied"; 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().SuccessfullyAppliedUpdateCount()) 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The undecryptable password update shouldn't be applied"; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ApplyUpdatesCommandTest, NigoriUpdate) { 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Storing the cryptographer separately is bad, but for this test we 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // know it's safe. 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Cryptographer* cryptographer; 322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::ModelTypeSet encrypted_types; 323dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 324dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 325dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 326dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 327dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(encrypted_types, GetEncryptedDataTypes(&trans)); 328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer = 329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen session()->context()->directory_manager()->GetCryptographer(&trans); 330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 331dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Nigori node updates should update the Cryptographer. 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Cryptographer other_cryptographer; 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KeyParams params = {"localhost", "dummy", "foobar"}; 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch other_cryptographer.AddKey(params); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::EntitySpecifics specifics; 338dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::NigoriSpecifics* nigori = 339dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics.MutableExtension(sync_pb::nigori); 340dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen other_cryptographer.GetKeys(nigori->mutable_encrypted()); 341dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen nigori->set_encrypt_bookmarks(true); 342dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen encrypted_types.insert(syncable::BOOKMARKS); 343dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), 344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics, true); 345dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(cryptographer->has_pending_keys()); 346dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 347dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen apply_updates_command_.ExecuteImpl(session()); 348dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 349dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sessions::StatusController* status = session()->status_controller(); 350dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 351dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(1, status->update_progress().AppliedUpdatesSize()) 352dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "All updates should have been attempted"; 353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(0, status->conflict_progress().ConflictingItemsSize()) 354dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "The nigori update shouldn't be in conflict"; 355dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(1, status->update_progress().SuccessfullyAppliedUpdateCount()) 356dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "The nigori update should be applied"; 357dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(cryptographer->is_ready()); 359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(cryptographer->has_pending_keys()); 360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 362dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST_F(ApplyUpdatesCommandTest, EncryptUnsyncedChanges) { 363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Storing the cryptographer separately is bad, but for this test we 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // know it's safe. 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Cryptographer* cryptographer; 366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::ModelTypeSet encrypted_types; 367dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(encrypted_types, GetEncryptedDataTypes(&trans)); 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer = 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen session()->context()->directory_manager()->GetCryptographer(&trans); 374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // With empty encrypted_types, this should be true. 376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 378dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 380dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(handles.empty()); 381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Create unsynced bookmarks without encryption. 384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // First item is a folder 385dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Id folder_id = id_factory_.NewLocalId(); 386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", 387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen true, syncable::BOOKMARKS, NULL); 388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Next five items are children of the folder 389dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t i; 390dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t batch_s = 5; 391dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (i = 0; i < batch_s; ++i) { 392dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, 393dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen StringPrintf("Item %"PRIuS"", i), false, 394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::BOOKMARKS, NULL); 395dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 396dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Next five items are children of the root. 397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (; i < 2*batch_s; ++i) { 398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(), 399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen StringPrintf("Item %"PRIuS"", i), false, 400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::BOOKMARKS, NULL); 401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen KeyParams params = {"localhost", "dummy", "foobar"}; 404dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen cryptographer->AddKey(params); 405dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::EntitySpecifics specifics; 406dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::NigoriSpecifics* nigori = 407dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics.MutableExtension(sync_pb::nigori); 408dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen cryptographer->GetKeys(nigori->mutable_encrypted()); 409dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen nigori->set_encrypt_bookmarks(true); 410dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen encrypted_types.insert(syncable::BOOKMARKS); 411dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), 412dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics, true); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_FALSE(cryptographer->has_pending_keys()); 414dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(cryptographer->is_ready()); 415dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 417dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Ensure we have unsynced nodes that aren't properly encrypted. 418dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 419dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 420dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 421dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 422dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 423dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 424dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 425dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(2*batch_s+1, handles.size()); 426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch apply_updates_command_.ExecuteImpl(session()); 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::StatusController* status = session()->status_controller(); 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().AppliedUpdatesSize()) 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "All updates should have been attempted"; 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(0, status->conflict_progress().ConflictingItemsSize()) 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The nigori update shouldn't be in conflict"; 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(1, status->update_progress().SuccessfullyAppliedUpdateCount()) 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "The nigori update should be applied"; 438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(cryptographer->has_pending_keys()); 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(cryptographer->is_ready()); 440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes 446dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // should be encrypted now. 447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(encrypted_types, GetEncryptedDataTypes(&trans)); 448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 451dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 452dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(2*batch_s+1, handles.size()); 453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 456dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST_F(ApplyUpdatesCommandTest, CannotEncryptUnsyncedChanges) { 457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Storing the cryptographer separately is bad, but for this test we 458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // know it's safe. 459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Cryptographer* cryptographer; 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::ModelTypeSet encrypted_types; 461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(encrypted_types, GetEncryptedDataTypes(&trans)); 466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cryptographer = 467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen session()->context()->directory_manager()->GetCryptographer(&trans); 468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 469dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // With empty encrypted_types, this should be true. 470dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 474dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(handles.empty()); 475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 476dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Create unsynced bookmarks without encryption. 478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // First item is a folder 479dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Id folder_id = id_factory_.NewLocalId(); 480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", true, 481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::BOOKMARKS, NULL); 482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Next five items are children of the folder 483dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t i; 484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t batch_s = 5; 485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (i = 0; i < batch_s; ++i) { 486dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, 487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen StringPrintf("Item %"PRIuS"", i), false, 488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::BOOKMARKS, NULL); 489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Next five items are children of the root. 491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (; i < 2*batch_s; ++i) { 492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(), 493dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen StringPrintf("Item %"PRIuS"", i), false, 494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen syncable::BOOKMARKS, NULL); 495dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 496dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 497dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We encrypt with new keys, triggering the local cryptographer to be unready 498dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // and unable to decrypt data (once updated). 499dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Cryptographer other_cryptographer; 500dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen KeyParams params = {"localhost", "dummy", "foobar"}; 501dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen other_cryptographer.AddKey(params); 502dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::EntitySpecifics specifics; 503dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sync_pb::NigoriSpecifics* nigori = 504dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics.MutableExtension(sync_pb::nigori); 505dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen other_cryptographer.GetKeys(nigori->mutable_encrypted()); 506dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen nigori->set_encrypt_bookmarks(true); 507dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen encrypted_types.insert(syncable::BOOKMARKS); 508dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI), 509dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen specifics, true); 510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(cryptographer->has_pending_keys()); 511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 513dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Ensure we have unsynced nodes that aren't properly encrypted. 514dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 515dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 516dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 517dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 518dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 519dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 520dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(2*batch_s+1, handles.size()); 521dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 522dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 523dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen apply_updates_command_.ExecuteImpl(session()); 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 525dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sessions::StatusController* status = session()->status_controller(); 526dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); 527dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(1, status->update_progress().AppliedUpdatesSize()) 528dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "All updates should have been attempted"; 529dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(1, status->conflict_progress().ConflictingItemsSize()) 530dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "The unsynced chnages trigger a conflict with the nigori update."; 531dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(0, status->update_progress().SuccessfullyAppliedUpdateCount()) 532dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen << "The nigori update should not be applied"; 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_FALSE(cryptographer->is_ready()); 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_TRUE(cryptographer->has_pending_keys()); 535dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen { 536dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Ensure the unsynced nodes are still not encrypted. 537dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ScopedDirLookup dir(syncdb()->manager(), syncdb()->name()); 538dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ASSERT_TRUE(dir.good()); 539dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ReadTransaction trans(dir, __FILE__, __LINE__); 540dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 541dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Since we're in conflict, the specifics don't reflect the unapplied 542dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // changes. 543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); 544dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen encrypted_types.clear(); 545dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(encrypted_types, GetEncryptedDataTypes(&trans)); 546dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 547dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Syncer::UnsyncedMetaHandles handles; 548dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SyncerUtil::GetUnsyncedEntries(&trans, &handles); 549dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_EQ(2*batch_s+1, handles.size()); 550dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace browser_sync 554