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_database_test_helper.h" |
| 18 #include "webkit/fileapi/file_system_util.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 having multiple database instances for |
33 // directory at once. | 44 // single 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).NormalizePathSeparators(); |
| 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 = false; |
| 92 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; |
| 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 // Makes link from |parent_id| to |child_id| with |name|. |
| 122 void MakeHierarchyLink(FileId parent_id, |
| 123 FileId child_id, |
| 124 const FilePath::StringType& name) { |
| 125 ASSERT_TRUE(db()->db_->Put( |
| 126 leveldb::WriteOptions(), |
| 127 "CHILD_OF:" + base::Int64ToString(parent_id) + ":" + |
| 128 FilePathToString(FilePath(name)), |
| 129 base::Int64ToString(child_id)).ok()); |
| 130 } |
| 131 |
| 132 // Deletes link from parent of |file_id| to |file_id|. |
| 133 void DeleteHierarchyLink(FileId file_id) { |
| 134 FileInfo file_info; |
| 135 ASSERT_TRUE(db()->GetFileInfo(file_id, &file_info)); |
| 136 ASSERT_TRUE(db()->db_->Delete( |
| 137 leveldb::WriteOptions(), |
| 138 "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" + |
| 139 FilePathToString(FilePath(file_info.name))).ok()); |
| 140 } |
| 141 |
46 protected: | 142 protected: |
47 // Common temp base for nondestructive uses. | 143 // Common temp base for nondestructive uses. |
48 ScopedTempDir base_; | 144 ScopedTempDir base_; |
49 scoped_ptr<FileSystemDirectoryDatabase> db_; | 145 scoped_ptr<FileSystemDirectoryDatabase> db_; |
50 | 146 |
51 DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabaseTest); | 147 DISALLOW_COPY_AND_ASSIGN(FileSystemDirectoryDatabaseTest); |
52 }; | 148 }; |
53 | 149 |
54 TEST_F(FileSystemDirectoryDatabaseTest, TestMissingFileGetInfo) { | 150 TEST_F(FileSystemDirectoryDatabaseTest, TestMissingFileGetInfo) { |
55 FileId file_id = 888; | 151 FileId file_id = 888; |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 | 492 |
397 EXPECT_FALSE(db()->GetFileWithPath(FilePath(info0.name), &check_id)); | 493 EXPECT_FALSE(db()->GetFileWithPath(FilePath(info0.name), &check_id)); |
398 EXPECT_TRUE(db()->GetFileWithPath( | 494 EXPECT_TRUE(db()->GetFileWithPath( |
399 FilePath(dir_info.name).Append(info1.name), &check_id)); | 495 FilePath(dir_info.name).Append(info1.name), &check_id)); |
400 EXPECT_TRUE(db()->GetFileInfo(check_id, &check_info)); | 496 EXPECT_TRUE(db()->GetFileInfo(check_id, &check_info)); |
401 | 497 |
402 EXPECT_EQ(info0.data_path, check_info.data_path); | 498 EXPECT_EQ(info0.data_path, check_info.data_path); |
403 } | 499 } |
404 | 500 |
405 TEST_F(FileSystemDirectoryDatabaseTest, TestGetNextInteger) { | 501 TEST_F(FileSystemDirectoryDatabaseTest, TestGetNextInteger) { |
406 int64 next; | 502 int64 next = -1; |
407 EXPECT_TRUE(db()->GetNextInteger(&next)); | 503 EXPECT_TRUE(db()->GetNextInteger(&next)); |
408 EXPECT_EQ(0, next); | 504 EXPECT_EQ(0, next); |
409 EXPECT_TRUE(db()->GetNextInteger(&next)); | 505 EXPECT_TRUE(db()->GetNextInteger(&next)); |
410 EXPECT_EQ(1, next); | 506 EXPECT_EQ(1, next); |
411 InitDatabase(); | 507 InitDatabase(); |
412 EXPECT_TRUE(db()->GetNextInteger(&next)); | 508 EXPECT_TRUE(db()->GetNextInteger(&next)); |
413 EXPECT_EQ(2, next); | 509 EXPECT_EQ(2, next); |
414 EXPECT_TRUE(db()->GetNextInteger(&next)); | 510 EXPECT_TRUE(db()->GetNextInteger(&next)); |
415 EXPECT_EQ(3, next); | 511 EXPECT_EQ(3, next); |
416 InitDatabase(); | 512 InitDatabase(); |
417 EXPECT_TRUE(db()->GetNextInteger(&next)); | 513 EXPECT_TRUE(db()->GetNextInteger(&next)); |
418 EXPECT_EQ(4, next); | 514 EXPECT_EQ(4, next); |
419 } | 515 } |
420 | 516 |
| 517 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_Empty) { |
| 518 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 519 |
| 520 int64 next = -1; |
| 521 EXPECT_TRUE(db()->GetNextInteger(&next)); |
| 522 EXPECT_EQ(0, next); |
| 523 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 524 } |
| 525 |
| 526 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_Consistent) { |
| 527 FileId dir_id; |
| 528 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); |
| 529 CreateDirectory(0, FPL("bar"), &dir_id); |
| 530 CreateFile(dir_id, FPL("baz"), FPL("fuga"), NULL); |
| 531 CreateFile(dir_id, FPL("fizz"), FPL("buzz"), NULL); |
| 532 |
| 533 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 534 } |
| 535 |
| 536 TEST_F(FileSystemDirectoryDatabaseTest, |
| 537 TestConsistencyCheck_BackingMultiEntry) { |
| 538 const FilePath::CharType kBackingFileName[] = FPL("the celeb"); |
| 539 CreateFile(0, FPL("foo"), kBackingFileName, NULL); |
| 540 |
| 541 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 542 ASSERT_TRUE(file_util::Delete(path().Append(kBackingFileName), false)); |
| 543 CreateFile(0, FPL("bar"), kBackingFileName, NULL); |
| 544 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 545 } |
| 546 |
| 547 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_FileLost) { |
| 548 const FilePath::CharType kBackingFileName[] = FPL("hoge"); |
| 549 CreateFile(0, FPL("foo"), kBackingFileName, NULL); |
| 550 |
| 551 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 552 ASSERT_TRUE(file_util::Delete(path().Append(kBackingFileName), false)); |
| 553 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 554 } |
| 555 |
| 556 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_OrphanFile) { |
| 557 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); |
| 558 |
| 559 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 560 |
| 561 bool created = false; |
| 562 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; |
| 563 base::PlatformFile file = base::CreatePlatformFile( |
| 564 path().Append(FPL("Orphan File")), |
| 565 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, |
| 566 &created, &error); |
| 567 ASSERT_EQ(base::PLATFORM_FILE_OK, error); |
| 568 ASSERT_TRUE(created); |
| 569 ASSERT_TRUE(base::ClosePlatformFile(file)); |
| 570 |
| 571 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 572 } |
| 573 |
| 574 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_RootLoop) { |
| 575 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 576 MakeHierarchyLink(0, 0, FPL("")); |
| 577 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 578 } |
| 579 |
| 580 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_DirectoryLoop) { |
| 581 FileId dir1_id; |
| 582 FileId dir2_id; |
| 583 FilePath::StringType dir1_name = FPL("foo"); |
| 584 CreateDirectory(0, dir1_name, &dir1_id); |
| 585 CreateDirectory(dir1_id, FPL("bar"), &dir2_id); |
| 586 |
| 587 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 588 MakeHierarchyLink(dir2_id, dir1_id, dir1_name); |
| 589 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 590 } |
| 591 |
| 592 TEST_F(FileSystemDirectoryDatabaseTest, TestConsistencyCheck_NameMismatch) { |
| 593 FileId dir_id; |
| 594 FileId file_id; |
| 595 CreateDirectory(0, FPL("foo"), &dir_id); |
| 596 CreateFile(dir_id, FPL("bar"), FPL("hoge/fuga/piyo"), &file_id); |
| 597 |
| 598 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 599 DeleteHierarchyLink(file_id); |
| 600 MakeHierarchyLink(dir_id, 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 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 612 DeleteHierarchyLink(dir2_id); // Delete link from |dir1_id| to |dir2_id|. |
| 613 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 614 } |
| 615 |
| 616 TEST_F(FileSystemDirectoryDatabaseTest, TestRepairDatabase_Success) { |
| 617 FilePath::StringType kFileName = FPL("bar"); |
| 618 |
| 619 FileId file_id_prev; |
| 620 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); |
| 621 CreateFile(0, kFileName, FPL("fuga"), &file_id_prev); |
| 622 |
| 623 const FilePath kDatabaseDirectory = path().Append(kDirectoryDatabaseName); |
| 624 CloseDatabase(); |
| 625 CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, |
| 626 0, std::numeric_limits<size_t>::max()); |
| 627 InitDatabase(); |
| 628 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 629 |
| 630 FileId file_id; |
| 631 EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id)); |
| 632 EXPECT_EQ(file_id_prev, file_id); |
| 633 |
| 634 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 635 } |
| 636 |
| 637 TEST_F(FileSystemDirectoryDatabaseTest, TestRepairDatabase_Failure) { |
| 638 FilePath::StringType kFileName = FPL("bar"); |
| 639 |
| 640 CreateFile(0, FPL("foo"), FPL("hoge"), NULL); |
| 641 CreateFile(0, kFileName, FPL("fuga"), NULL); |
| 642 |
| 643 const FilePath kDatabaseDirectory = path().Append(kDirectoryDatabaseName); |
| 644 CloseDatabase(); |
| 645 CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, |
| 646 0, std::numeric_limits<size_t>::max()); |
| 647 CorruptDatabase(kDatabaseDirectory, leveldb::kLogFile, |
| 648 -1, 1); |
| 649 InitDatabase(); |
| 650 EXPECT_FALSE(db()->IsFileSystemConsistent()); |
| 651 |
| 652 FileId file_id; |
| 653 EXPECT_FALSE(db()->GetChildWithName(0, kFileName, &file_id)); |
| 654 EXPECT_TRUE(db()->IsFileSystemConsistent()); |
| 655 } |
| 656 |
421 } // namespace fileapi | 657 } // namespace fileapi |
OLD | NEW |