OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "sync/engine/directory_update_handler.h" | 5 #include "sync/engine/directory_update_handler.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "sync/engine/syncer_proto_util.h" | 10 #include "sync/engine/syncer_proto_util.h" |
| 11 #include "sync/internal_api/public/base/attachment_id_proto.h" |
11 #include "sync/internal_api/public/base/model_type.h" | 12 #include "sync/internal_api/public/base/model_type.h" |
12 #include "sync/internal_api/public/test/test_entry_factory.h" | 13 #include "sync/internal_api/public/test/test_entry_factory.h" |
13 #include "sync/protocol/sync.pb.h" | 14 #include "sync/protocol/sync.pb.h" |
14 #include "sync/sessions/directory_type_debug_info_emitter.h" | 15 #include "sync/sessions/directory_type_debug_info_emitter.h" |
15 #include "sync/sessions/status_controller.h" | 16 #include "sync/sessions/status_controller.h" |
16 #include "sync/syncable/directory.h" | 17 #include "sync/syncable/directory.h" |
17 #include "sync/syncable/entry.h" | 18 #include "sync/syncable/entry.h" |
18 #include "sync/syncable/mutable_entry.h" | 19 #include "sync/syncable/mutable_entry.h" |
19 #include "sync/syncable/syncable_model_neutral_write_transaction.h" | 20 #include "sync/syncable/syncable_model_neutral_write_transaction.h" |
20 #include "sync/syncable/syncable_proto_util.h" | 21 #include "sync/syncable/syncable_proto_util.h" |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 | 390 |
390 { | 391 { |
391 sync_pb::DataTypeContext dir_context; | 392 sync_pb::DataTypeContext dir_context; |
392 syncable::ReadTransaction trans(FROM_HERE, dir()); | 393 syncable::ReadTransaction trans(FROM_HERE, dir()); |
393 trans.directory()->GetDataTypeContext( | 394 trans.directory()->GetDataTypeContext( |
394 &trans, SYNCED_NOTIFICATIONS, &dir_context); | 395 &trans, SYNCED_NOTIFICATIONS, &dir_context); |
395 EXPECT_EQ(old_context.SerializeAsString(), dir_context.SerializeAsString()); | 396 EXPECT_EQ(old_context.SerializeAsString(), dir_context.SerializeAsString()); |
396 } | 397 } |
397 } | 398 } |
398 | 399 |
| 400 // See that updates containing attachment metadata are applied |
| 401 // (i.e. server_attachment_metadata is copied to attachment_metadata). |
| 402 TEST_F(DirectoryUpdateHandlerProcessUpdateTest, |
| 403 ProcessAndApplyUpdatesWithAttachments) { |
| 404 DirectoryTypeDebugInfoEmitter emitter(ARTICLES, &type_observers_); |
| 405 DirectoryUpdateHandler handler(dir(), ARTICLES, ui_worker(), &emitter); |
| 406 sessions::StatusController status; |
| 407 |
| 408 sync_pb::DataTypeProgressMarker progress; |
| 409 progress.set_data_type_id(GetSpecificsFieldNumberFromModelType(ARTICLES)); |
| 410 progress.set_token("token"); |
| 411 progress.mutable_gc_directive()->set_version_watermark(kDefaultVersion + 10); |
| 412 |
| 413 sync_pb::DataTypeContext context; |
| 414 context.set_data_type_id(GetSpecificsFieldNumberFromModelType(ARTICLES)); |
| 415 context.set_context("context"); |
| 416 context.set_version(1); |
| 417 |
| 418 scoped_ptr<sync_pb::SyncEntity> type_root = |
| 419 CreateUpdate(SyncableIdToProto(syncable::Id::CreateFromServerId("root")), |
| 420 syncable::GetNullId().GetServerId(), |
| 421 ARTICLES); |
| 422 type_root->set_server_defined_unique_tag(ModelTypeToRootTag(ARTICLES)); |
| 423 type_root->set_folder(true); |
| 424 |
| 425 scoped_ptr<sync_pb::SyncEntity> e1 = |
| 426 CreateUpdate(SyncableIdToProto(syncable::Id::CreateFromServerId("e1")), |
| 427 type_root->id_string(), |
| 428 ARTICLES); |
| 429 sync_pb::AttachmentIdProto* attachment_id = e1->add_attachment_id(); |
| 430 *attachment_id = CreateAttachmentIdProto(); |
| 431 |
| 432 SyncEntityList updates; |
| 433 updates.push_back(type_root.get()); |
| 434 updates.push_back(e1.get()); |
| 435 |
| 436 // Process and apply updates. |
| 437 EXPECT_EQ( |
| 438 SYNCER_OK, |
| 439 handler.ProcessGetUpdatesResponse(progress, context, updates, &status)); |
| 440 handler.ApplyUpdates(&status); |
| 441 |
| 442 ASSERT_TRUE(EntryExists(type_root->id_string())); |
| 443 ASSERT_TRUE(EntryExists(e1->id_string())); |
| 444 { |
| 445 syncable::ReadTransaction trans(FROM_HERE, dir()); |
| 446 syncable::Entry e(&trans, |
| 447 syncable::GET_BY_ID, |
| 448 syncable::Id::CreateFromServerId(e1->id_string())); |
| 449 |
| 450 // See that the attachment_metadata is correct. |
| 451 sync_pb::AttachmentMetadata attachment_metadata = e.GetAttachmentMetadata(); |
| 452 ASSERT_EQ(1, attachment_metadata.record_size()); |
| 453 ASSERT_EQ(attachment_id->SerializeAsString(), |
| 454 attachment_metadata.record(0).id().SerializeAsString()); |
| 455 ASSERT_TRUE(attachment_metadata.record(0).is_on_server()); |
| 456 |
| 457 // See that attachment_metadata and server_attachment_metadata are equal. |
| 458 ASSERT_EQ(attachment_metadata.SerializeAsString(), |
| 459 e.GetServerAttachmentMetadata().SerializeAsString()); |
| 460 } |
| 461 } |
| 462 |
399 // A test harness for tests that focus on applying updates. | 463 // A test harness for tests that focus on applying updates. |
400 // | 464 // |
401 // Update application is performed when we want to take updates that were | 465 // Update application is performed when we want to take updates that were |
402 // previously downloaded, processed, and stored in our syncable::Directory | 466 // previously downloaded, processed, and stored in our syncable::Directory |
403 // and use them to update our local state (both the Directory's local state | 467 // and use them to update our local state (both the Directory's local state |
404 // and the model's local state, though these tests focus only on the Directory's | 468 // and the model's local state, though these tests focus only on the Directory's |
405 // local state). | 469 // local state). |
406 // | 470 // |
407 // This is kept separate from the update processing test in part for historical | 471 // This is kept separate from the update processing test in part for historical |
408 // reasons, and in part because these tests may require a bit more infrastrcture | 472 // reasons, and in part because these tests may require a bit more infrastrcture |
409 // in the future. Update application should happen on a different thread a lot | 473 // in the future. Update application should happen on a different thread a lot |
410 // of the time so these tests may end up requiring more infrastructure than the | 474 // of the time so these tests may end up requiring more infrastructure than the |
411 // update processing tests. Currently, we're bypassing most of those issues by | 475 // update processing tests. Currently, we're bypassing most of those issues by |
412 // using FakeModelWorkers, so there's not much difference between the two test | 476 // using FakeModelWorkers, so there's not much difference between the two test |
413 // harnesses. | 477 // harnesses. |
414 class DirectoryUpdateHandlerApplyUpdateTest : public ::testing::Test { | 478 class DirectoryUpdateHandlerApplyUpdateTest : public ::testing::Test { |
415 public: | 479 public: |
416 DirectoryUpdateHandlerApplyUpdateTest() | 480 DirectoryUpdateHandlerApplyUpdateTest() |
417 : ui_worker_(new FakeModelWorker(GROUP_UI)), | 481 : ui_worker_(new FakeModelWorker(GROUP_UI)), |
418 password_worker_(new FakeModelWorker(GROUP_PASSWORD)), | 482 password_worker_(new FakeModelWorker(GROUP_PASSWORD)), |
419 passive_worker_(new FakeModelWorker(GROUP_PASSIVE)), | 483 passive_worker_(new FakeModelWorker(GROUP_PASSIVE)), |
420 bookmarks_emitter_(BOOKMARKS, &type_observers_), | 484 bookmarks_emitter_(BOOKMARKS, &type_observers_), |
421 passwords_emitter_(PASSWORDS, &type_observers_), | 485 passwords_emitter_(PASSWORDS, &type_observers_), |
| 486 articles_emitter_(ARTICLES, &type_observers_), |
422 update_handler_map_deleter_(&update_handler_map_) {} | 487 update_handler_map_deleter_(&update_handler_map_) {} |
423 | 488 |
424 virtual void SetUp() OVERRIDE { | 489 virtual void SetUp() OVERRIDE { |
425 dir_maker_.SetUp(); | 490 dir_maker_.SetUp(); |
426 entry_factory_.reset(new TestEntryFactory(directory())); | 491 entry_factory_.reset(new TestEntryFactory(directory())); |
427 | 492 |
428 update_handler_map_.insert(std::make_pair( | 493 update_handler_map_.insert(std::make_pair( |
429 BOOKMARKS, | 494 BOOKMARKS, |
430 new DirectoryUpdateHandler(directory(), BOOKMARKS, | 495 new DirectoryUpdateHandler(directory(), BOOKMARKS, |
431 ui_worker_, &bookmarks_emitter_))); | 496 ui_worker_, &bookmarks_emitter_))); |
432 update_handler_map_.insert(std::make_pair( | 497 update_handler_map_.insert(std::make_pair( |
433 PASSWORDS, | 498 PASSWORDS, |
434 new DirectoryUpdateHandler(directory(), | 499 new DirectoryUpdateHandler(directory(), |
435 PASSWORDS, | 500 PASSWORDS, |
436 password_worker_, | 501 password_worker_, |
437 &passwords_emitter_))); | 502 &passwords_emitter_))); |
| 503 update_handler_map_.insert(std::make_pair( |
| 504 ARTICLES, |
| 505 new DirectoryUpdateHandler( |
| 506 directory(), ARTICLES, ui_worker_, &articles_emitter_))); |
438 } | 507 } |
439 | 508 |
440 virtual void TearDown() OVERRIDE { | 509 virtual void TearDown() OVERRIDE { |
441 dir_maker_.TearDown(); | 510 dir_maker_.TearDown(); |
442 } | 511 } |
443 | 512 |
444 const UpdateCounters& GetBookmarksUpdateCounters() { | 513 const UpdateCounters& GetBookmarksUpdateCounters() { |
445 return bookmarks_emitter_.GetUpdateCounters(); | 514 return bookmarks_emitter_.GetUpdateCounters(); |
446 } | 515 } |
447 | 516 |
448 const UpdateCounters& GetPasswordsUpdateCounters() { | 517 const UpdateCounters& GetPasswordsUpdateCounters() { |
449 return passwords_emitter_.GetUpdateCounters(); | 518 return passwords_emitter_.GetUpdateCounters(); |
450 } | 519 } |
451 | 520 |
| 521 const UpdateCounters& GetArticlesUpdateCounters() { |
| 522 return articles_emitter_.GetUpdateCounters(); |
| 523 } |
| 524 |
452 protected: | 525 protected: |
453 void ApplyBookmarkUpdates(sessions::StatusController* status) { | 526 void ApplyBookmarkUpdates(sessions::StatusController* status) { |
454 update_handler_map_[BOOKMARKS]->ApplyUpdates(status); | 527 update_handler_map_[BOOKMARKS]->ApplyUpdates(status); |
455 } | 528 } |
456 | 529 |
457 void ApplyPasswordUpdates(sessions::StatusController* status) { | 530 void ApplyPasswordUpdates(sessions::StatusController* status) { |
458 update_handler_map_[PASSWORDS]->ApplyUpdates(status); | 531 update_handler_map_[PASSWORDS]->ApplyUpdates(status); |
459 } | 532 } |
460 | 533 |
| 534 void ApplyArticlesUpdates(sessions::StatusController* status) { |
| 535 update_handler_map_[ARTICLES]->ApplyUpdates(status); |
| 536 } |
| 537 |
461 TestEntryFactory* entry_factory() { | 538 TestEntryFactory* entry_factory() { |
462 return entry_factory_.get(); | 539 return entry_factory_.get(); |
463 } | 540 } |
464 | 541 |
465 syncable::Directory* directory() { | 542 syncable::Directory* directory() { |
466 return dir_maker_.directory(); | 543 return dir_maker_.directory(); |
467 } | 544 } |
468 | 545 |
469 private: | 546 private: |
470 typedef std::map<ModelType, UpdateHandler*> UpdateHandlerMap; | 547 typedef std::map<ModelType, UpdateHandler*> UpdateHandlerMap; |
471 | 548 |
472 base::MessageLoop loop_; // Needed to initialize the directory. | 549 base::MessageLoop loop_; // Needed to initialize the directory. |
473 TestDirectorySetterUpper dir_maker_; | 550 TestDirectorySetterUpper dir_maker_; |
474 scoped_ptr<TestEntryFactory> entry_factory_; | 551 scoped_ptr<TestEntryFactory> entry_factory_; |
475 | 552 |
476 scoped_refptr<FakeModelWorker> ui_worker_; | 553 scoped_refptr<FakeModelWorker> ui_worker_; |
477 scoped_refptr<FakeModelWorker> password_worker_; | 554 scoped_refptr<FakeModelWorker> password_worker_; |
478 scoped_refptr<FakeModelWorker> passive_worker_; | 555 scoped_refptr<FakeModelWorker> passive_worker_; |
479 | 556 |
480 ObserverList<TypeDebugInfoObserver> type_observers_; | 557 ObserverList<TypeDebugInfoObserver> type_observers_; |
481 DirectoryTypeDebugInfoEmitter bookmarks_emitter_; | 558 DirectoryTypeDebugInfoEmitter bookmarks_emitter_; |
482 DirectoryTypeDebugInfoEmitter passwords_emitter_; | 559 DirectoryTypeDebugInfoEmitter passwords_emitter_; |
| 560 DirectoryTypeDebugInfoEmitter articles_emitter_; |
483 | 561 |
484 UpdateHandlerMap update_handler_map_; | 562 UpdateHandlerMap update_handler_map_; |
485 STLValueDeleter<UpdateHandlerMap> update_handler_map_deleter_; | 563 STLValueDeleter<UpdateHandlerMap> update_handler_map_deleter_; |
486 }; | 564 }; |
487 | 565 |
488 namespace { | 566 namespace { |
489 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { | 567 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { |
490 sync_pb::EntitySpecifics result; | 568 sync_pb::EntitySpecifics result; |
491 AddDefaultFieldValue(BOOKMARKS, &result); | 569 AddDefaultFieldValue(BOOKMARKS, &result); |
492 return result; | 570 return result; |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1017 syncable::ReadTransaction trans(FROM_HERE, directory()); | 1095 syncable::ReadTransaction trans(FROM_HERE, directory()); |
1018 syncable::Entry e1(&trans, syncable::GET_BY_HANDLE, decryptable_handle); | 1096 syncable::Entry e1(&trans, syncable::GET_BY_HANDLE, decryptable_handle); |
1019 syncable::Entry e2(&trans, syncable::GET_BY_HANDLE, undecryptable_handle); | 1097 syncable::Entry e2(&trans, syncable::GET_BY_HANDLE, undecryptable_handle); |
1020 ASSERT_TRUE(e1.good()); | 1098 ASSERT_TRUE(e1.good()); |
1021 ASSERT_TRUE(e2.good()); | 1099 ASSERT_TRUE(e2.good()); |
1022 EXPECT_FALSE(e1.GetIsUnappliedUpdate()); | 1100 EXPECT_FALSE(e1.GetIsUnappliedUpdate()); |
1023 EXPECT_TRUE(e2.GetIsUnappliedUpdate()); | 1101 EXPECT_TRUE(e2.GetIsUnappliedUpdate()); |
1024 } | 1102 } |
1025 } | 1103 } |
1026 | 1104 |
| 1105 TEST_F(DirectoryUpdateHandlerApplyUpdateTest, |
| 1106 SimpleConflictDifferentAttachmentMetadata) { |
| 1107 const bool is_folder = false; |
| 1108 sync_pb::EntitySpecifics specifics; |
| 1109 *specifics.mutable_article() = sync_pb::ArticleSpecifics(); |
| 1110 int64 handle = entry_factory()->CreateSyncedItem("art1", ARTICLES, is_folder); |
| 1111 |
| 1112 sync_pb::AttachmentIdProto local_attachment_id = CreateAttachmentIdProto(); |
| 1113 sync_pb::AttachmentIdProto server_attachment_id = CreateAttachmentIdProto(); |
| 1114 |
| 1115 // Add an attachment to the local attachment metadata. |
| 1116 sync_pb::AttachmentMetadata local_metadata; |
| 1117 sync_pb::AttachmentMetadataRecord* local_record = local_metadata.add_record(); |
| 1118 *local_record->mutable_id() = local_attachment_id; |
| 1119 local_record->set_is_on_server(true); |
| 1120 entry_factory()->SetLocalAttachmentMetadataForItem(handle, local_metadata); |
| 1121 |
| 1122 // Add a different attachment to the server attachment metadata. |
| 1123 sync_pb::AttachmentMetadata server_metadata; |
| 1124 sync_pb::AttachmentMetadataRecord* server_record = |
| 1125 server_metadata.add_record(); |
| 1126 *server_record->mutable_id() = server_attachment_id; |
| 1127 server_record->set_is_on_server(true); |
| 1128 entry_factory()->SetServerAttachmentMetadataForItem(handle, server_metadata); |
| 1129 |
| 1130 // At this point we have a simple conflict. The server says art1 should have |
| 1131 // server_attachment_id, but the local sync engine says it should have |
| 1132 // local_attachment_id. |
| 1133 |
| 1134 sessions::StatusController status; |
| 1135 ApplyArticlesUpdates(&status); |
| 1136 |
| 1137 // See that the server won. |
| 1138 const UpdateCounters& counters = GetArticlesUpdateCounters(); |
| 1139 EXPECT_EQ(1, counters.num_updates_applied); |
| 1140 EXPECT_EQ(1, counters.num_local_overwrites); |
| 1141 EXPECT_EQ(0, counters.num_server_overwrites); |
| 1142 local_metadata = entry_factory()->GetLocalAttachmentMetadataForItem(handle); |
| 1143 EXPECT_EQ(server_metadata.SerializeAsString(), |
| 1144 local_metadata.SerializeAsString()); |
| 1145 } |
| 1146 |
| 1147 TEST_F(DirectoryUpdateHandlerApplyUpdateTest, |
| 1148 SimpleConflictSameAttachmentMetadataDifferentOrder) { |
| 1149 const bool is_folder = false; |
| 1150 sync_pb::EntitySpecifics specifics; |
| 1151 *specifics.mutable_article() = sync_pb::ArticleSpecifics(); |
| 1152 int64 handle = entry_factory()->CreateSyncedItem("art1", ARTICLES, is_folder); |
| 1153 |
| 1154 sync_pb::AttachmentIdProto id1 = CreateAttachmentIdProto(); |
| 1155 sync_pb::AttachmentIdProto id2 = CreateAttachmentIdProto(); |
| 1156 |
| 1157 // Add id1, then id2 to the local attachment metadata. |
| 1158 sync_pb::AttachmentMetadata local_metadata; |
| 1159 sync_pb::AttachmentMetadataRecord* record = local_metadata.add_record(); |
| 1160 *record->mutable_id() = id1; |
| 1161 record->set_is_on_server(true); |
| 1162 record = local_metadata.add_record(); |
| 1163 *record->mutable_id() = id2; |
| 1164 record->set_is_on_server(true); |
| 1165 entry_factory()->SetLocalAttachmentMetadataForItem(handle, local_metadata); |
| 1166 |
| 1167 // Add id1 and id2 to the server attachment metadata, but in reverse order. |
| 1168 sync_pb::AttachmentMetadata server_metadata; |
| 1169 record = server_metadata.add_record(); |
| 1170 *record->mutable_id() = id2; |
| 1171 record->set_is_on_server(true); |
| 1172 record = local_metadata.add_record(); |
| 1173 *record->mutable_id() = id1; |
| 1174 record->set_is_on_server(true); |
| 1175 entry_factory()->SetServerAttachmentMetadataForItem(handle, server_metadata); |
| 1176 |
| 1177 // At this point we have a (false) conflict. |
| 1178 |
| 1179 sessions::StatusController status; |
| 1180 ApplyArticlesUpdates(&status); |
| 1181 |
| 1182 // See that the server won. |
| 1183 const UpdateCounters& counters = GetArticlesUpdateCounters(); |
| 1184 EXPECT_EQ(1, counters.num_updates_applied); |
| 1185 EXPECT_EQ(1, counters.num_local_overwrites); |
| 1186 EXPECT_EQ(0, counters.num_server_overwrites); |
| 1187 local_metadata = entry_factory()->GetLocalAttachmentMetadataForItem(handle); |
| 1188 EXPECT_EQ(server_metadata.SerializeAsString(), |
| 1189 local_metadata.SerializeAsString()); |
| 1190 } |
| 1191 |
1027 } // namespace syncer | 1192 } // namespace syncer |
OLD | NEW |