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 "sync/syncable/syncable.h" | 5 #include "sync/syncable/syncable.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 | 422 |
423 virtual void SetUp() { | 423 virtual void SetUp() { |
424 dir_.reset(new Directory(&encryptor_, &handler_, NULL)); | 424 dir_.reset(new Directory(&encryptor_, &handler_, NULL)); |
425 ASSERT_TRUE(dir_.get()); | 425 ASSERT_TRUE(dir_.get()); |
426 ASSERT_EQ(OPENED, dir_->OpenInMemoryForTest(kName, &delegate_, | 426 ASSERT_EQ(OPENED, dir_->OpenInMemoryForTest(kName, &delegate_, |
427 NullTransactionObserver())); | 427 NullTransactionObserver())); |
428 ASSERT_TRUE(dir_->good()); | 428 ASSERT_TRUE(dir_->good()); |
429 } | 429 } |
430 | 430 |
431 virtual void TearDown() { | 431 virtual void TearDown() { |
432 dir_->SaveChanges(); | 432 if (dir_.get()) |
| 433 dir_->SaveChanges(); |
433 dir_.reset(); | 434 dir_.reset(); |
434 } | 435 } |
435 | 436 |
436 void GetAllMetaHandles(BaseTransaction* trans, MetahandleSet* result) { | 437 void GetAllMetaHandles(BaseTransaction* trans, MetahandleSet* result) { |
437 dir_->GetAllMetaHandles(trans, result); | 438 dir_->GetAllMetaHandles(trans, result); |
438 } | 439 } |
439 | 440 |
440 bool IsInDirtyMetahandles(int64 metahandle) { | 441 bool IsInDirtyMetahandles(int64 metahandle) { |
441 return 1 == dir_->kernel_->dirty_metahandles->count(metahandle); | 442 return 1 == dir_->kernel_->dirty_metahandles->count(metahandle); |
442 } | 443 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 me.Put(IS_UNSYNCED, true); | 502 me.Put(IS_UNSYNCED, true); |
502 } | 503 } |
503 | 504 |
504 void ValidateEntry(BaseTransaction* trans, | 505 void ValidateEntry(BaseTransaction* trans, |
505 int64 id, | 506 int64 id, |
506 bool check_name, | 507 bool check_name, |
507 const std::string& name, | 508 const std::string& name, |
508 int64 base_version, | 509 int64 base_version, |
509 int64 server_version, | 510 int64 server_version, |
510 bool is_del); | 511 bool is_del); |
| 512 |
| 513 // When a directory is saved then loaded from disk, it will pass through |
| 514 // DropDeletedEntries(). This will remove some entries from the directory. |
| 515 // This function is intended to simulate that process. |
| 516 // |
| 517 // WARNING: The directory will be deleted by this operation. You should |
| 518 // not have any pointers to the directory (open transactions included) |
| 519 // when you call this. |
| 520 DirOpenResult SimulateSaveAndReloadDir(); |
511 }; | 521 }; |
512 | 522 |
513 TEST_F(SyncableDirectoryTest, TakeSnapshotGetsMetahandlesToPurge) { | 523 TEST_F(SyncableDirectoryTest, TakeSnapshotGetsMetahandlesToPurge) { |
514 const int metas_to_create = 50; | 524 const int metas_to_create = 50; |
515 MetahandleSet expected_purges; | 525 MetahandleSet expected_purges; |
516 MetahandleSet all_handles; | 526 MetahandleSet all_handles; |
517 { | 527 { |
518 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); | 528 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
519 for (int i = 0; i < metas_to_create; i++) { | 529 for (int i = 0; i < metas_to_create; i++) { |
520 MutableEntry e(&trans, CREATE, trans.root_id(), "foo"); | 530 MutableEntry e(&trans, CREATE, trans.root_id(), "foo"); |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1147 | 1157 |
1148 browser_sync::SyncEntity item_entity; | 1158 browser_sync::SyncEntity item_entity; |
1149 item_entity.set_id(id_factory.NewServerId()); | 1159 item_entity.set_id(id_factory.NewServerId()); |
1150 item_entity.set_deleted(false); | 1160 item_entity.set_deleted(false); |
1151 item_entity.set_folder(false); | 1161 item_entity.set_folder(false); |
1152 item_entity.mutable_specifics()->CopyFrom(specifics); | 1162 item_entity.mutable_specifics()->CopyFrom(specifics); |
1153 ASSERT_EQ(datatype, item_entity.GetModelType()); | 1163 ASSERT_EQ(datatype, item_entity.GetModelType()); |
1154 } | 1164 } |
1155 } | 1165 } |
1156 | 1166 |
| 1167 // A test that roughly mimics the directory interaction that occurs when a |
| 1168 // bookmark folder and entry are created then synced for the first time. It is |
| 1169 // a more common variant of the 'DeletedAndUnsyncedChild' scenario tested below. |
| 1170 TEST_F(SyncableDirectoryTest, ChangeEntryIDAndUpdateChildren_ParentAndChild) { |
| 1171 TestIdFactory id_factory; |
| 1172 Id orig_parent_id; |
| 1173 Id orig_child_id; |
| 1174 |
| 1175 { |
| 1176 // Create two client-side items, a parent and child. |
| 1177 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
| 1178 |
| 1179 MutableEntry parent(&trans, CREATE, id_factory.root(), "parent"); |
| 1180 parent.Put(IS_DIR, true); |
| 1181 parent.Put(IS_UNSYNCED, true); |
| 1182 |
| 1183 MutableEntry child(&trans, CREATE, parent.Get(ID), "child"); |
| 1184 child.Put(IS_UNSYNCED, true); |
| 1185 |
| 1186 orig_parent_id = parent.Get(ID); |
| 1187 orig_child_id = child.Get(ID); |
| 1188 } |
| 1189 |
| 1190 { |
| 1191 // Simulate what happens after committing two items. Their IDs will be |
| 1192 // replaced with server IDs. The child is renamed first, then the parent. |
| 1193 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
| 1194 |
| 1195 MutableEntry parent(&trans, GET_BY_ID, orig_parent_id); |
| 1196 MutableEntry child(&trans, GET_BY_ID, orig_child_id); |
| 1197 |
| 1198 ChangeEntryIDAndUpdateChildren(&trans, &child, id_factory.NewServerId()); |
| 1199 child.Put(IS_UNSYNCED, false); |
| 1200 child.Put(BASE_VERSION, 1); |
| 1201 child.Put(SERVER_VERSION, 1); |
| 1202 |
| 1203 ChangeEntryIDAndUpdateChildren(&trans, &parent, id_factory.NewServerId()); |
| 1204 parent.Put(IS_UNSYNCED, false); |
| 1205 parent.Put(BASE_VERSION, 1); |
| 1206 parent.Put(SERVER_VERSION, 1); |
| 1207 } |
| 1208 |
| 1209 // Final check for validity. |
| 1210 EXPECT_EQ(OPENED, SimulateSaveAndReloadDir()); |
| 1211 } |
| 1212 |
| 1213 // A test based on the scenario where we create a bookmark folder and entry |
| 1214 // locally, but with a twist. In this case, the bookmark is deleted before we |
| 1215 // are able to sync either it or its parent folder. This scenario used to cause |
| 1216 // directory corruption, see crbug.com/125381. |
| 1217 TEST_F(SyncableDirectoryTest, |
| 1218 ChangeEntryIDAndUpdateChildren_DeletedAndUnsyncedChild) { |
| 1219 TestIdFactory id_factory; |
| 1220 Id orig_parent_id; |
| 1221 Id orig_child_id; |
| 1222 |
| 1223 { |
| 1224 // Create two client-side items, a parent and child. |
| 1225 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
| 1226 |
| 1227 MutableEntry parent(&trans, CREATE, id_factory.root(), "parent"); |
| 1228 parent.Put(IS_DIR, true); |
| 1229 parent.Put(IS_UNSYNCED, true); |
| 1230 |
| 1231 MutableEntry child(&trans, CREATE, parent.Get(ID), "child"); |
| 1232 child.Put(IS_UNSYNCED, true); |
| 1233 |
| 1234 orig_parent_id = parent.Get(ID); |
| 1235 orig_child_id = child.Get(ID); |
| 1236 } |
| 1237 |
| 1238 { |
| 1239 // Delete the child. |
| 1240 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
| 1241 |
| 1242 MutableEntry child(&trans, GET_BY_ID, orig_child_id); |
| 1243 child.Put(IS_DEL, true); |
| 1244 } |
| 1245 |
| 1246 { |
| 1247 // Simulate what happens after committing the parent. Its ID will be |
| 1248 // replaced with server a ID. |
| 1249 WriteTransaction trans(FROM_HERE, UNITTEST, dir_.get()); |
| 1250 |
| 1251 MutableEntry parent(&trans, GET_BY_ID, orig_parent_id); |
| 1252 |
| 1253 ChangeEntryIDAndUpdateChildren(&trans, &parent, id_factory.NewServerId()); |
| 1254 parent.Put(IS_UNSYNCED, false); |
| 1255 parent.Put(BASE_VERSION, 1); |
| 1256 parent.Put(SERVER_VERSION, 1); |
| 1257 } |
| 1258 |
| 1259 // Final check for validity. |
| 1260 EXPECT_EQ(OPENED, SimulateSaveAndReloadDir()); |
| 1261 } |
| 1262 |
1157 // A variant of SyncableDirectoryTest that uses a real sqlite database. | 1263 // A variant of SyncableDirectoryTest that uses a real sqlite database. |
1158 class OnDiskSyncableDirectoryTest : public SyncableDirectoryTest { | 1264 class OnDiskSyncableDirectoryTest : public SyncableDirectoryTest { |
1159 protected: | 1265 protected: |
1160 // SetUp() is called before each test case is run. | 1266 // SetUp() is called before each test case is run. |
1161 // The sqlite3 DB is deleted before each test is run. | 1267 // The sqlite3 DB is deleted before each test is run. |
1162 virtual void SetUp() { | 1268 virtual void SetUp() { |
1163 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 1269 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
1164 file_path_ = temp_dir_.path().Append( | 1270 file_path_ = temp_dir_.path().Append( |
1165 FILE_PATH_LITERAL("Test.sqlite3")); | 1271 FILE_PATH_LITERAL("Test.sqlite3")); |
1166 file_util::Delete(file_path_, true); | 1272 file_util::Delete(file_path_, true); |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1529 bool is_del) { | 1635 bool is_del) { |
1530 Entry e(trans, GET_BY_ID, TestIdFactory::FromNumber(id)); | 1636 Entry e(trans, GET_BY_ID, TestIdFactory::FromNumber(id)); |
1531 ASSERT_TRUE(e.good()); | 1637 ASSERT_TRUE(e.good()); |
1532 if (check_name) | 1638 if (check_name) |
1533 ASSERT_TRUE(name == e.Get(NON_UNIQUE_NAME)); | 1639 ASSERT_TRUE(name == e.Get(NON_UNIQUE_NAME)); |
1534 ASSERT_TRUE(base_version == e.Get(BASE_VERSION)); | 1640 ASSERT_TRUE(base_version == e.Get(BASE_VERSION)); |
1535 ASSERT_TRUE(server_version == e.Get(SERVER_VERSION)); | 1641 ASSERT_TRUE(server_version == e.Get(SERVER_VERSION)); |
1536 ASSERT_TRUE(is_del == e.Get(IS_DEL)); | 1642 ASSERT_TRUE(is_del == e.Get(IS_DEL)); |
1537 } | 1643 } |
1538 | 1644 |
| 1645 DirOpenResult SyncableDirectoryTest::SimulateSaveAndReloadDir() { |
| 1646 if (!dir_->SaveChanges()) |
| 1647 return FAILED_IN_UNITTEST; |
| 1648 |
| 1649 // Do some tricky things to preserve the backing store. |
| 1650 DirectoryBackingStore* saved_store = dir_->store_; |
| 1651 dir_->store_ = NULL; |
| 1652 |
| 1653 // Close the current directory. |
| 1654 dir_->Close(); |
| 1655 dir_.reset(); |
| 1656 |
| 1657 dir_.reset(new Directory(&encryptor_, &handler_, NULL)); |
| 1658 if (!dir_.get()) |
| 1659 return FAILED_IN_UNITTEST; |
| 1660 DirOpenResult result = dir_->OpenImpl(saved_store, kName, &delegate_, |
| 1661 NullTransactionObserver()); |
| 1662 |
| 1663 // If something went wrong, we need to clear this member. If we don't, |
| 1664 // TearDown() will be guaranteed to crash when it calls SaveChanges(). |
| 1665 if (result != OPENED) |
| 1666 dir_.reset(); |
| 1667 |
| 1668 return result; |
| 1669 } |
| 1670 |
1539 namespace { | 1671 namespace { |
1540 | 1672 |
1541 class SyncableDirectoryManagement : public testing::Test { | 1673 class SyncableDirectoryManagement : public testing::Test { |
1542 public: | 1674 public: |
1543 virtual void SetUp() { | 1675 virtual void SetUp() { |
1544 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 1676 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
1545 } | 1677 } |
1546 | 1678 |
1547 virtual void TearDown() { | 1679 virtual void TearDown() { |
1548 } | 1680 } |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1732 TEST_F(SyncableClientTagTest, TestClientTagIndexDuplicateServer) { | 1864 TEST_F(SyncableClientTagTest, TestClientTagIndexDuplicateServer) { |
1733 EXPECT_TRUE(CreateWithDefaultTag(factory_.NewServerId(), true)); | 1865 EXPECT_TRUE(CreateWithDefaultTag(factory_.NewServerId(), true)); |
1734 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewServerId(), true)); | 1866 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewServerId(), true)); |
1735 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewServerId(), false)); | 1867 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewServerId(), false)); |
1736 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewLocalId(), false)); | 1868 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewLocalId(), false)); |
1737 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewLocalId(), true)); | 1869 EXPECT_FALSE(CreateWithDefaultTag(factory_.NewLocalId(), true)); |
1738 } | 1870 } |
1739 | 1871 |
1740 } // namespace | 1872 } // namespace |
1741 } // namespace syncable | 1873 } // namespace syncable |
OLD | NEW |