| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <string> | 5 #include <string> |
| 6 | 6 |
| 7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
| 8 #include "base/location.h" | 8 #include "base/location.h" |
| 9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 using sessions::SyncSession; | 32 using sessions::SyncSession; |
| 33 using std::string; | 33 using std::string; |
| 34 using syncable::Id; | 34 using syncable::Id; |
| 35 using syncable::MutableEntry; | 35 using syncable::MutableEntry; |
| 36 using syncable::UNITTEST; | 36 using syncable::UNITTEST; |
| 37 using syncable::WriteTransaction; | 37 using syncable::WriteTransaction; |
| 38 | 38 |
| 39 namespace { | 39 namespace { |
| 40 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { | 40 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { |
| 41 sync_pb::EntitySpecifics result; | 41 sync_pb::EntitySpecifics result; |
| 42 AddDefaultFieldValue(syncer::BOOKMARKS, &result); | 42 AddDefaultFieldValue(BOOKMARKS, &result); |
| 43 return result; | 43 return result; |
| 44 } | 44 } |
| 45 } // namespace | 45 } // namespace |
| 46 | 46 |
| 47 // A test fixture for tests exercising ApplyUpdatesCommand. | 47 // A test fixture for tests exercising ApplyUpdatesCommand. |
| 48 class ApplyUpdatesCommandTest : public SyncerCommandTest { | 48 class ApplyUpdatesCommandTest : public SyncerCommandTest { |
| 49 public: | 49 public: |
| 50 protected: | 50 protected: |
| 51 ApplyUpdatesCommandTest() {} | 51 ApplyUpdatesCommandTest() {} |
| 52 virtual ~ApplyUpdatesCommandTest() {} | 52 virtual ~ApplyUpdatesCommandTest() {} |
| 53 | 53 |
| 54 virtual void SetUp() { | 54 virtual void SetUp() { |
| 55 workers()->clear(); | 55 workers()->clear(); |
| 56 mutable_routing_info()->clear(); | 56 mutable_routing_info()->clear(); |
| 57 workers()->push_back( | 57 workers()->push_back( |
| 58 make_scoped_refptr(new FakeModelWorker(GROUP_UI))); | 58 make_scoped_refptr(new FakeModelWorker(GROUP_UI))); |
| 59 workers()->push_back( | 59 workers()->push_back( |
| 60 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD))); | 60 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD))); |
| 61 (*mutable_routing_info())[syncer::BOOKMARKS] = GROUP_UI; | 61 (*mutable_routing_info())[BOOKMARKS] = GROUP_UI; |
| 62 (*mutable_routing_info())[syncer::PASSWORDS] = GROUP_PASSWORD; | 62 (*mutable_routing_info())[PASSWORDS] = GROUP_PASSWORD; |
| 63 (*mutable_routing_info())[syncer::NIGORI] = GROUP_PASSIVE; | 63 (*mutable_routing_info())[NIGORI] = GROUP_PASSIVE; |
| 64 SyncerCommandTest::SetUp(); | 64 SyncerCommandTest::SetUp(); |
| 65 entry_factory_.reset(new TestEntryFactory(directory())); | 65 entry_factory_.reset(new TestEntryFactory(directory())); |
| 66 ExpectNoGroupsToChange(apply_updates_command_); | 66 ExpectNoGroupsToChange(apply_updates_command_); |
| 67 } | 67 } |
| 68 | 68 |
| 69 ApplyUpdatesCommand apply_updates_command_; | 69 ApplyUpdatesCommand apply_updates_command_; |
| 70 FakeEncryptor encryptor_; | 70 FakeEncryptor encryptor_; |
| 71 TestIdFactory id_factory_; | 71 TestIdFactory id_factory_; |
| 72 scoped_ptr<TestEntryFactory> entry_factory_; | 72 scoped_ptr<TestEntryFactory> entry_factory_; |
| 73 private: | 73 private: |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 << "Simple update shouldn't result in conflicts, even if out-of-order"; | 131 << "Simple update shouldn't result in conflicts, even if out-of-order"; |
| 132 EXPECT_EQ(5, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 132 EXPECT_EQ(5, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 133 << "All updates should have been successfully applied"; | 133 << "All updates should have been successfully applied"; |
| 134 } | 134 } |
| 135 | 135 |
| 136 // Runs the ApplyUpdatesCommand on an item that has both local and remote | 136 // Runs the ApplyUpdatesCommand on an item that has both local and remote |
| 137 // modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We expect the command | 137 // modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We expect the command |
| 138 // to detect that this update can't be applied because it is in a CONFLICT | 138 // to detect that this update can't be applied because it is in a CONFLICT |
| 139 // state. | 139 // state. |
| 140 TEST_F(ApplyUpdatesCommandTest, SimpleConflict) { | 140 TEST_F(ApplyUpdatesCommandTest, SimpleConflict) { |
| 141 entry_factory_->CreateUnappliedAndUnsyncedItem("item", syncer::BOOKMARKS); | 141 entry_factory_->CreateUnappliedAndUnsyncedItem("item", BOOKMARKS); |
| 142 | 142 |
| 143 ExpectGroupToChange(apply_updates_command_, GROUP_UI); | 143 ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
| 144 apply_updates_command_.ExecuteImpl(session()); | 144 apply_updates_command_.ExecuteImpl(session()); |
| 145 | 145 |
| 146 sessions::StatusController* status = session()->mutable_status_controller(); | 146 sessions::StatusController* status = session()->mutable_status_controller(); |
| 147 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); | 147 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
| 148 ASSERT_TRUE(status->conflict_progress()); | 148 ASSERT_TRUE(status->conflict_progress()); |
| 149 EXPECT_EQ(1, status->conflict_progress()->SimpleConflictingItemsSize()) | 149 EXPECT_EQ(1, status->conflict_progress()->SimpleConflictingItemsSize()) |
| 150 << "Unsynced and unapplied item should be a simple conflict"; | 150 << "Unsynced and unapplied item should be a simple conflict"; |
| 151 } | 151 } |
| 152 | 152 |
| 153 // Runs the ApplyUpdatesCommand on an item that has both local and remote | 153 // Runs the ApplyUpdatesCommand on an item that has both local and remote |
| 154 // modifications *and* the remote modification cannot be applied without | 154 // modifications *and* the remote modification cannot be applied without |
| 155 // violating the tree constraints. We expect the command to detect that this | 155 // violating the tree constraints. We expect the command to detect that this |
| 156 // update can't be applied and that this situation can't be resolved with the | 156 // update can't be applied and that this situation can't be resolved with the |
| 157 // simple conflict processing logic; it is in a CONFLICT_HIERARCHY state. | 157 // simple conflict processing logic; it is in a CONFLICT_HIERARCHY state. |
| 158 TEST_F(ApplyUpdatesCommandTest, HierarchyAndSimpleConflict) { | 158 TEST_F(ApplyUpdatesCommandTest, HierarchyAndSimpleConflict) { |
| 159 // Create a simply-conflicting item. It will start with valid parent ids. | 159 // Create a simply-conflicting item. It will start with valid parent ids. |
| 160 int64 handle = entry_factory_->CreateUnappliedAndUnsyncedItem( | 160 int64 handle = entry_factory_->CreateUnappliedAndUnsyncedItem( |
| 161 "orphaned_by_server", syncer::BOOKMARKS); | 161 "orphaned_by_server", BOOKMARKS); |
| 162 { | 162 { |
| 163 // Manually set the SERVER_PARENT_ID to bad value. | 163 // Manually set the SERVER_PARENT_ID to bad value. |
| 164 // A bad parent indicates a hierarchy conflict. | 164 // A bad parent indicates a hierarchy conflict. |
| 165 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); | 165 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
| 166 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); | 166 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
| 167 ASSERT_TRUE(entry.good()); | 167 ASSERT_TRUE(entry.good()); |
| 168 | 168 |
| 169 entry.Put(syncable::SERVER_PARENT_ID, | 169 entry.Put(syncable::SERVER_PARENT_ID, |
| 170 id_factory_.MakeServer("bogus_parent")); | 170 id_factory_.MakeServer("bogus_parent")); |
| 171 } | 171 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 188 | 188 |
| 189 // Runs the ApplyUpdatesCommand on an item with remote modifications that would | 189 // Runs the ApplyUpdatesCommand on an item with remote modifications that would |
| 190 // create a directory loop if the update were applied. We expect the command to | 190 // create a directory loop if the update were applied. We expect the command to |
| 191 // detect that this update can't be applied because it is in a | 191 // detect that this update can't be applied because it is in a |
| 192 // CONFLICT_HIERARCHY state. | 192 // CONFLICT_HIERARCHY state. |
| 193 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDirectoryLoop) { | 193 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDirectoryLoop) { |
| 194 // Item 'X' locally has parent of 'root'. Server is updating it to have | 194 // Item 'X' locally has parent of 'root'. Server is updating it to have |
| 195 // parent of 'Y'. | 195 // parent of 'Y'. |
| 196 { | 196 { |
| 197 // Create it as a child of root node. | 197 // Create it as a child of root node. |
| 198 int64 handle = entry_factory_->CreateSyncedItem( | 198 int64 handle = entry_factory_->CreateSyncedItem("X", BOOKMARKS, true); |
| 199 "X", syncer::BOOKMARKS, true); | |
| 200 | 199 |
| 201 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); | 200 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
| 202 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); | 201 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
| 203 ASSERT_TRUE(entry.good()); | 202 ASSERT_TRUE(entry.good()); |
| 204 | 203 |
| 205 // Re-parent from root to "Y" | 204 // Re-parent from root to "Y" |
| 206 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); | 205 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); |
| 207 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); | 206 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
| 208 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y")); | 207 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y")); |
| 209 } | 208 } |
| 210 | 209 |
| 211 // Item 'Y' is child of 'X'. | 210 // Item 'Y' is child of 'X'. |
| 212 entry_factory_->CreateUnsyncedItem( | 211 entry_factory_->CreateUnsyncedItem( |
| 213 id_factory_.MakeServer("Y"), id_factory_.MakeServer("X"), "Y", true, | 212 id_factory_.MakeServer("Y"), id_factory_.MakeServer("X"), "Y", true, |
| 214 syncer::BOOKMARKS, NULL); | 213 BOOKMARKS, NULL); |
| 215 | 214 |
| 216 // If the server's update were applied, we would have X be a child of Y, and Y | 215 // If the server's update were applied, we would have X be a child of Y, and Y |
| 217 // as a child of X. That's a directory loop. The UpdateApplicator should | 216 // as a child of X. That's a directory loop. The UpdateApplicator should |
| 218 // prevent the update from being applied and note that this is a hierarchy | 217 // prevent the update from being applied and note that this is a hierarchy |
| 219 // conflict. | 218 // conflict. |
| 220 | 219 |
| 221 ExpectGroupToChange(apply_updates_command_, GROUP_UI); | 220 ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
| 222 apply_updates_command_.ExecuteImpl(session()); | 221 apply_updates_command_.ExecuteImpl(session()); |
| 223 | 222 |
| 224 sessions::StatusController* status = session()->mutable_status_controller(); | 223 sessions::StatusController* status = session()->mutable_status_controller(); |
| 225 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); | 224 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
| 226 | 225 |
| 227 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); | 226 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); |
| 228 | 227 |
| 229 // This should count as a hierarchy conflict. | 228 // This should count as a hierarchy conflict. |
| 230 ASSERT_TRUE(status->conflict_progress()); | 229 ASSERT_TRUE(status->conflict_progress()); |
| 231 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); | 230 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); |
| 232 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); | 231 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); |
| 233 } | 232 } |
| 234 | 233 |
| 235 // Runs the ApplyUpdatesCommand on a directory where the server sent us an | 234 // Runs the ApplyUpdatesCommand on a directory where the server sent us an |
| 236 // update to add a child to a locally deleted (and unsynced) parent. We expect | 235 // update to add a child to a locally deleted (and unsynced) parent. We expect |
| 237 // the command to not apply the update and to indicate the update is in a | 236 // the command to not apply the update and to indicate the update is in a |
| 238 // CONFLICT_HIERARCHY state. | 237 // CONFLICT_HIERARCHY state. |
| 239 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeletedParent) { | 238 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeletedParent) { |
| 240 // Create a locally deleted parent item. | 239 // Create a locally deleted parent item. |
| 241 int64 parent_handle; | 240 int64 parent_handle; |
| 242 entry_factory_->CreateUnsyncedItem( | 241 entry_factory_->CreateUnsyncedItem( |
| 243 Id::CreateFromServerId("parent"), id_factory_.root(), | 242 Id::CreateFromServerId("parent"), id_factory_.root(), |
| 244 "parent", true, syncer::BOOKMARKS, &parent_handle); | 243 "parent", true, BOOKMARKS, &parent_handle); |
| 245 { | 244 { |
| 246 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); | 245 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
| 247 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle); | 246 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle); |
| 248 entry.Put(syncable::IS_DEL, true); | 247 entry.Put(syncable::IS_DEL, true); |
| 249 } | 248 } |
| 250 | 249 |
| 251 // Create an incoming child from the server. | 250 // Create an incoming child from the server. |
| 252 entry_factory_->CreateUnappliedNewItemWithParent( | 251 entry_factory_->CreateUnappliedNewItemWithParent( |
| 253 "child", DefaultBookmarkSpecifics(), "parent"); | 252 "child", DefaultBookmarkSpecifics(), "parent"); |
| 254 | 253 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 269 } | 268 } |
| 270 | 269 |
| 271 // Runs the ApplyUpdatesCommand on a directory where the server is trying to | 270 // Runs the ApplyUpdatesCommand on a directory where the server is trying to |
| 272 // delete a folder that has a recently added (and unsynced) child. We expect | 271 // delete a folder that has a recently added (and unsynced) child. We expect |
| 273 // the command to not apply the update because it is in a CONFLICT_HIERARCHY | 272 // the command to not apply the update because it is in a CONFLICT_HIERARCHY |
| 274 // state. | 273 // state. |
| 275 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeleteNonEmptyDirectory) { | 274 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeleteNonEmptyDirectory) { |
| 276 // Create a server-deleted directory. | 275 // Create a server-deleted directory. |
| 277 { | 276 { |
| 278 // Create it as a child of root node. | 277 // Create it as a child of root node. |
| 279 int64 handle = entry_factory_->CreateSyncedItem( | 278 int64 handle = |
| 280 "parent", syncer::BOOKMARKS, true); | 279 entry_factory_->CreateSyncedItem("parent", BOOKMARKS, true); |
| 281 | 280 |
| 282 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); | 281 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
| 283 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); | 282 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); |
| 284 ASSERT_TRUE(entry.good()); | 283 ASSERT_TRUE(entry.good()); |
| 285 | 284 |
| 286 // Delete it on the server. | 285 // Delete it on the server. |
| 287 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); | 286 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); |
| 288 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); | 287 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
| 289 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.root()); | 288 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.root()); |
| 290 entry.Put(syncable::SERVER_IS_DEL, true); | 289 entry.Put(syncable::SERVER_IS_DEL, true); |
| 291 } | 290 } |
| 292 | 291 |
| 293 // Create a local child of the server-deleted directory. | 292 // Create a local child of the server-deleted directory. |
| 294 entry_factory_->CreateUnsyncedItem( | 293 entry_factory_->CreateUnsyncedItem( |
| 295 id_factory_.MakeServer("child"), id_factory_.MakeServer("parent"), | 294 id_factory_.MakeServer("child"), id_factory_.MakeServer("parent"), |
| 296 "child", false, syncer::BOOKMARKS, NULL); | 295 "child", false, BOOKMARKS, NULL); |
| 297 | 296 |
| 298 // The server's request to delete the directory must be ignored, otherwise our | 297 // The server's request to delete the directory must be ignored, otherwise our |
| 299 // unsynced new child would be orphaned. This is a hierarchy conflict. | 298 // unsynced new child would be orphaned. This is a hierarchy conflict. |
| 300 | 299 |
| 301 ExpectGroupToChange(apply_updates_command_, GROUP_UI); | 300 ExpectGroupToChange(apply_updates_command_, GROUP_UI); |
| 302 apply_updates_command_.ExecuteImpl(session()); | 301 apply_updates_command_.ExecuteImpl(session()); |
| 303 | 302 |
| 304 sessions::StatusController* status = session()->mutable_status_controller(); | 303 sessions::StatusController* status = session()->mutable_status_controller(); |
| 305 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); | 304 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); |
| 306 | 305 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 TEST_F(ApplyUpdatesCommandTest, DecryptablePassword) { | 371 TEST_F(ApplyUpdatesCommandTest, DecryptablePassword) { |
| 373 // Decryptable password updates should be applied. | 372 // Decryptable password updates should be applied. |
| 374 Cryptographer* cryptographer; | 373 Cryptographer* cryptographer; |
| 375 { | 374 { |
| 376 // Storing the cryptographer separately is bad, but for this test we | 375 // Storing the cryptographer separately is bad, but for this test we |
| 377 // know it's safe. | 376 // know it's safe. |
| 378 syncable::ReadTransaction trans(FROM_HERE, directory()); | 377 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 379 cryptographer = directory()->GetCryptographer(&trans); | 378 cryptographer = directory()->GetCryptographer(&trans); |
| 380 } | 379 } |
| 381 | 380 |
| 382 syncer::KeyParams params = {"localhost", "dummy", "foobar"}; | 381 KeyParams params = {"localhost", "dummy", "foobar"}; |
| 383 cryptographer->AddKey(params); | 382 cryptographer->AddKey(params); |
| 384 | 383 |
| 385 sync_pb::EntitySpecifics specifics; | 384 sync_pb::EntitySpecifics specifics; |
| 386 sync_pb::PasswordSpecificsData data; | 385 sync_pb::PasswordSpecificsData data; |
| 387 data.set_origin("http://example.com"); | 386 data.set_origin("http://example.com"); |
| 388 | 387 |
| 389 cryptographer->Encrypt(data, | 388 cryptographer->Encrypt(data, |
| 390 specifics.mutable_password()->mutable_encrypted()); | 389 specifics.mutable_password()->mutable_encrypted()); |
| 391 entry_factory_->CreateUnappliedNewItem("item", specifics, false); | 390 entry_factory_->CreateUnappliedNewItem("item", specifics, false); |
| 392 | 391 |
| 393 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); | 392 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); |
| 394 apply_updates_command_.ExecuteImpl(session()); | 393 apply_updates_command_.ExecuteImpl(session()); |
| 395 | 394 |
| 396 sessions::StatusController* status = session()->mutable_status_controller(); | 395 sessions::StatusController* status = session()->mutable_status_controller(); |
| 397 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); | 396 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); |
| 398 ASSERT_TRUE(status->update_progress()); | 397 ASSERT_TRUE(status->update_progress()); |
| 399 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) | 398 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
| 400 << "All updates should have been attempted"; | 399 << "All updates should have been attempted"; |
| 401 ASSERT_TRUE(status->conflict_progress()); | 400 ASSERT_TRUE(status->conflict_progress()); |
| 402 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) | 401 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
| 403 << "No update should be in conflict because they're all decryptable"; | 402 << "No update should be in conflict because they're all decryptable"; |
| 404 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 403 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 405 << "The updates that can be decrypted should be applied"; | 404 << "The updates that can be decrypted should be applied"; |
| 406 } | 405 } |
| 407 | 406 |
| 408 TEST_F(ApplyUpdatesCommandTest, UndecryptableData) { | 407 TEST_F(ApplyUpdatesCommandTest, UndecryptableData) { |
| 409 // Undecryptable updates should not be applied. | 408 // Undecryptable updates should not be applied. |
| 410 sync_pb::EntitySpecifics encrypted_bookmark; | 409 sync_pb::EntitySpecifics encrypted_bookmark; |
| 411 encrypted_bookmark.mutable_encrypted(); | 410 encrypted_bookmark.mutable_encrypted(); |
| 412 AddDefaultFieldValue(syncer::BOOKMARKS, &encrypted_bookmark); | 411 AddDefaultFieldValue(BOOKMARKS, &encrypted_bookmark); |
| 413 string root_server_id = syncable::GetNullId().GetServerId(); | 412 string root_server_id = syncable::GetNullId().GetServerId(); |
| 414 entry_factory_->CreateUnappliedNewItemWithParent( | 413 entry_factory_->CreateUnappliedNewItemWithParent( |
| 415 "folder", encrypted_bookmark, root_server_id); | 414 "folder", encrypted_bookmark, root_server_id); |
| 416 entry_factory_->CreateUnappliedNewItem("item2", encrypted_bookmark, false); | 415 entry_factory_->CreateUnappliedNewItem("item2", encrypted_bookmark, false); |
| 417 sync_pb::EntitySpecifics encrypted_password; | 416 sync_pb::EntitySpecifics encrypted_password; |
| 418 encrypted_password.mutable_password(); | 417 encrypted_password.mutable_password(); |
| 419 entry_factory_->CreateUnappliedNewItem("item3", encrypted_password, false); | 418 entry_factory_->CreateUnappliedNewItem("item3", encrypted_password, false); |
| 420 | 419 |
| 421 ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD); | 420 ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD); |
| 422 apply_updates_command_.ExecuteImpl(session()); | 421 apply_updates_command_.ExecuteImpl(session()); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 << "conflict"; | 510 << "conflict"; |
| 512 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 511 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 513 << "The undecryptable password update shouldn't be applied"; | 512 << "The undecryptable password update shouldn't be applied"; |
| 514 } | 513 } |
| 515 } | 514 } |
| 516 | 515 |
| 517 TEST_F(ApplyUpdatesCommandTest, NigoriUpdate) { | 516 TEST_F(ApplyUpdatesCommandTest, NigoriUpdate) { |
| 518 // Storing the cryptographer separately is bad, but for this test we | 517 // Storing the cryptographer separately is bad, but for this test we |
| 519 // know it's safe. | 518 // know it's safe. |
| 520 Cryptographer* cryptographer; | 519 Cryptographer* cryptographer; |
| 521 syncer::ModelTypeSet encrypted_types; | 520 ModelTypeSet encrypted_types; |
| 522 encrypted_types.Put(syncer::PASSWORDS); | 521 encrypted_types.Put(PASSWORDS); |
| 523 encrypted_types.Put(syncer::NIGORI); | 522 encrypted_types.Put(NIGORI); |
| 524 { | 523 { |
| 525 syncable::ReadTransaction trans(FROM_HERE, directory()); | 524 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 526 cryptographer = directory()->GetCryptographer(&trans); | 525 cryptographer = directory()->GetCryptographer(&trans); |
| 527 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); | 526 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
| 528 } | 527 } |
| 529 | 528 |
| 530 // Nigori node updates should update the Cryptographer. | 529 // Nigori node updates should update the Cryptographer. |
| 531 Cryptographer other_cryptographer(&encryptor_); | 530 Cryptographer other_cryptographer(&encryptor_); |
| 532 KeyParams params = {"localhost", "dummy", "foobar"}; | 531 KeyParams params = {"localhost", "dummy", "foobar"}; |
| 533 other_cryptographer.AddKey(params); | 532 other_cryptographer.AddKey(params); |
| 534 | 533 |
| 535 sync_pb::EntitySpecifics specifics; | 534 sync_pb::EntitySpecifics specifics; |
| 536 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); | 535 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
| 537 other_cryptographer.GetKeys(nigori->mutable_encrypted()); | 536 other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
| 538 nigori->set_encrypt_bookmarks(true); | 537 nigori->set_encrypt_bookmarks(true); |
| 539 encrypted_types.Put(syncer::BOOKMARKS); | 538 encrypted_types.Put(BOOKMARKS); |
| 540 entry_factory_->CreateUnappliedNewItem( | 539 entry_factory_->CreateUnappliedNewItem( |
| 541 syncer::ModelTypeToRootTag(syncer::NIGORI), specifics, true); | 540 ModelTypeToRootTag(NIGORI), specifics, true); |
| 542 EXPECT_FALSE(cryptographer->has_pending_keys()); | 541 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 543 | 542 |
| 544 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); | 543 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
| 545 apply_updates_command_.ExecuteImpl(session()); | 544 apply_updates_command_.ExecuteImpl(session()); |
| 546 | 545 |
| 547 sessions::StatusController* status = session()->mutable_status_controller(); | 546 sessions::StatusController* status = session()->mutable_status_controller(); |
| 548 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); | 547 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
| 549 ASSERT_TRUE(status->update_progress()); | 548 ASSERT_TRUE(status->update_progress()); |
| 550 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) | 549 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
| 551 << "All updates should have been attempted"; | 550 << "All updates should have been attempted"; |
| 552 ASSERT_TRUE(status->conflict_progress()); | 551 ASSERT_TRUE(status->conflict_progress()); |
| 553 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) | 552 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
| 554 << "The nigori update shouldn't be in conflict"; | 553 << "The nigori update shouldn't be in conflict"; |
| 555 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 554 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 556 << "The nigori update should be applied"; | 555 << "The nigori update should be applied"; |
| 557 | 556 |
| 558 EXPECT_FALSE(cryptographer->is_ready()); | 557 EXPECT_FALSE(cryptographer->is_ready()); |
| 559 EXPECT_TRUE(cryptographer->has_pending_keys()); | 558 EXPECT_TRUE(cryptographer->has_pending_keys()); |
| 560 EXPECT_TRUE( | 559 EXPECT_TRUE( |
| 561 cryptographer->GetEncryptedTypes().Equals(syncer::ModelTypeSet::All())); | 560 cryptographer->GetEncryptedTypes().Equals(ModelTypeSet::All())); |
| 562 } | 561 } |
| 563 | 562 |
| 564 TEST_F(ApplyUpdatesCommandTest, NigoriUpdateForDisabledTypes) { | 563 TEST_F(ApplyUpdatesCommandTest, NigoriUpdateForDisabledTypes) { |
| 565 // Storing the cryptographer separately is bad, but for this test we | 564 // Storing the cryptographer separately is bad, but for this test we |
| 566 // know it's safe. | 565 // know it's safe. |
| 567 Cryptographer* cryptographer; | 566 Cryptographer* cryptographer; |
| 568 syncer::ModelTypeSet encrypted_types; | 567 ModelTypeSet encrypted_types; |
| 569 encrypted_types.Put(syncer::PASSWORDS); | 568 encrypted_types.Put(PASSWORDS); |
| 570 encrypted_types.Put(syncer::NIGORI); | 569 encrypted_types.Put(NIGORI); |
| 571 { | 570 { |
| 572 syncable::ReadTransaction trans(FROM_HERE, directory()); | 571 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 573 cryptographer = directory()->GetCryptographer(&trans); | 572 cryptographer = directory()->GetCryptographer(&trans); |
| 574 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); | 573 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
| 575 } | 574 } |
| 576 | 575 |
| 577 // Nigori node updates should update the Cryptographer. | 576 // Nigori node updates should update the Cryptographer. |
| 578 Cryptographer other_cryptographer(&encryptor_); | 577 Cryptographer other_cryptographer(&encryptor_); |
| 579 KeyParams params = {"localhost", "dummy", "foobar"}; | 578 KeyParams params = {"localhost", "dummy", "foobar"}; |
| 580 other_cryptographer.AddKey(params); | 579 other_cryptographer.AddKey(params); |
| 581 | 580 |
| 582 sync_pb::EntitySpecifics specifics; | 581 sync_pb::EntitySpecifics specifics; |
| 583 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); | 582 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
| 584 other_cryptographer.GetKeys(nigori->mutable_encrypted()); | 583 other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
| 585 nigori->set_encrypt_sessions(true); | 584 nigori->set_encrypt_sessions(true); |
| 586 nigori->set_encrypt_themes(true); | 585 nigori->set_encrypt_themes(true); |
| 587 encrypted_types.Put(syncer::SESSIONS); | 586 encrypted_types.Put(SESSIONS); |
| 588 encrypted_types.Put(syncer::THEMES); | 587 encrypted_types.Put(THEMES); |
| 589 entry_factory_->CreateUnappliedNewItem( | 588 entry_factory_->CreateUnappliedNewItem( |
| 590 syncer::ModelTypeToRootTag(syncer::NIGORI), specifics, true); | 589 ModelTypeToRootTag(NIGORI), specifics, true); |
| 591 EXPECT_FALSE(cryptographer->has_pending_keys()); | 590 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 592 | 591 |
| 593 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); | 592 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
| 594 apply_updates_command_.ExecuteImpl(session()); | 593 apply_updates_command_.ExecuteImpl(session()); |
| 595 | 594 |
| 596 sessions::StatusController* status = session()->mutable_status_controller(); | 595 sessions::StatusController* status = session()->mutable_status_controller(); |
| 597 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); | 596 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
| 598 ASSERT_TRUE(status->update_progress()); | 597 ASSERT_TRUE(status->update_progress()); |
| 599 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) | 598 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) |
| 600 << "All updates should have been attempted"; | 599 << "All updates should have been attempted"; |
| 601 ASSERT_TRUE(status->conflict_progress()); | 600 ASSERT_TRUE(status->conflict_progress()); |
| 602 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) | 601 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
| 603 << "The nigori update shouldn't be in conflict"; | 602 << "The nigori update shouldn't be in conflict"; |
| 604 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 603 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 605 << "The nigori update should be applied"; | 604 << "The nigori update should be applied"; |
| 606 | 605 |
| 607 EXPECT_FALSE(cryptographer->is_ready()); | 606 EXPECT_FALSE(cryptographer->is_ready()); |
| 608 EXPECT_TRUE(cryptographer->has_pending_keys()); | 607 EXPECT_TRUE(cryptographer->has_pending_keys()); |
| 609 EXPECT_TRUE( | 608 EXPECT_TRUE( |
| 610 cryptographer->GetEncryptedTypes().Equals(syncer::ModelTypeSet::All())); | 609 cryptographer->GetEncryptedTypes().Equals(ModelTypeSet::All())); |
| 611 } | 610 } |
| 612 | 611 |
| 613 // Create some local unsynced and unencrypted data. Apply a nigori update that | 612 // Create some local unsynced and unencrypted data. Apply a nigori update that |
| 614 // turns on encryption for the unsynced data. Ensure we properly encrypt the | 613 // turns on encryption for the unsynced data. Ensure we properly encrypt the |
| 615 // data as part of the nigori update. Apply another nigori update with no | 614 // data as part of the nigori update. Apply another nigori update with no |
| 616 // changes. Ensure we ignore already-encrypted unsynced data and that nothing | 615 // changes. Ensure we ignore already-encrypted unsynced data and that nothing |
| 617 // breaks. | 616 // breaks. |
| 618 TEST_F(ApplyUpdatesCommandTest, EncryptUnsyncedChanges) { | 617 TEST_F(ApplyUpdatesCommandTest, EncryptUnsyncedChanges) { |
| 619 // Storing the cryptographer separately is bad, but for this test we | 618 // Storing the cryptographer separately is bad, but for this test we |
| 620 // know it's safe. | 619 // know it's safe. |
| 621 Cryptographer* cryptographer; | 620 Cryptographer* cryptographer; |
| 622 syncer::ModelTypeSet encrypted_types; | 621 ModelTypeSet encrypted_types; |
| 623 encrypted_types.Put(syncer::PASSWORDS); | 622 encrypted_types.Put(PASSWORDS); |
| 624 encrypted_types.Put(syncer::NIGORI); | 623 encrypted_types.Put(NIGORI); |
| 625 { | 624 { |
| 626 syncable::ReadTransaction trans(FROM_HERE, directory()); | 625 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 627 cryptographer = directory()->GetCryptographer(&trans); | 626 cryptographer = directory()->GetCryptographer(&trans); |
| 628 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); | 627 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
| 629 | 628 |
| 630 // With default encrypted_types, this should be true. | 629 // With default encrypted_types, this should be true. |
| 631 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 630 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 632 | 631 |
| 633 Syncer::UnsyncedMetaHandles handles; | 632 Syncer::UnsyncedMetaHandles handles; |
| 634 GetUnsyncedEntries(&trans, &handles); | 633 GetUnsyncedEntries(&trans, &handles); |
| 635 EXPECT_TRUE(handles.empty()); | 634 EXPECT_TRUE(handles.empty()); |
| 636 } | 635 } |
| 637 | 636 |
| 638 // Create unsynced bookmarks without encryption. | 637 // Create unsynced bookmarks without encryption. |
| 639 // First item is a folder | 638 // First item is a folder |
| 640 Id folder_id = id_factory_.NewLocalId(); | 639 Id folder_id = id_factory_.NewLocalId(); |
| 641 entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", | 640 entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", |
| 642 true, syncer::BOOKMARKS, NULL); | 641 true, BOOKMARKS, NULL); |
| 643 // Next five items are children of the folder | 642 // Next five items are children of the folder |
| 644 size_t i; | 643 size_t i; |
| 645 size_t batch_s = 5; | 644 size_t batch_s = 5; |
| 646 for (i = 0; i < batch_s; ++i) { | 645 for (i = 0; i < batch_s; ++i) { |
| 647 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, | 646 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, |
| 648 base::StringPrintf("Item %"PRIuS"", i), | 647 base::StringPrintf("Item %"PRIuS"", i), |
| 649 false, syncer::BOOKMARKS, NULL); | 648 false, BOOKMARKS, NULL); |
| 650 } | 649 } |
| 651 // Next five items are children of the root. | 650 // Next five items are children of the root. |
| 652 for (; i < 2*batch_s; ++i) { | 651 for (; i < 2*batch_s; ++i) { |
| 653 entry_factory_->CreateUnsyncedItem( | 652 entry_factory_->CreateUnsyncedItem( |
| 654 id_factory_.NewLocalId(), id_factory_.root(), | 653 id_factory_.NewLocalId(), id_factory_.root(), |
| 655 base::StringPrintf("Item %"PRIuS"", i), false, | 654 base::StringPrintf("Item %"PRIuS"", i), false, |
| 656 syncer::BOOKMARKS, NULL); | 655 BOOKMARKS, NULL); |
| 657 } | 656 } |
| 658 | 657 |
| 659 KeyParams params = {"localhost", "dummy", "foobar"}; | 658 KeyParams params = {"localhost", "dummy", "foobar"}; |
| 660 cryptographer->AddKey(params); | 659 cryptographer->AddKey(params); |
| 661 sync_pb::EntitySpecifics specifics; | 660 sync_pb::EntitySpecifics specifics; |
| 662 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); | 661 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
| 663 cryptographer->GetKeys(nigori->mutable_encrypted()); | 662 cryptographer->GetKeys(nigori->mutable_encrypted()); |
| 664 nigori->set_encrypt_bookmarks(true); | 663 nigori->set_encrypt_bookmarks(true); |
| 665 encrypted_types.Put(syncer::BOOKMARKS); | 664 encrypted_types.Put(BOOKMARKS); |
| 666 entry_factory_->CreateUnappliedNewItem( | 665 entry_factory_->CreateUnappliedNewItem( |
| 667 syncer::ModelTypeToRootTag(syncer::NIGORI), specifics, true); | 666 ModelTypeToRootTag(NIGORI), specifics, true); |
| 668 EXPECT_FALSE(cryptographer->has_pending_keys()); | 667 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 669 EXPECT_TRUE(cryptographer->is_ready()); | 668 EXPECT_TRUE(cryptographer->is_ready()); |
| 670 | 669 |
| 671 { | 670 { |
| 672 // Ensure we have unsynced nodes that aren't properly encrypted. | 671 // Ensure we have unsynced nodes that aren't properly encrypted. |
| 673 syncable::ReadTransaction trans(FROM_HERE, directory()); | 672 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 674 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 673 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 675 | 674 |
| 676 Syncer::UnsyncedMetaHandles handles; | 675 Syncer::UnsyncedMetaHandles handles; |
| 677 GetUnsyncedEntries(&trans, &handles); | 676 GetUnsyncedEntries(&trans, &handles); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 695 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 694 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 696 << "The nigori update should be applied"; | 695 << "The nigori update should be applied"; |
| 697 } | 696 } |
| 698 EXPECT_FALSE(cryptographer->has_pending_keys()); | 697 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 699 EXPECT_TRUE(cryptographer->is_ready()); | 698 EXPECT_TRUE(cryptographer->is_ready()); |
| 700 { | 699 { |
| 701 syncable::ReadTransaction trans(FROM_HERE, directory()); | 700 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 702 | 701 |
| 703 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes | 702 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes |
| 704 // should be encrypted now. | 703 // should be encrypted now. |
| 705 EXPECT_TRUE(syncer::ModelTypeSet::All().Equals( | 704 EXPECT_TRUE(ModelTypeSet::All().Equals( |
| 706 cryptographer->GetEncryptedTypes())); | 705 cryptographer->GetEncryptedTypes())); |
| 707 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 706 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 708 | 707 |
| 709 Syncer::UnsyncedMetaHandles handles; | 708 Syncer::UnsyncedMetaHandles handles; |
| 710 GetUnsyncedEntries(&trans, &handles); | 709 GetUnsyncedEntries(&trans, &handles); |
| 711 EXPECT_EQ(2*batch_s+1, handles.size()); | 710 EXPECT_EQ(2*batch_s+1, handles.size()); |
| 712 } | 711 } |
| 713 | 712 |
| 714 // Simulate another nigori update that doesn't change anything. | 713 // Simulate another nigori update that doesn't change anything. |
| 715 { | 714 { |
| 716 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); | 715 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); |
| 717 MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG, | 716 MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG, |
| 718 syncer::ModelTypeToRootTag(syncer::NIGORI)); | 717 ModelTypeToRootTag(NIGORI)); |
| 719 ASSERT_TRUE(entry.good()); | 718 ASSERT_TRUE(entry.good()); |
| 720 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); | 719 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision()); |
| 721 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); | 720 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); |
| 722 } | 721 } |
| 723 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); | 722 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE); |
| 724 apply_updates_command_.ExecuteImpl(session()); | 723 apply_updates_command_.ExecuteImpl(session()); |
| 725 { | 724 { |
| 726 sessions::StatusController* status = session()->mutable_status_controller(); | 725 sessions::StatusController* status = session()->mutable_status_controller(); |
| 727 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); | 726 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE); |
| 728 ASSERT_TRUE(status->update_progress()); | 727 ASSERT_TRUE(status->update_progress()); |
| 729 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) | 728 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) |
| 730 << "All updates should have been attempted"; | 729 << "All updates should have been attempted"; |
| 731 ASSERT_TRUE(status->conflict_progress()); | 730 ASSERT_TRUE(status->conflict_progress()); |
| 732 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) | 731 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) |
| 733 << "No updates should be in conflict"; | 732 << "No updates should be in conflict"; |
| 734 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) | 733 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) |
| 735 << "No updates should be in conflict"; | 734 << "No updates should be in conflict"; |
| 736 EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount()) | 735 EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount()) |
| 737 << "The nigori update should be applied"; | 736 << "The nigori update should be applied"; |
| 738 } | 737 } |
| 739 EXPECT_FALSE(cryptographer->has_pending_keys()); | 738 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 740 EXPECT_TRUE(cryptographer->is_ready()); | 739 EXPECT_TRUE(cryptographer->is_ready()); |
| 741 { | 740 { |
| 742 syncable::ReadTransaction trans(FROM_HERE, directory()); | 741 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 743 | 742 |
| 744 // All our changes should still be encrypted. | 743 // All our changes should still be encrypted. |
| 745 EXPECT_TRUE(syncer::ModelTypeSet::All().Equals( | 744 EXPECT_TRUE(ModelTypeSet::All().Equals( |
| 746 cryptographer->GetEncryptedTypes())); | 745 cryptographer->GetEncryptedTypes())); |
| 747 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 746 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 748 | 747 |
| 749 Syncer::UnsyncedMetaHandles handles; | 748 Syncer::UnsyncedMetaHandles handles; |
| 750 GetUnsyncedEntries(&trans, &handles); | 749 GetUnsyncedEntries(&trans, &handles); |
| 751 EXPECT_EQ(2*batch_s+1, handles.size()); | 750 EXPECT_EQ(2*batch_s+1, handles.size()); |
| 752 } | 751 } |
| 753 } | 752 } |
| 754 | 753 |
| 755 TEST_F(ApplyUpdatesCommandTest, CannotEncryptUnsyncedChanges) { | 754 TEST_F(ApplyUpdatesCommandTest, CannotEncryptUnsyncedChanges) { |
| 756 // Storing the cryptographer separately is bad, but for this test we | 755 // Storing the cryptographer separately is bad, but for this test we |
| 757 // know it's safe. | 756 // know it's safe. |
| 758 Cryptographer* cryptographer; | 757 Cryptographer* cryptographer; |
| 759 syncer::ModelTypeSet encrypted_types; | 758 ModelTypeSet encrypted_types; |
| 760 encrypted_types.Put(syncer::PASSWORDS); | 759 encrypted_types.Put(PASSWORDS); |
| 761 encrypted_types.Put(syncer::NIGORI); | 760 encrypted_types.Put(NIGORI); |
| 762 { | 761 { |
| 763 syncable::ReadTransaction trans(FROM_HERE, directory()); | 762 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 764 cryptographer = directory()->GetCryptographer(&trans); | 763 cryptographer = directory()->GetCryptographer(&trans); |
| 765 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); | 764 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types)); |
| 766 | 765 |
| 767 // With default encrypted_types, this should be true. | 766 // With default encrypted_types, this should be true. |
| 768 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 767 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 769 | 768 |
| 770 Syncer::UnsyncedMetaHandles handles; | 769 Syncer::UnsyncedMetaHandles handles; |
| 771 GetUnsyncedEntries(&trans, &handles); | 770 GetUnsyncedEntries(&trans, &handles); |
| 772 EXPECT_TRUE(handles.empty()); | 771 EXPECT_TRUE(handles.empty()); |
| 773 } | 772 } |
| 774 | 773 |
| 775 // Create unsynced bookmarks without encryption. | 774 // Create unsynced bookmarks without encryption. |
| 776 // First item is a folder | 775 // First item is a folder |
| 777 Id folder_id = id_factory_.NewLocalId(); | 776 Id folder_id = id_factory_.NewLocalId(); |
| 778 entry_factory_->CreateUnsyncedItem( | 777 entry_factory_->CreateUnsyncedItem( |
| 779 folder_id, id_factory_.root(), "folder", true, | 778 folder_id, id_factory_.root(), "folder", true, |
| 780 syncer::BOOKMARKS, NULL); | 779 BOOKMARKS, NULL); |
| 781 // Next five items are children of the folder | 780 // Next five items are children of the folder |
| 782 size_t i; | 781 size_t i; |
| 783 size_t batch_s = 5; | 782 size_t batch_s = 5; |
| 784 for (i = 0; i < batch_s; ++i) { | 783 for (i = 0; i < batch_s; ++i) { |
| 785 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, | 784 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id, |
| 786 base::StringPrintf("Item %"PRIuS"", i), | 785 base::StringPrintf("Item %"PRIuS"", i), |
| 787 false, syncer::BOOKMARKS, NULL); | 786 false, BOOKMARKS, NULL); |
| 788 } | 787 } |
| 789 // Next five items are children of the root. | 788 // Next five items are children of the root. |
| 790 for (; i < 2*batch_s; ++i) { | 789 for (; i < 2*batch_s; ++i) { |
| 791 entry_factory_->CreateUnsyncedItem( | 790 entry_factory_->CreateUnsyncedItem( |
| 792 id_factory_.NewLocalId(), id_factory_.root(), | 791 id_factory_.NewLocalId(), id_factory_.root(), |
| 793 base::StringPrintf("Item %"PRIuS"", i), false, | 792 base::StringPrintf("Item %"PRIuS"", i), false, |
| 794 syncer::BOOKMARKS, NULL); | 793 BOOKMARKS, NULL); |
| 795 } | 794 } |
| 796 | 795 |
| 797 // We encrypt with new keys, triggering the local cryptographer to be unready | 796 // We encrypt with new keys, triggering the local cryptographer to be unready |
| 798 // and unable to decrypt data (once updated). | 797 // and unable to decrypt data (once updated). |
| 799 Cryptographer other_cryptographer(&encryptor_); | 798 Cryptographer other_cryptographer(&encryptor_); |
| 800 KeyParams params = {"localhost", "dummy", "foobar"}; | 799 KeyParams params = {"localhost", "dummy", "foobar"}; |
| 801 other_cryptographer.AddKey(params); | 800 other_cryptographer.AddKey(params); |
| 802 sync_pb::EntitySpecifics specifics; | 801 sync_pb::EntitySpecifics specifics; |
| 803 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); | 802 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori(); |
| 804 other_cryptographer.GetKeys(nigori->mutable_encrypted()); | 803 other_cryptographer.GetKeys(nigori->mutable_encrypted()); |
| 805 nigori->set_encrypt_bookmarks(true); | 804 nigori->set_encrypt_bookmarks(true); |
| 806 encrypted_types.Put(syncer::BOOKMARKS); | 805 encrypted_types.Put(BOOKMARKS); |
| 807 entry_factory_->CreateUnappliedNewItem( | 806 entry_factory_->CreateUnappliedNewItem( |
| 808 syncer::ModelTypeToRootTag(syncer::NIGORI), specifics, true); | 807 ModelTypeToRootTag(NIGORI), specifics, true); |
| 809 EXPECT_FALSE(cryptographer->has_pending_keys()); | 808 EXPECT_FALSE(cryptographer->has_pending_keys()); |
| 810 | 809 |
| 811 { | 810 { |
| 812 // Ensure we have unsynced nodes that aren't properly encrypted. | 811 // Ensure we have unsynced nodes that aren't properly encrypted. |
| 813 syncable::ReadTransaction trans(FROM_HERE, directory()); | 812 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 814 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 813 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 815 Syncer::UnsyncedMetaHandles handles; | 814 Syncer::UnsyncedMetaHandles handles; |
| 816 GetUnsyncedEntries(&trans, &handles); | 815 GetUnsyncedEntries(&trans, &handles); |
| 817 EXPECT_EQ(2*batch_s+1, handles.size()); | 816 EXPECT_EQ(2*batch_s+1, handles.size()); |
| 818 } | 817 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 836 << "The nigori update should be applied"; | 835 << "The nigori update should be applied"; |
| 837 EXPECT_FALSE(cryptographer->is_ready()); | 836 EXPECT_FALSE(cryptographer->is_ready()); |
| 838 EXPECT_TRUE(cryptographer->has_pending_keys()); | 837 EXPECT_TRUE(cryptographer->has_pending_keys()); |
| 839 { | 838 { |
| 840 syncable::ReadTransaction trans(FROM_HERE, directory()); | 839 syncable::ReadTransaction trans(FROM_HERE, directory()); |
| 841 | 840 |
| 842 // Since we have pending keys, we would have failed to encrypt, but the | 841 // Since we have pending keys, we would have failed to encrypt, but the |
| 843 // cryptographer should be updated. | 842 // cryptographer should be updated. |
| 844 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); | 843 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types)); |
| 845 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals( | 844 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals( |
| 846 syncer::ModelTypeSet().All())); | 845 ModelTypeSet().All())); |
| 847 EXPECT_FALSE(cryptographer->is_ready()); | 846 EXPECT_FALSE(cryptographer->is_ready()); |
| 848 EXPECT_TRUE(cryptographer->has_pending_keys()); | 847 EXPECT_TRUE(cryptographer->has_pending_keys()); |
| 849 | 848 |
| 850 Syncer::UnsyncedMetaHandles handles; | 849 Syncer::UnsyncedMetaHandles handles; |
| 851 GetUnsyncedEntries(&trans, &handles); | 850 GetUnsyncedEntries(&trans, &handles); |
| 852 EXPECT_EQ(2*batch_s+1, handles.size()); | 851 EXPECT_EQ(2*batch_s+1, handles.size()); |
| 853 } | 852 } |
| 854 } | 853 } |
| 855 | 854 |
| 856 } // namespace syncer | 855 } // namespace syncer |
| OLD | NEW |