| Index: sync/syncable/directory_unittest.cc
|
| diff --git a/sync/syncable/directory_unittest.cc b/sync/syncable/directory_unittest.cc
|
| index b2bff36aa56131e62f75b098876ee1d6d69fbb92..ef11d3ba6e8da021876e1d95e5399910c89e836c 100644
|
| --- a/sync/syncable/directory_unittest.cc
|
| +++ b/sync/syncable/directory_unittest.cc
|
| @@ -6,6 +6,11 @@
|
|
|
| #include "base/strings/stringprintf.h"
|
| #include "base/test/values_test_util.h"
|
| +#include "sync/api/attachments/attachment.h"
|
| +#include "sync/internal_api/public/read_node.h"
|
| +#include "sync/internal_api/public/read_transaction.h"
|
| +#include "sync/internal_api/public/write_node.h"
|
| +#include "sync/internal_api/public/write_transaction.h"
|
| #include "sync/syncable/syncable_proto_util.h"
|
| #include "sync/syncable/syncable_util.h"
|
| #include "sync/syncable/syncable_write_transaction.h"
|
| @@ -62,24 +67,24 @@ void SyncableDirectoryTest::SetUp() {
|
| }
|
|
|
| void SyncableDirectoryTest::TearDown() {
|
| - if (dir_)
|
| - dir_->SaveChanges();
|
| - dir_.reset();
|
| + if (user_share_.directory)
|
| + user_share_.directory->SaveChanges();
|
| + user_share_.directory.reset();
|
| }
|
|
|
| DirOpenResult SyncableDirectoryTest::ReopenDirectory() {
|
| // Use a TestDirectoryBackingStore and sql::Connection so we can have test
|
| // data persist across Directory object lifetimes while getting the
|
| // performance benefits of not writing to disk.
|
| - dir_.reset(
|
| + user_share_.directory.reset(
|
| new Directory(new TestDirectoryBackingStore(kDirectoryName, &connection_),
|
| &handler_,
|
| NULL,
|
| NULL,
|
| NULL));
|
|
|
| - DirOpenResult open_result =
|
| - dir_->Open(kDirectoryName, &delegate_, NullTransactionObserver());
|
| + DirOpenResult open_result = user_share_.directory->Open(
|
| + kDirectoryName, &delegate_, NullTransactionObserver());
|
| return open_result;
|
| }
|
|
|
| @@ -93,16 +98,30 @@ void SyncableDirectoryTest::CreateEntry(const std::string& entryname,
|
| const int id) {
|
| CreateEntry(entryname, TestIdFactory::FromNumber(id));
|
| }
|
| +
|
| void SyncableDirectoryTest::CreateEntry(const std::string& entryname, Id id) {
|
| - WriteTransaction wtrans(FROM_HERE, UNITTEST, dir_.get());
|
| + WriteTransaction wtrans(FROM_HERE, UNITTEST, user_share_.directory.get());
|
| MutableEntry me(&wtrans, CREATE, BOOKMARKS, wtrans.root_id(), entryname);
|
| ASSERT_TRUE(me.good());
|
| me.PutId(id);
|
| me.PutIsUnsynced(true);
|
| }
|
|
|
| +void SyncableDirectoryTest::CreateEntryWithAttachmentMetadata(
|
| + const ModelType& model_type,
|
| + const std::string& client_tag,
|
| + const sync_pb::AttachmentMetadata& attachment_metadata) {
|
| + syncer::WriteTransaction trans(FROM_HERE, user_share());
|
| + syncer::ReadNode root_node(&trans);
|
| + root_node.InitByRootLookup();
|
| + syncer::WriteNode node(&trans);
|
| + ASSERT_EQ(node.InitUniqueByCreation(model_type, root_node, client_tag),
|
| + syncer::WriteNode::INIT_SUCCESS);
|
| + node.SetAttachmentMetadata(attachment_metadata);
|
| +}
|
| +
|
| DirOpenResult SyncableDirectoryTest::SimulateSaveAndReloadDir() {
|
| - if (!dir_->SaveChanges())
|
| + if (!user_share_.directory->SaveChanges())
|
| return FAILED_IN_UNITTEST;
|
|
|
| return ReopenDirectory();
|
| @@ -114,7 +133,7 @@ DirOpenResult SyncableDirectoryTest::SimulateCrashAndReloadDir() {
|
|
|
| void SyncableDirectoryTest::GetAllMetaHandles(BaseTransaction* trans,
|
| MetahandleSet* result) {
|
| - dir_->GetAllMetaHandles(trans, result);
|
| + user_share_.directory->GetAllMetaHandles(trans, result);
|
| }
|
|
|
| void SyncableDirectoryTest::CheckPurgeEntriesWithTypeInSucceeded(
|
| @@ -122,12 +141,13 @@ void SyncableDirectoryTest::CheckPurgeEntriesWithTypeInSucceeded(
|
| bool before_reload) {
|
| SCOPED_TRACE(testing::Message("Before reload: ") << before_reload);
|
| {
|
| - ReadTransaction trans(FROM_HERE, dir_.get());
|
| + ReadTransaction trans(FROM_HERE, user_share_.directory.get());
|
| MetahandleSet all_set;
|
| - dir_->GetAllMetaHandles(&trans, &all_set);
|
| + user_share_.directory->GetAllMetaHandles(&trans, &all_set);
|
| EXPECT_EQ(4U, all_set.size());
|
| if (before_reload)
|
| - EXPECT_EQ(6U, dir_->kernel_->metahandles_to_purge.size());
|
| + EXPECT_EQ(6U,
|
| + user_share_.directory->kernel_->metahandles_to_purge.size());
|
| for (MetahandleSet::iterator iter = all_set.begin(); iter != all_set.end();
|
| ++iter) {
|
| Entry e(&trans, GET_BY_HANDLE, *iter);
|
| @@ -144,30 +164,54 @@ void SyncableDirectoryTest::CheckPurgeEntriesWithTypeInSucceeded(
|
|
|
| for (ModelTypeSet::Iterator it = types_to_purge.First(); it.Good();
|
| it.Inc()) {
|
| - EXPECT_FALSE(dir_->InitialSyncEndedForType(it.Get()));
|
| + EXPECT_FALSE(user_share_.directory->InitialSyncEndedForType(it.Get()));
|
| sync_pb::DataTypeProgressMarker progress;
|
| - dir_->GetDownloadProgress(it.Get(), &progress);
|
| + user_share_.directory->GetDownloadProgress(it.Get(), &progress);
|
| EXPECT_EQ("", progress.token());
|
|
|
| - ReadTransaction trans(FROM_HERE, dir_.get());
|
| + ReadTransaction trans(FROM_HERE, user_share_.directory.get());
|
| sync_pb::DataTypeContext context;
|
| - dir_->GetDataTypeContext(&trans, it.Get(), &context);
|
| + user_share_.directory->GetDataTypeContext(&trans, it.Get(), &context);
|
| EXPECT_TRUE(context.SerializeAsString().empty());
|
| }
|
| EXPECT_FALSE(types_to_purge.Has(BOOKMARKS));
|
| - EXPECT_TRUE(dir_->InitialSyncEndedForType(BOOKMARKS));
|
| + EXPECT_TRUE(user_share_.directory->InitialSyncEndedForType(BOOKMARKS));
|
| }
|
|
|
| bool SyncableDirectoryTest::IsInDirtyMetahandles(int64 metahandle) {
|
| - return 1 == dir_->kernel_->dirty_metahandles.count(metahandle);
|
| + return 1 ==
|
| + user_share_.directory->kernel_->dirty_metahandles.count(metahandle);
|
| }
|
|
|
| bool SyncableDirectoryTest::IsInMetahandlesToPurge(int64 metahandle) {
|
| - return 1 == dir_->kernel_->metahandles_to_purge.count(metahandle);
|
| + return 1 ==
|
| + user_share_.directory->kernel_->metahandles_to_purge.count(metahandle);
|
| +}
|
| +
|
| +BaseNode::InitByLookupResult SyncableDirectoryTest::LookupEntryByClientTag(
|
| + const ModelType& model_type,
|
| + const std::string& client_tag) {
|
| + syncer::ReadTransaction trans(FROM_HERE, user_share());
|
| + syncer::ReadNode node(&trans);
|
| + return node.InitByClientTagLookup(model_type, client_tag);
|
| +}
|
| +
|
| +void SyncableDirectoryTest::ReplaceWithTombstone(
|
| + const ModelType& model_type,
|
| + const std::string& client_tag) {
|
| + syncer::WriteTransaction trans(FROM_HERE, user_share());
|
| + syncer::WriteNode node(&trans);
|
| + ASSERT_EQ(node.InitByClientTagLookup(model_type, client_tag),
|
| + syncer::WriteNode::INIT_OK);
|
| + node.Tombstone();
|
| }
|
|
|
| scoped_ptr<Directory>& SyncableDirectoryTest::dir() {
|
| - return dir_;
|
| + return user_share_.directory;
|
| +}
|
| +
|
| +UserShare* SyncableDirectoryTest::user_share() {
|
| + return &user_share_;
|
| }
|
|
|
| DirectoryChangeDelegate* SyncableDirectoryTest::directory_change_delegate() {
|
| @@ -1521,6 +1565,58 @@ TEST_F(SyncableDirectoryTest, StressTransactions) {
|
| }
|
| }
|
|
|
| +// Verify that Directory keeps track of which attachments are referenced by
|
| +// which entries.
|
| +TEST_F(SyncableDirectoryTest, AttachmentLinking) {
|
| + // Add an entry with an attachment.
|
| + std::string tag1("some tag");
|
| + syncer::AttachmentId attachment_id(syncer::AttachmentId::Create());
|
| + sync_pb::AttachmentMetadata attachment_metadata;
|
| + sync_pb::AttachmentMetadataRecord* record = attachment_metadata.add_record();
|
| + *record->mutable_id() = attachment_id.GetProto();
|
| + ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id));
|
| + CreateEntryWithAttachmentMetadata(PREFERENCES, tag1, attachment_metadata);
|
| +
|
| + // See that the directory knows it's linked.
|
| + ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id));
|
| +
|
| + // Add a second entry referencing the same attachment.
|
| + std::string tag2("some other tag");
|
| + CreateEntryWithAttachmentMetadata(PREFERENCES, tag2, attachment_metadata);
|
| +
|
| + // See that the directory knows it's still linked.
|
| + ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id));
|
| +
|
| + // Tombstone the first entry.
|
| + ReplaceWithTombstone(syncer::PREFERENCES, tag1);
|
| +
|
| + // See that the attachment is still considered linked because the entry hasn't
|
| + // been purged from the Directory.
|
| + ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id));
|
| +
|
| + // Save changes and see that the entry is truly gone.
|
| + ASSERT_TRUE(dir()->SaveChanges());
|
| + ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag1),
|
| + syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD);
|
| +
|
| + // However, the attachment is still linked.
|
| + ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id));
|
| +
|
| + // Save, destroy, and recreate the directory. See that it's still linked.
|
| + ASSERT_TRUE(dir()->SaveChanges());
|
| + ASSERT_EQ(syncable::OPENED, ReopenDirectory());
|
| + ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id));
|
| +
|
| + // Tombstone the second entry, save changes, see that it's truly gone.
|
| + ReplaceWithTombstone(syncer::PREFERENCES, tag2);
|
| + ASSERT_TRUE(dir()->SaveChanges());
|
| + ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag2),
|
| + syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD);
|
| +
|
| + // Finally, the attachment is no longer linked.
|
| + ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id));
|
| +}
|
| +
|
| } // namespace syncable
|
|
|
| } // namespace syncer
|
|
|