Chromium Code Reviews| 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 "webkit/fileapi/file_system_directory_database.h" | 5 #include "webkit/fileapi/file_system_directory_database.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/file_util.h" | |
| 10 #include "base/platform_file.h" | |
| 9 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/scoped_temp_dir.h" | 12 #include "base/scoped_temp_dir.h" |
| 11 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
| 12 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 #include "third_party/leveldatabase/src/include/leveldb/db.h" | |
| 17 #include "webkit/fileapi/file_system_util.h" | |
| 18 #include "webkit/fileapi/file_system_database_test_helper.h" | |
| 19 | |
| 20 #define FPL(x) FILE_PATH_LITERAL(x) | |
| 14 | 21 |
| 15 namespace fileapi { | 22 namespace fileapi { |
| 16 | 23 |
| 24 namespace { | |
| 25 const FilePath::CharType kDirectoryDatabaseName[] = FPL("Paths"); | |
| 26 } | |
| 27 | |
| 17 class FileSystemDirectoryDatabaseTest : public testing::Test { | 28 class FileSystemDirectoryDatabaseTest : public testing::Test { |
| 18 public: | 29 public: |
| 19 typedef FileSystemDirectoryDatabase::FileId FileId; | 30 typedef FileSystemDirectoryDatabase::FileId FileId; |
| 20 typedef FileSystemDirectoryDatabase::FileInfo FileInfo; | 31 typedef FileSystemDirectoryDatabase::FileInfo FileInfo; |
| 21 | 32 |
| 22 FileSystemDirectoryDatabaseTest() { | 33 FileSystemDirectoryDatabaseTest() { |
| 23 EXPECT_TRUE(base_.CreateUniqueTempDir()); | 34 EXPECT_TRUE(base_.CreateUniqueTempDir()); |
| 24 InitDatabase(); | 35 InitDatabase(); |
| 25 } | 36 } |
| 26 | 37 |
| 27 FileSystemDirectoryDatabase* db() { | 38 FileSystemDirectoryDatabase* db() { |
| 28 return db_.get(); | 39 return db_.get(); |
| 29 } | 40 } |
| 30 | 41 |
| 31 void InitDatabase() { | 42 void InitDatabase() { |
| 32 // First reset() is to avoid multiple database instance for single | 43 // Call CloseDatabase() to avoid multiple database instance for single |
| 33 // directory at once. | 44 // directory at once. |
| 45 CloseDatabase(); | |
| 46 db_.reset(new FileSystemDirectoryDatabase(path())); | |
| 47 } | |
| 48 | |
| 49 void CloseDatabase() { | |
| 34 db_.reset(); | 50 db_.reset(); |
| 35 db_.reset(new FileSystemDirectoryDatabase(base_.path())); | |
| 36 } | 51 } |
| 37 | 52 |
| 38 bool AddFileInfo(FileId parent_id, const FilePath::StringType& name) { | 53 bool AddFileInfo(FileId parent_id, const FilePath::StringType& name) { |
| 39 FileId file_id; | 54 FileId file_id; |
| 40 FileInfo info; | 55 FileInfo info; |
| 41 info.parent_id = parent_id; | 56 info.parent_id = parent_id; |
| 42 info.name = name; | 57 info.name = name; |
| 43 return db_->AddFileInfo(info, &file_id); | 58 return db_->AddFileInfo(info, &file_id); |
| 44 } | 59 } |
| 45 | 60 |
| 61 void CreateDirectory(FileId parent_id, | |
| 62 const FilePath::StringType& name, | |
| 63 FileId* file_id_out) { | |
| 64 FileId file_id; | |
| 65 | |
| 66 FileInfo info; | |
| 67 info.parent_id = parent_id; | |
| 68 info.name = name; | |
| 69 ASSERT_TRUE(db_->AddFileInfo(info, &file_id)); | |
| 70 | |
| 71 if (file_id_out) | |
| 72 *file_id_out = file_id; | |
| 73 } | |
| 74 | |
| 75 void CreateFile(FileId parent_id, | |
| 76 const FilePath::StringType& name, | |
| 77 const FilePath::StringType& data_path, | |
| 78 FileId* file_id_out) { | |
| 79 FileId file_id; | |
| 80 | |
| 81 FileInfo info; | |
| 82 info.parent_id = parent_id; | |
| 83 info.name = name; | |
| 84 info.data_path = FilePath(data_path); | |
| 85 ASSERT_TRUE(db_->AddFileInfo(info, &file_id)); | |
| 86 | |
| 87 FilePath local_path = path().Append(data_path); | |
| 88 if (!file_util::DirectoryExists(local_path.DirName())) | |
| 89 ASSERT_TRUE(file_util::CreateDirectory(local_path.DirName())); | |
| 90 | |
| 91 bool created; | |
| 92 base::PlatformFileError error; | |
| 93 base::PlatformFile file = base::CreatePlatformFile( | |
| 94 local_path, | |
| 95 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, | |
| 96 &created, &error); | |
| 97 ASSERT_EQ(base::PLATFORM_FILE_OK, error); | |
| 98 ASSERT_TRUE(created); | |
| 99 ASSERT_TRUE(base::ClosePlatformFile(file)); | |
| 100 | |
| 101 if (file_id_out) | |
| 102 *file_id_out = file_id; | |
| 103 } | |
| 104 | |
| 105 void ClearDatabaseAndDirectory() { | |
| 106 db_.reset(); | |
| 107 ASSERT_TRUE(file_util::Delete(path(), true /* recursive */)); | |
| 108 ASSERT_TRUE(file_util::CreateDirectory(path())); | |
| 109 db_.reset(new FileSystemDirectoryDatabase(path())); | |
| 110 } | |
| 111 | |
| 112 bool RepairDatabase() { | |
| 113 return db()->RepairDatabase( | |
| 114 FilePathToString(path().Append(kDirectoryDatabaseName))); | |
| 115 } | |
| 116 | |
| 117 const FilePath& path() { | |
| 118 return base_.path(); | |
| 119 } | |
| 120 | |
| 121 void MakeHierarchyLink(FileId parent_id, FileId child_id) { | |
| 122 FileInfo file_info; | |
| 123 ASSERT_TRUE(db()->GetFileInfo(child_id, &file_info)); | |
| 124 ASSERT_TRUE(db()->db_->Put( | |
| 125 leveldb::WriteOptions(), | |
| 126 "CHILD_OF:" + base::Int64ToString(parent_id) + ":" + file_info.name, | |
| 127 base::Int64ToString(child_id)).ok()); | |
| 128 } | |
| 129 | |
| 130 void ReplaceHierarchyLinkName(FileId file_id, | |
|
ericu
2012/04/05 00:22:26
This could just use DeleteHierarchyLink and MakeHi
tzik
2012/04/05 05:54:33
Done.
| |
| 131 const FilePath::StringType& new_name) { | |
| 132 FileInfo file_info; | |
| 133 ASSERT_TRUE(db()->GetFileInfo(file_id, &file_info)); | |
| 134 ASSERT_TRUE(db()->db_->Delete( | |
| 135 leveldb::WriteOptions(), | |
| 136 "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" + | |
| 137 file_info.name).ok()); | |
| 138 ASSERT_TRUE(db()->db_->Put( | |
| 139 leveldb::WriteOptions(), | |
| 140 "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" + new_name, | |
| 141 base::Int64ToString(file_id)).ok()); | |
| 142 } | |
| 143 | |
| 144 void DeleteHierarchyLink(FileId file_id) { | |
| 145 FileInfo file_info; | |
| 146 ASSERT_TRUE(db()->GetFileInfo(file_id, &file_info)); | |
| 147 ASSERT_TRUE(db()->db_->Delete( | |
| 148 leveldb::WriteOptions(), | |
| 149 "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" + | |
| 150 file_info.name).ok()); | |
| 151 } | |
| 152 | |
| 46 protected: | 153 protected: |
| 47 // Common temp base for nondestructive uses. | 154 // Common temp base for nondestructive uses. |
| 48 ScopedTempDir base_; | 155 ScopedTempDir base_; |
| 49 scoped_ptr<FileSystemDirectoryDatabase> db_; | 156 scoped_ptr<FileSystemDirectoryDatabase> db_; |
| 50 | 157 |
| 51 DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabaseTest); | 158 DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabaseTest); |
| 52 }; | 159 }; |
| 53 | 160 |
| 54 TEST_F(FileSystemDirectoryDatabaseTest, TestMissingFileGetInfo) { | 161 TEST_F(FileSystemDirectoryDatabaseTest, TestMissingFileGetInfo) { |
| 55 FileId file_id = 888; | 162 FileId file_id = 888; |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 InitDatabase(); | 518 InitDatabase(); |
| 412 EXPECT_TRUE(db()->GetNextInteger(&next)); | 519 EXPECT_TRUE(db()->GetNextInteger(&next)); |
| 413 EXPECT_EQ(2, next); | 520 EXPECT_EQ(2, next); |
| 414 EXPECT_TRUE(db()->GetNextInteger(&next)); | 521 EXPECT_TRUE(db()->GetNextInteger(&next)); |
| 415 EXPECT_EQ(3, next); | 522 EXPECT_EQ(3, next); |
| 416 InitDatabase(); | 523 InitDatabase(); |
| 417 EXPECT_TRUE(db()->GetNextInteger(&next)); | 524 EXPECT_TRUE(db()->GetNextInteger(&next)); |
| 418 EXPECT_EQ(4, next); | 525 EXPECT_EQ(4, next); |
| 419 } | 526 } |
| 420 | 527 |
| 528 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_Empty) { | |
| 529 EXPECT_TRUE(db()->IsFileSystemConsistent()); | |
| 530 | |
| 531 int64 next; | |
| 532 EXPECT_TRUE(db()->GetNextInteger(&next)); | |
| 533 EXPECT_EQ(0, next); | |
| 534 EXPECT_TRUE(db()->IsFileSystemConsistent()); | |
| 535 } | |
| 536 | |
| 537 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_Consistent) { | |
| 538 FileId dir_id; | |
| 539 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | |
| 540 CreateDirectory(0, FPL("bar"), &dir_id); | |
| 541 CreateFile(dir_id, FPL("baz"), FPL("fuga"), NULL); | |
| 542 CreateFile(dir_id, FPL("fizz"), FPL("buzz"), NULL); | |
| 543 | |
| 544 EXPECT_TRUE(db()->IsFileSystemConsistent()); | |
| 545 } | |
| 546 | |
| 547 TEST_F(FileSystemDirectoryDatabaseTest, | |
| 548 TestConsistencyCheck_BackingMultiEntry) { | |
| 549 const FilePath::CharType kBackingFileName[] = FPL("the celeb"); | |
| 550 CreateFile(0, FPL("foo"), kBackingFileName, NULL); | |
| 551 ASSERT_TRUE(file_util::Delete(path().Append(kBackingFileName), false)); | |
| 552 CreateFile(0, FPL("bar"), kBackingFileName, NULL); | |
| 553 | |
| 554 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 555 } | |
| 556 | |
| 557 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_FileLost) { | |
| 558 const FilePath::CharType kBackingFileName[] = FPL("hoge"); | |
| 559 CreateFile(0, FPL("foo"), kBackingFileName, NULL); | |
| 560 ASSERT_TRUE(file_util::Delete(path().Append(kBackingFileName), false)); | |
| 561 | |
| 562 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 563 } | |
| 564 | |
| 565 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_OrphanFile) { | |
| 566 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | |
| 567 | |
| 568 bool created; | |
| 569 base::PlatformFileError error; | |
| 570 base::PlatformFile file = base::CreatePlatformFile( | |
| 571 path().Append("Orphan File"), | |
| 572 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, | |
| 573 &created, &error); | |
| 574 ASSERT_EQ(base::PLATFORM_FILE_OK, error); | |
| 575 ASSERT_TRUE(created); | |
| 576 ASSERT_TRUE(base::ClosePlatformFile(file)); | |
| 577 | |
| 578 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 579 } | |
| 580 | |
| 581 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_RootLoop) { | |
| 582 MakeHierarchyLink(0, 0); | |
| 583 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 584 } | |
| 585 | |
| 586 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_DirectoryLoop) { | |
| 587 FileId dir1_id; | |
| 588 FileId dir2_id; | |
| 589 CreateDirectory(0, FPL("foo"), &dir1_id); | |
| 590 CreateDirectory(dir1_id, FPL("bar"), &dir2_id); | |
| 591 MakeHierarchyLink(dir2_id, dir1_id); | |
| 592 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 593 } | |
| 594 | |
| 595 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_NameMismatch) { | |
| 596 FileId dir_id; | |
| 597 FileId file_id; | |
| 598 CreateDirectory(0, FPL("foo"), &dir_id); | |
| 599 CreateFile(dir_id, FPL("bar"), FPL("hoge/fuga/piyo"), &file_id); | |
| 600 ReplaceHierarchyLinkName(file_id, FPL("baz")); | |
| 601 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 602 } | |
| 603 | |
| 604 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_WreckedEntries) { | |
| 605 FileId dir1_id; | |
| 606 FileId dir2_id; | |
| 607 CreateDirectory(0, FPL("foo"), &dir1_id); | |
| 608 CreateDirectory(dir1_id, FPL("bar"), &dir2_id); | |
| 609 CreateFile(dir2_id, FPL("baz"), FPL("fizz/buzz"), NULL); | |
| 610 | |
| 611 DeleteHierarchyLink(dir2_id); // delete link from |dir1_id| to |dir2_id| | |
|
ericu
2012/04/05 00:22:26
In each of these tests, I think it would be good t
tzik
2012/04/05 05:54:33
Done.
| |
| 612 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 613 } | |
| 614 | |
| 615 TEST_F(FileSystemDirectoryDatabaseTest, TestRepairDatabase_Success) { | |
| 616 FilePath::StringType kFileName = FPL("bar"); | |
| 617 | |
| 618 FileId file_id_prev; | |
| 619 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | |
| 620 CreateFile(0, kFileName, FPL("fuga"), &file_id_prev); | |
| 621 | |
| 622 const FilePath kDatabaseDirectory = path().Append(kDirectoryDatabaseName); | |
| 623 CloseDatabase(); | |
| 624 CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, | |
| 625 0, std::numeric_limits<size_t>::max()); | |
| 626 InitDatabase(); | |
| 627 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 628 | |
| 629 FileId file_id; | |
| 630 EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id)); | |
| 631 EXPECT_EQ(file_id_prev, file_id); | |
| 632 | |
| 633 EXPECT_TRUE(db()->IsFileSystemConsistent()); | |
| 634 } | |
| 635 | |
| 636 TEST_F(FileSystemDirectoryDatabaseTest, TestRepairDatabase_Failure) { | |
| 637 FilePath::StringType kFileName = FPL("bar"); | |
| 638 | |
| 639 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | |
| 640 CreateFile(0, kFileName, FPL("fuga"), NULL); | |
| 641 | |
| 642 const FilePath kDatabaseDirectory = path().Append(kDirectoryDatabaseName); | |
| 643 CloseDatabase(); | |
| 644 CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, | |
| 645 0, std::numeric_limits<size_t>::max()); | |
| 646 CorruptDatabase(kDatabaseDirectory, leveldb::kLogFile, | |
| 647 -1, 1); | |
| 648 InitDatabase(); | |
| 649 EXPECT_FALSE(db()->IsFileSystemConsistent()); | |
| 650 | |
| 651 FileId file_id; | |
| 652 EXPECT_FALSE(db()->GetChildWithName(0, kFileName, &file_id)); | |
| 653 EXPECT_TRUE(db()->IsFileSystemConsistent()); | |
| 654 } | |
| 655 | |
| 421 } // namespace fileapi | 656 } // namespace fileapi |
| OLD | NEW |