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 |