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

Side by Side Diff: webkit/fileapi/file_system_directory_database_unittest.cc

Issue 9910005: Add database recovery for FileSystemDirectoryDatabase. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 8 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 (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
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
OLDNEW
« no previous file with comments | « webkit/fileapi/file_system_directory_database.cc ('k') | webkit/fileapi/file_system_origin_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698