Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(692)

Side by Side Diff: sync/syncable/directory_unittest.cc

Issue 247983002: Keep track of which attachments are referenced by which sync entries. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: FakeAttachmentService::StoreAttachments now calls AttachmentStore::Write. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698