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/syncable/directory_unittest.h" | 5 #include "sync/syncable/directory_unittest.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
8 #include "base/test/values_test_util.h" | 8 #include "base/test/values_test_util.h" |
| 9 #include "sync/api/attachments/attachment.h" |
| 10 #include "sync/internal_api/public/read_node.h" |
| 11 #include "sync/internal_api/public/read_transaction.h" |
| 12 #include "sync/internal_api/public/write_node.h" |
| 13 #include "sync/internal_api/public/write_transaction.h" |
9 #include "sync/syncable/syncable_proto_util.h" | 14 #include "sync/syncable/syncable_proto_util.h" |
10 #include "sync/syncable/syncable_util.h" | 15 #include "sync/syncable/syncable_util.h" |
11 #include "sync/syncable/syncable_write_transaction.h" | 16 #include "sync/syncable/syncable_write_transaction.h" |
12 #include "sync/test/engine/test_syncable_utils.h" | 17 #include "sync/test/engine/test_syncable_utils.h" |
13 #include "sync/test/test_directory_backing_store.h" | 18 #include "sync/test/test_directory_backing_store.h" |
14 | 19 |
15 using base::ExpectDictBooleanValue; | 20 using base::ExpectDictBooleanValue; |
16 using base::ExpectDictStringValue; | 21 using base::ExpectDictStringValue; |
17 | 22 |
18 namespace syncer { | 23 namespace syncer { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 | 60 |
56 SyncableDirectoryTest::~SyncableDirectoryTest() { | 61 SyncableDirectoryTest::~SyncableDirectoryTest() { |
57 } | 62 } |
58 | 63 |
59 void SyncableDirectoryTest::SetUp() { | 64 void SyncableDirectoryTest::SetUp() { |
60 ASSERT_TRUE(connection_.OpenInMemory()); | 65 ASSERT_TRUE(connection_.OpenInMemory()); |
61 ASSERT_EQ(OPENED, ReopenDirectory()); | 66 ASSERT_EQ(OPENED, ReopenDirectory()); |
62 } | 67 } |
63 | 68 |
64 void SyncableDirectoryTest::TearDown() { | 69 void SyncableDirectoryTest::TearDown() { |
65 if (dir_) | 70 if (user_share_.directory) |
66 dir_->SaveChanges(); | 71 user_share_.directory->SaveChanges(); |
67 dir_.reset(); | 72 user_share_.directory.reset(); |
68 } | 73 } |
69 | 74 |
70 DirOpenResult SyncableDirectoryTest::ReopenDirectory() { | 75 DirOpenResult SyncableDirectoryTest::ReopenDirectory() { |
71 // Use a TestDirectoryBackingStore and sql::Connection so we can have test | 76 // Use a TestDirectoryBackingStore and sql::Connection so we can have test |
72 // data persist across Directory object lifetimes while getting the | 77 // data persist across Directory object lifetimes while getting the |
73 // performance benefits of not writing to disk. | 78 // performance benefits of not writing to disk. |
74 dir_.reset( | 79 user_share_.directory.reset( |
75 new Directory(new TestDirectoryBackingStore(kDirectoryName, &connection_), | 80 new Directory(new TestDirectoryBackingStore(kDirectoryName, &connection_), |
76 &handler_, | 81 &handler_, |
77 NULL, | 82 NULL, |
78 NULL, | 83 NULL, |
79 NULL)); | 84 NULL)); |
80 | 85 |
81 DirOpenResult open_result = | 86 DirOpenResult open_result = user_share_.directory->Open( |
82 dir_->Open(kDirectoryName, &delegate_, NullTransactionObserver()); | 87 kDirectoryName, &delegate_, NullTransactionObserver()); |
83 return open_result; | 88 return open_result; |
84 } | 89 } |
85 | 90 |
86 // Creates an empty entry and sets the ID field to a default one. | 91 // Creates an empty entry and sets the ID field to a default one. |
87 void SyncableDirectoryTest::CreateEntry(const std::string& entryname) { | 92 void SyncableDirectoryTest::CreateEntry(const std::string& entryname) { |
88 CreateEntry(entryname, TestIdFactory::FromNumber(-99)); | 93 CreateEntry(entryname, TestIdFactory::FromNumber(-99)); |
89 } | 94 } |
90 | 95 |
91 // Creates an empty entry and sets the ID field to id. | 96 // Creates an empty entry and sets the ID field to id. |
92 void SyncableDirectoryTest::CreateEntry(const std::string& entryname, | 97 void SyncableDirectoryTest::CreateEntry(const std::string& entryname, |
93 const int id) { | 98 const int id) { |
94 CreateEntry(entryname, TestIdFactory::FromNumber(id)); | 99 CreateEntry(entryname, TestIdFactory::FromNumber(id)); |
95 } | 100 } |
| 101 |
96 void SyncableDirectoryTest::CreateEntry(const std::string& entryname, Id id) { | 102 void SyncableDirectoryTest::CreateEntry(const std::string& entryname, Id id) { |
97 WriteTransaction wtrans(FROM_HERE, UNITTEST, dir_.get()); | 103 WriteTransaction wtrans(FROM_HERE, UNITTEST, user_share_.directory.get()); |
98 MutableEntry me(&wtrans, CREATE, BOOKMARKS, wtrans.root_id(), entryname); | 104 MutableEntry me(&wtrans, CREATE, BOOKMARKS, wtrans.root_id(), entryname); |
99 ASSERT_TRUE(me.good()); | 105 ASSERT_TRUE(me.good()); |
100 me.PutId(id); | 106 me.PutId(id); |
101 me.PutIsUnsynced(true); | 107 me.PutIsUnsynced(true); |
102 } | 108 } |
103 | 109 |
| 110 void SyncableDirectoryTest::CreateEntryWithAttachmentMetadata( |
| 111 const ModelType& model_type, |
| 112 const std::string& client_tag, |
| 113 const sync_pb::AttachmentMetadata& attachment_metadata) { |
| 114 syncer::WriteTransaction trans(FROM_HERE, user_share()); |
| 115 syncer::ReadNode root_node(&trans); |
| 116 root_node.InitByRootLookup(); |
| 117 syncer::WriteNode node(&trans); |
| 118 ASSERT_EQ(node.InitUniqueByCreation(model_type, root_node, client_tag), |
| 119 syncer::WriteNode::INIT_SUCCESS); |
| 120 node.SetAttachmentMetadata(attachment_metadata); |
| 121 } |
| 122 |
104 DirOpenResult SyncableDirectoryTest::SimulateSaveAndReloadDir() { | 123 DirOpenResult SyncableDirectoryTest::SimulateSaveAndReloadDir() { |
105 if (!dir_->SaveChanges()) | 124 if (!user_share_.directory->SaveChanges()) |
106 return FAILED_IN_UNITTEST; | 125 return FAILED_IN_UNITTEST; |
107 | 126 |
108 return ReopenDirectory(); | 127 return ReopenDirectory(); |
109 } | 128 } |
110 | 129 |
111 DirOpenResult SyncableDirectoryTest::SimulateCrashAndReloadDir() { | 130 DirOpenResult SyncableDirectoryTest::SimulateCrashAndReloadDir() { |
112 return ReopenDirectory(); | 131 return ReopenDirectory(); |
113 } | 132 } |
114 | 133 |
115 void SyncableDirectoryTest::GetAllMetaHandles(BaseTransaction* trans, | 134 void SyncableDirectoryTest::GetAllMetaHandles(BaseTransaction* trans, |
116 MetahandleSet* result) { | 135 MetahandleSet* result) { |
117 dir_->GetAllMetaHandles(trans, result); | 136 user_share_.directory->GetAllMetaHandles(trans, result); |
118 } | 137 } |
119 | 138 |
120 void SyncableDirectoryTest::CheckPurgeEntriesWithTypeInSucceeded( | 139 void SyncableDirectoryTest::CheckPurgeEntriesWithTypeInSucceeded( |
121 ModelTypeSet types_to_purge, | 140 ModelTypeSet types_to_purge, |
122 bool before_reload) { | 141 bool before_reload) { |
123 SCOPED_TRACE(testing::Message("Before reload: ") << before_reload); | 142 SCOPED_TRACE(testing::Message("Before reload: ") << before_reload); |
124 { | 143 { |
125 ReadTransaction trans(FROM_HERE, dir_.get()); | 144 ReadTransaction trans(FROM_HERE, user_share_.directory.get()); |
126 MetahandleSet all_set; | 145 MetahandleSet all_set; |
127 dir_->GetAllMetaHandles(&trans, &all_set); | 146 user_share_.directory->GetAllMetaHandles(&trans, &all_set); |
128 EXPECT_EQ(4U, all_set.size()); | 147 EXPECT_EQ(4U, all_set.size()); |
129 if (before_reload) | 148 if (before_reload) |
130 EXPECT_EQ(6U, dir_->kernel_->metahandles_to_purge.size()); | 149 EXPECT_EQ(6U, |
| 150 user_share_.directory->kernel_->metahandles_to_purge.size()); |
131 for (MetahandleSet::iterator iter = all_set.begin(); iter != all_set.end(); | 151 for (MetahandleSet::iterator iter = all_set.begin(); iter != all_set.end(); |
132 ++iter) { | 152 ++iter) { |
133 Entry e(&trans, GET_BY_HANDLE, *iter); | 153 Entry e(&trans, GET_BY_HANDLE, *iter); |
134 const ModelType local_type = e.GetModelType(); | 154 const ModelType local_type = e.GetModelType(); |
135 const ModelType server_type = e.GetServerModelType(); | 155 const ModelType server_type = e.GetServerModelType(); |
136 | 156 |
137 // Note the dance around incrementing |it|, since we sometimes erase(). | 157 // Note the dance around incrementing |it|, since we sometimes erase(). |
138 if ((IsRealDataType(local_type) && types_to_purge.Has(local_type)) || | 158 if ((IsRealDataType(local_type) && types_to_purge.Has(local_type)) || |
139 (IsRealDataType(server_type) && types_to_purge.Has(server_type))) { | 159 (IsRealDataType(server_type) && types_to_purge.Has(server_type))) { |
140 FAIL() << "Illegal type should have been deleted."; | 160 FAIL() << "Illegal type should have been deleted."; |
141 } | 161 } |
142 } | 162 } |
143 } | 163 } |
144 | 164 |
145 for (ModelTypeSet::Iterator it = types_to_purge.First(); it.Good(); | 165 for (ModelTypeSet::Iterator it = types_to_purge.First(); it.Good(); |
146 it.Inc()) { | 166 it.Inc()) { |
147 EXPECT_FALSE(dir_->InitialSyncEndedForType(it.Get())); | 167 EXPECT_FALSE(user_share_.directory->InitialSyncEndedForType(it.Get())); |
148 sync_pb::DataTypeProgressMarker progress; | 168 sync_pb::DataTypeProgressMarker progress; |
149 dir_->GetDownloadProgress(it.Get(), &progress); | 169 user_share_.directory->GetDownloadProgress(it.Get(), &progress); |
150 EXPECT_EQ("", progress.token()); | 170 EXPECT_EQ("", progress.token()); |
151 | 171 |
152 ReadTransaction trans(FROM_HERE, dir_.get()); | 172 ReadTransaction trans(FROM_HERE, user_share_.directory.get()); |
153 sync_pb::DataTypeContext context; | 173 sync_pb::DataTypeContext context; |
154 dir_->GetDataTypeContext(&trans, it.Get(), &context); | 174 user_share_.directory->GetDataTypeContext(&trans, it.Get(), &context); |
155 EXPECT_TRUE(context.SerializeAsString().empty()); | 175 EXPECT_TRUE(context.SerializeAsString().empty()); |
156 } | 176 } |
157 EXPECT_FALSE(types_to_purge.Has(BOOKMARKS)); | 177 EXPECT_FALSE(types_to_purge.Has(BOOKMARKS)); |
158 EXPECT_TRUE(dir_->InitialSyncEndedForType(BOOKMARKS)); | 178 EXPECT_TRUE(user_share_.directory->InitialSyncEndedForType(BOOKMARKS)); |
159 } | 179 } |
160 | 180 |
161 bool SyncableDirectoryTest::IsInDirtyMetahandles(int64 metahandle) { | 181 bool SyncableDirectoryTest::IsInDirtyMetahandles(int64 metahandle) { |
162 return 1 == dir_->kernel_->dirty_metahandles.count(metahandle); | 182 return 1 == |
| 183 user_share_.directory->kernel_->dirty_metahandles.count(metahandle); |
163 } | 184 } |
164 | 185 |
165 bool SyncableDirectoryTest::IsInMetahandlesToPurge(int64 metahandle) { | 186 bool SyncableDirectoryTest::IsInMetahandlesToPurge(int64 metahandle) { |
166 return 1 == dir_->kernel_->metahandles_to_purge.count(metahandle); | 187 return 1 == |
| 188 user_share_.directory->kernel_->metahandles_to_purge.count(metahandle); |
| 189 } |
| 190 |
| 191 BaseNode::InitByLookupResult SyncableDirectoryTest::LookupEntryByClientTag( |
| 192 const ModelType& model_type, |
| 193 const std::string& client_tag) { |
| 194 syncer::ReadTransaction trans(FROM_HERE, user_share()); |
| 195 syncer::ReadNode node(&trans); |
| 196 return node.InitByClientTagLookup(model_type, client_tag); |
| 197 } |
| 198 |
| 199 void SyncableDirectoryTest::ReplaceWithTombstone( |
| 200 const ModelType& model_type, |
| 201 const std::string& client_tag) { |
| 202 syncer::WriteTransaction trans(FROM_HERE, user_share()); |
| 203 syncer::WriteNode node(&trans); |
| 204 ASSERT_EQ(node.InitByClientTagLookup(model_type, client_tag), |
| 205 syncer::WriteNode::INIT_OK); |
| 206 node.Tombstone(); |
167 } | 207 } |
168 | 208 |
169 scoped_ptr<Directory>& SyncableDirectoryTest::dir() { | 209 scoped_ptr<Directory>& SyncableDirectoryTest::dir() { |
170 return dir_; | 210 return user_share_.directory; |
| 211 } |
| 212 |
| 213 UserShare* SyncableDirectoryTest::user_share() { |
| 214 return &user_share_; |
171 } | 215 } |
172 | 216 |
173 DirectoryChangeDelegate* SyncableDirectoryTest::directory_change_delegate() { | 217 DirectoryChangeDelegate* SyncableDirectoryTest::directory_change_delegate() { |
174 return &delegate_; | 218 return &delegate_; |
175 } | 219 } |
176 | 220 |
177 Encryptor* SyncableDirectoryTest::encryptor() { | 221 Encryptor* SyncableDirectoryTest::encryptor() { |
178 return &encryptor_; | 222 return &encryptor_; |
179 } | 223 } |
180 | 224 |
(...skipping 1333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1514 thread_delegates[i].reset(new StressTransactionsDelegate(dir().get(), i)); | 1558 thread_delegates[i].reset(new StressTransactionsDelegate(dir().get(), i)); |
1515 ASSERT_TRUE(base::PlatformThread::Create( | 1559 ASSERT_TRUE(base::PlatformThread::Create( |
1516 0, thread_delegates[i].get(), &threads[i])); | 1560 0, thread_delegates[i].get(), &threads[i])); |
1517 } | 1561 } |
1518 | 1562 |
1519 for (int i = 0; i < kThreadCount; ++i) { | 1563 for (int i = 0; i < kThreadCount; ++i) { |
1520 base::PlatformThread::Join(threads[i]); | 1564 base::PlatformThread::Join(threads[i]); |
1521 } | 1565 } |
1522 } | 1566 } |
1523 | 1567 |
| 1568 // Verify that Directory keeps track of which attachments are referenced by |
| 1569 // which entries. |
| 1570 TEST_F(SyncableDirectoryTest, AttachmentLinking) { |
| 1571 // Add an entry with an attachment. |
| 1572 std::string tag1("some tag"); |
| 1573 syncer::AttachmentId attachment_id(syncer::AttachmentId::Create()); |
| 1574 sync_pb::AttachmentMetadata attachment_metadata; |
| 1575 sync_pb::AttachmentMetadataRecord* record = attachment_metadata.add_record(); |
| 1576 *record->mutable_id() = attachment_id.GetProto(); |
| 1577 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id)); |
| 1578 CreateEntryWithAttachmentMetadata(PREFERENCES, tag1, attachment_metadata); |
| 1579 |
| 1580 // See that the directory knows it's linked. |
| 1581 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id)); |
| 1582 |
| 1583 // Add a second entry referencing the same attachment. |
| 1584 std::string tag2("some other tag"); |
| 1585 CreateEntryWithAttachmentMetadata(PREFERENCES, tag2, attachment_metadata); |
| 1586 |
| 1587 // See that the directory knows it's still linked. |
| 1588 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id)); |
| 1589 |
| 1590 // Tombstone the first entry. |
| 1591 ReplaceWithTombstone(syncer::PREFERENCES, tag1); |
| 1592 |
| 1593 // See that the attachment is still considered linked because the entry hasn't |
| 1594 // been purged from the Directory. |
| 1595 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id)); |
| 1596 |
| 1597 // Save changes and see that the entry is truly gone. |
| 1598 ASSERT_TRUE(dir()->SaveChanges()); |
| 1599 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag1), |
| 1600 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD); |
| 1601 |
| 1602 // However, the attachment is still linked. |
| 1603 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id)); |
| 1604 |
| 1605 // Save, destroy, and recreate the directory. See that it's still linked. |
| 1606 ASSERT_TRUE(dir()->SaveChanges()); |
| 1607 ASSERT_EQ(syncable::OPENED, ReopenDirectory()); |
| 1608 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id)); |
| 1609 |
| 1610 // Tombstone the second entry, save changes, see that it's truly gone. |
| 1611 ReplaceWithTombstone(syncer::PREFERENCES, tag2); |
| 1612 ASSERT_TRUE(dir()->SaveChanges()); |
| 1613 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag2), |
| 1614 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD); |
| 1615 |
| 1616 // Finally, the attachment is no longer linked. |
| 1617 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id)); |
| 1618 } |
| 1619 |
1524 } // namespace syncable | 1620 } // namespace syncable |
1525 | 1621 |
1526 } // namespace syncer | 1622 } // namespace syncer |
OLD | NEW |