|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "storage/browser/fileapi/sandbox_directory_database.h" | 
|  |  | 
|  | #include <math.h> | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <limits> | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/files/file.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "content/browser/fileapi/sandbox_database_test_helper.h" | 
|  | #include "storage/common/fileapi/file_system_util.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/leveldatabase/src/include/leveldb/db.h" | 
|  |  | 
|  | #define FPL(x) FILE_PATH_LITERAL(x) | 
|  |  | 
|  | using storage::FilePathToString; | 
|  | using storage::SandboxDirectoryDatabase; | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | namespace { | 
|  | const base::FilePath::CharType kDirectoryDatabaseName[] = FPL("Paths"); | 
|  | } | 
|  |  | 
|  | class SandboxDirectoryDatabaseTest : public testing::Test { | 
|  | public: | 
|  | typedef SandboxDirectoryDatabase::FileId FileId; | 
|  | typedef SandboxDirectoryDatabase::FileInfo FileInfo; | 
|  |  | 
|  | SandboxDirectoryDatabaseTest() { | 
|  | EXPECT_TRUE(base_.CreateUniqueTempDir()); | 
|  | InitDatabase(); | 
|  | } | 
|  |  | 
|  | SandboxDirectoryDatabase* db() { | 
|  | return db_.get(); | 
|  | } | 
|  |  | 
|  | void InitDatabase() { | 
|  | // Call CloseDatabase() to avoid having multiple database instances for | 
|  | // single directory at once. | 
|  | CloseDatabase(); | 
|  | db_.reset(new SandboxDirectoryDatabase(path(), NULL)); | 
|  | } | 
|  |  | 
|  | void CloseDatabase() { | 
|  | db_.reset(); | 
|  | } | 
|  |  | 
|  | base::File::Error AddFileInfo( | 
|  | FileId parent_id, const base::FilePath::StringType& name) { | 
|  | FileId file_id; | 
|  | FileInfo info; | 
|  | info.parent_id = parent_id; | 
|  | info.name = name; | 
|  | return db_->AddFileInfo(info, &file_id); | 
|  | } | 
|  |  | 
|  | void CreateDirectory(FileId parent_id, | 
|  | const base::FilePath::StringType& name, | 
|  | FileId* file_id_out) { | 
|  | FileInfo info; | 
|  | info.parent_id = parent_id; | 
|  | info.name = name; | 
|  | ASSERT_EQ(base::File::FILE_OK, db_->AddFileInfo(info, file_id_out)); | 
|  | } | 
|  |  | 
|  | void CreateFile(FileId parent_id, | 
|  | const base::FilePath::StringType& name, | 
|  | const base::FilePath::StringType& data_path, | 
|  | FileId* file_id_out) { | 
|  | FileId file_id; | 
|  |  | 
|  | FileInfo info; | 
|  | info.parent_id = parent_id; | 
|  | info.name = name; | 
|  | info.data_path = base::FilePath(data_path).NormalizePathSeparators(); | 
|  | ASSERT_EQ(base::File::FILE_OK, db_->AddFileInfo(info, &file_id)); | 
|  |  | 
|  | base::FilePath local_path = path().Append(data_path); | 
|  | if (!base::DirectoryExists(local_path.DirName())) | 
|  | ASSERT_TRUE(base::CreateDirectory(local_path.DirName())); | 
|  |  | 
|  | base::File file(local_path, | 
|  | base::File::FLAG_CREATE | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_TRUE(file.created()); | 
|  |  | 
|  | if (file_id_out) | 
|  | *file_id_out = file_id; | 
|  | } | 
|  |  | 
|  | void ClearDatabaseAndDirectory() { | 
|  | db_.reset(); | 
|  | ASSERT_TRUE(base::DeleteFile(path(), true /* recursive */)); | 
|  | ASSERT_TRUE(base::CreateDirectory(path())); | 
|  | db_.reset(new SandboxDirectoryDatabase(path(), NULL)); | 
|  | } | 
|  |  | 
|  | bool RepairDatabase() { | 
|  | return db()->RepairDatabase( | 
|  | FilePathToString(path().Append(kDirectoryDatabaseName))); | 
|  | } | 
|  |  | 
|  | const base::FilePath& path() { return base_.GetPath(); } | 
|  |  | 
|  | // Makes link from |parent_id| to |child_id| with |name|. | 
|  | void MakeHierarchyLink(FileId parent_id, | 
|  | FileId child_id, | 
|  | const base::FilePath::StringType& name) { | 
|  | ASSERT_TRUE(db()->db_->Put( | 
|  | leveldb::WriteOptions(), | 
|  | "CHILD_OF:" + base::Int64ToString(parent_id) + ":" + | 
|  | FilePathToString(base::FilePath(name)), | 
|  | base::Int64ToString(child_id)).ok()); | 
|  | } | 
|  |  | 
|  | // Deletes link from parent of |file_id| to |file_id|. | 
|  | void DeleteHierarchyLink(FileId file_id) { | 
|  | FileInfo file_info; | 
|  | ASSERT_TRUE(db()->GetFileInfo(file_id, &file_info)); | 
|  | ASSERT_TRUE(db()->db_->Delete( | 
|  | leveldb::WriteOptions(), | 
|  | "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" + | 
|  | FilePathToString(base::FilePath(file_info.name))).ok()); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // Common temp base for nondestructive uses. | 
|  | base::ScopedTempDir base_; | 
|  | std::unique_ptr<SandboxDirectoryDatabase> db_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(SandboxDirectoryDatabaseTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestMissingFileGetInfo) { | 
|  | FileId file_id = 888; | 
|  | FileInfo info; | 
|  | EXPECT_FALSE(db()->GetFileInfo(file_id, &info)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestGetRootFileInfoBeforeCreate) { | 
|  | FileId file_id = 0; | 
|  | FileInfo info; | 
|  | EXPECT_TRUE(db()->GetFileInfo(file_id, &info)); | 
|  | EXPECT_EQ(0, info.parent_id); | 
|  | EXPECT_TRUE(info.name.empty()); | 
|  | EXPECT_TRUE(info.data_path.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestMissingParentAddFileInfo) { | 
|  | FileId parent_id = 7; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, | 
|  | AddFileInfo(parent_id, FILE_PATH_LITERAL("foo"))); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestAddNameClash) { | 
|  | FileInfo info; | 
|  | FileId file_id; | 
|  | info.parent_id = 0; | 
|  | info.name = FILE_PATH_LITERAL("dir 0"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id)); | 
|  |  | 
|  | // Check for name clash in the root directory. | 
|  | base::FilePath::StringType name = info.name; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, AddFileInfo(0, name)); | 
|  | name = FILE_PATH_LITERAL("dir 1"); | 
|  | EXPECT_EQ(base::File::FILE_OK, AddFileInfo(0, name)); | 
|  |  | 
|  | name = FILE_PATH_LITERAL("subdir 0"); | 
|  | EXPECT_EQ(base::File::FILE_OK, AddFileInfo(file_id, name)); | 
|  |  | 
|  | // Check for name clash in a subdirectory. | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, AddFileInfo(file_id, name)); | 
|  | name = FILE_PATH_LITERAL("subdir 1"); | 
|  | EXPECT_EQ(base::File::FILE_OK, AddFileInfo(file_id, name)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestRenameNoMoveNameClash) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); | 
|  | base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); | 
|  | base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | EXPECT_EQ(base::File::FILE_OK, AddFileInfo(0, name1)); | 
|  | info.name = name1; | 
|  | EXPECT_FALSE(db()->UpdateFileInfo(file_id0, info)); | 
|  | info.name = name2; | 
|  | EXPECT_TRUE(db()->UpdateFileInfo(file_id0, info)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestMoveSameNameNameClash) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | FileId file_id1; | 
|  | base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); | 
|  | base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | info.parent_id = file_id0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | info.parent_id = 0; | 
|  | EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); | 
|  | info.name = name1; | 
|  | EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestMoveRenameNameClash) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | FileId file_id1; | 
|  | base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); | 
|  | base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); | 
|  | base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | info.parent_id = file_id0; | 
|  | info.name = name1; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); | 
|  | info.name = name1; | 
|  | EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); | 
|  | // Also test a successful move+rename. | 
|  | info.parent_id = file_id0; | 
|  | info.name = name2; | 
|  | EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestRemoveWithChildren) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | FileId file_id1; | 
|  | info.parent_id = 0; | 
|  | info.name = FILE_PATH_LITERAL("foo"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | info.parent_id = file_id0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | EXPECT_FALSE(db()->RemoveFileInfo(file_id0)); | 
|  | EXPECT_TRUE(db()->RemoveFileInfo(file_id1)); | 
|  | EXPECT_TRUE(db()->RemoveFileInfo(file_id0)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestGetChildWithName) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | FileId file_id1; | 
|  | base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); | 
|  | base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | info.parent_id = file_id0; | 
|  | info.name = name1; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | EXPECT_NE(file_id0, file_id1); | 
|  |  | 
|  | FileId check_file_id; | 
|  | EXPECT_FALSE(db()->GetChildWithName(0, name1, &check_file_id)); | 
|  | EXPECT_TRUE(db()->GetChildWithName(0, name0, &check_file_id)); | 
|  | EXPECT_EQ(file_id0, check_file_id); | 
|  | EXPECT_FALSE(db()->GetChildWithName(file_id0, name0, &check_file_id)); | 
|  | EXPECT_TRUE(db()->GetChildWithName(file_id0, name1, &check_file_id)); | 
|  | EXPECT_EQ(file_id1, check_file_id); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestGetFileWithPath) { | 
|  | FileInfo info; | 
|  | FileId file_id0; | 
|  | FileId file_id1; | 
|  | FileId file_id2; | 
|  | base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo"); | 
|  | base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); | 
|  | base::FilePath::StringType name2 = FILE_PATH_LITERAL("dog"); | 
|  |  | 
|  | info.parent_id = 0; | 
|  | info.name = name0; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | info.parent_id = file_id0; | 
|  | info.name = name1; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | EXPECT_NE(file_id0, file_id1); | 
|  | info.parent_id = file_id1; | 
|  | info.name = name2; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id2)); | 
|  | EXPECT_NE(file_id0, file_id2); | 
|  | EXPECT_NE(file_id1, file_id2); | 
|  |  | 
|  | FileId check_file_id; | 
|  | base::FilePath path = base::FilePath(name0); | 
|  | EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); | 
|  | EXPECT_EQ(file_id0, check_file_id); | 
|  |  | 
|  | path = path.Append(name1); | 
|  | EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); | 
|  | EXPECT_EQ(file_id1, check_file_id); | 
|  |  | 
|  | path = path.Append(name2); | 
|  | EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id)); | 
|  | EXPECT_EQ(file_id2, check_file_id); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestListChildren) { | 
|  | // No children in the root. | 
|  | std::vector<FileId> children; | 
|  | EXPECT_TRUE(db()->ListChildren(0, &children)); | 
|  | EXPECT_TRUE(children.empty()); | 
|  |  | 
|  | // One child in the root. | 
|  | FileId file_id0; | 
|  | FileInfo info; | 
|  | info.parent_id = 0; | 
|  | info.name = FILE_PATH_LITERAL("foo"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0)); | 
|  | EXPECT_TRUE(db()->ListChildren(0, &children)); | 
|  | EXPECT_EQ(children.size(), 1UL); | 
|  | EXPECT_EQ(children[0], file_id0); | 
|  |  | 
|  | // Two children in the root. | 
|  | FileId file_id1; | 
|  | info.name = FILE_PATH_LITERAL("bar"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1)); | 
|  | EXPECT_TRUE(db()->ListChildren(0, &children)); | 
|  | EXPECT_EQ(2UL, children.size()); | 
|  | if (children[0] == file_id0) { | 
|  | EXPECT_EQ(children[1], file_id1); | 
|  | } else { | 
|  | EXPECT_EQ(children[1], file_id0); | 
|  | EXPECT_EQ(children[0], file_id1); | 
|  | } | 
|  |  | 
|  | // No children in a subdirectory. | 
|  | EXPECT_TRUE(db()->ListChildren(file_id0, &children)); | 
|  | EXPECT_TRUE(children.empty()); | 
|  |  | 
|  | // One child in a subdirectory. | 
|  | info.parent_id = file_id0; | 
|  | info.name = FILE_PATH_LITERAL("foo"); | 
|  | FileId file_id2; | 
|  | FileId file_id3; | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id2)); | 
|  | EXPECT_TRUE(db()->ListChildren(file_id0, &children)); | 
|  | EXPECT_EQ(1UL, children.size()); | 
|  | EXPECT_EQ(children[0], file_id2); | 
|  |  | 
|  | // Two children in a subdirectory. | 
|  | info.name = FILE_PATH_LITERAL("bar"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id3)); | 
|  | EXPECT_TRUE(db()->ListChildren(file_id0, &children)); | 
|  | EXPECT_EQ(2UL, children.size()); | 
|  | if (children[0] == file_id2) { | 
|  | EXPECT_EQ(children[1], file_id3); | 
|  | } else { | 
|  | EXPECT_EQ(children[1], file_id2); | 
|  | EXPECT_EQ(children[0], file_id3); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestUpdateModificationTime) { | 
|  | FileInfo info0; | 
|  | FileId file_id; | 
|  | info0.parent_id = 0; | 
|  | info0.name = FILE_PATH_LITERAL("name"); | 
|  | info0.data_path = base::FilePath(FILE_PATH_LITERAL("fake path")); | 
|  | info0.modification_time = base::Time::Now(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id)); | 
|  | FileInfo info1; | 
|  | EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); | 
|  | EXPECT_EQ(info0.name, info1.name); | 
|  | EXPECT_EQ(info0.parent_id, info1.parent_id); | 
|  | EXPECT_EQ(info0.data_path, info1.data_path); | 
|  | EXPECT_EQ( | 
|  | floor(info0.modification_time.ToDoubleT()), | 
|  | info1.modification_time.ToDoubleT()); | 
|  |  | 
|  | EXPECT_TRUE(db()->UpdateModificationTime(file_id, base::Time::UnixEpoch())); | 
|  | EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); | 
|  | EXPECT_EQ(info0.name, info1.name); | 
|  | EXPECT_EQ(info0.parent_id, info1.parent_id); | 
|  | EXPECT_EQ(info0.data_path, info1.data_path); | 
|  | EXPECT_NE(info0.modification_time, info1.modification_time); | 
|  | EXPECT_EQ( | 
|  | info1.modification_time.ToDoubleT(), | 
|  | floor(base::Time::UnixEpoch().ToDoubleT())); | 
|  |  | 
|  | EXPECT_FALSE(db()->UpdateModificationTime(999, base::Time::UnixEpoch())); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestSimpleFileOperations) { | 
|  | FileId file_id = 888; | 
|  | FileInfo info0; | 
|  | EXPECT_FALSE(db()->GetFileInfo(file_id, &info0)); | 
|  | info0.parent_id = 0; | 
|  | info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo")); | 
|  | info0.name = FILE_PATH_LITERAL("file name"); | 
|  | info0.modification_time = base::Time::Now(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id)); | 
|  | FileInfo info1; | 
|  | EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); | 
|  | EXPECT_EQ(info0.parent_id, info1.parent_id); | 
|  | EXPECT_EQ(info0.data_path, info1.data_path); | 
|  | EXPECT_EQ(info0.name, info1.name); | 
|  | EXPECT_EQ( | 
|  | floor(info0.modification_time.ToDoubleT()), | 
|  | info1.modification_time.ToDoubleT()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSrcDirectory) { | 
|  | FileId directory_id; | 
|  | FileInfo info0; | 
|  | info0.parent_id = 0; | 
|  | info0.name = FILE_PATH_LITERAL("directory"); | 
|  | info0.modification_time = base::Time::Now(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &directory_id)); | 
|  |  | 
|  | FileId file_id; | 
|  | FileInfo info1; | 
|  | info1.parent_id = 0; | 
|  | info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); | 
|  | info1.name = FILE_PATH_LITERAL("file"); | 
|  | info1.modification_time = base::Time::UnixEpoch(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &file_id)); | 
|  |  | 
|  | EXPECT_FALSE(db()->OverwritingMoveFile(directory_id, file_id)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileDestDirectory) { | 
|  | FileId file_id; | 
|  | FileInfo info0; | 
|  | info0.parent_id = 0; | 
|  | info0.name = FILE_PATH_LITERAL("file"); | 
|  | info0.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); | 
|  | info0.modification_time = base::Time::Now(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id)); | 
|  |  | 
|  | FileId directory_id; | 
|  | FileInfo info1; | 
|  | info1.parent_id = 0; | 
|  | info1.name = FILE_PATH_LITERAL("directory"); | 
|  | info1.modification_time = base::Time::UnixEpoch(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &directory_id)); | 
|  |  | 
|  | EXPECT_FALSE(db()->OverwritingMoveFile(file_id, directory_id)); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSuccess) { | 
|  | FileId file_id0; | 
|  | FileInfo info0; | 
|  | info0.parent_id = 0; | 
|  | info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo")); | 
|  | info0.name = FILE_PATH_LITERAL("file name 0"); | 
|  | info0.modification_time = base::Time::Now(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id0)); | 
|  |  | 
|  | FileInfo dir_info; | 
|  | FileId dir_id; | 
|  | dir_info.parent_id = 0; | 
|  | dir_info.name = FILE_PATH_LITERAL("directory name"); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(dir_info, &dir_id)); | 
|  |  | 
|  | FileId file_id1; | 
|  | FileInfo info1; | 
|  | info1.parent_id = dir_id; | 
|  | info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); | 
|  | info1.name = FILE_PATH_LITERAL("file name 1"); | 
|  | info1.modification_time = base::Time::UnixEpoch(); | 
|  | EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &file_id1)); | 
|  |  | 
|  | EXPECT_TRUE(db()->OverwritingMoveFile(file_id0, file_id1)); | 
|  |  | 
|  | FileInfo check_info; | 
|  | FileId check_id; | 
|  |  | 
|  | EXPECT_FALSE(db()->GetFileWithPath(base::FilePath(info0.name), &check_id)); | 
|  | EXPECT_TRUE(db()->GetFileWithPath( | 
|  | base::FilePath(dir_info.name).Append(info1.name), &check_id)); | 
|  | EXPECT_TRUE(db()->GetFileInfo(check_id, &check_info)); | 
|  |  | 
|  | EXPECT_EQ(info0.data_path, check_info.data_path); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestGetNextInteger) { | 
|  | int64_t next = -1; | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(0, next); | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(1, next); | 
|  | InitDatabase(); | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(2, next); | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(3, next); | 
|  | InitDatabase(); | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(4, next); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_Empty) { | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  |  | 
|  | int64_t next = -1; | 
|  | EXPECT_TRUE(db()->GetNextInteger(&next)); | 
|  | EXPECT_EQ(0, next); | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_Consistent) { | 
|  | FileId dir_id; | 
|  | CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | 
|  | CreateDirectory(0, FPL("bar"), &dir_id); | 
|  | CreateFile(dir_id, FPL("baz"), FPL("fuga"), NULL); | 
|  | CreateFile(dir_id, FPL("fizz"), FPL("buzz"), NULL); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, | 
|  | TestConsistencyCheck_BackingMultiEntry) { | 
|  | const base::FilePath::CharType kBackingFileName[] = FPL("the celeb"); | 
|  | CreateFile(0, FPL("foo"), kBackingFileName, NULL); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false)); | 
|  | CreateFile(0, FPL("bar"), kBackingFileName, NULL); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_FileLost) { | 
|  | const base::FilePath::CharType kBackingFileName[] = FPL("hoge"); | 
|  | CreateFile(0, FPL("foo"), kBackingFileName, NULL); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false)); | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_OrphanFile) { | 
|  | CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  |  | 
|  | base::File file(path().Append(FPL("Orphan File")), | 
|  | base::File::FLAG_CREATE | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_TRUE(file.created()); | 
|  | file.Close(); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_RootLoop) { | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | MakeHierarchyLink(0, 0, base::FilePath::StringType()); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_DirectoryLoop) { | 
|  | FileId dir1_id; | 
|  | FileId dir2_id; | 
|  | base::FilePath::StringType dir1_name = FPL("foo"); | 
|  | CreateDirectory(0, dir1_name, &dir1_id); | 
|  | CreateDirectory(dir1_id, FPL("bar"), &dir2_id); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | MakeHierarchyLink(dir2_id, dir1_id, dir1_name); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_NameMismatch) { | 
|  | FileId dir_id; | 
|  | FileId file_id; | 
|  | CreateDirectory(0, FPL("foo"), &dir_id); | 
|  | CreateFile(dir_id, FPL("bar"), FPL("hoge/fuga/piyo"), &file_id); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | DeleteHierarchyLink(file_id); | 
|  | MakeHierarchyLink(dir_id, file_id, FPL("baz")); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_WreckedEntries) { | 
|  | FileId dir1_id; | 
|  | FileId dir2_id; | 
|  | CreateDirectory(0, FPL("foo"), &dir1_id); | 
|  | CreateDirectory(dir1_id, FPL("bar"), &dir2_id); | 
|  | CreateFile(dir2_id, FPL("baz"), FPL("fizz/buzz"), NULL); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | DeleteHierarchyLink(dir2_id);  // Delete link from |dir1_id| to |dir2_id|. | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_Success) { | 
|  | base::FilePath::StringType kFileName = FPL("bar"); | 
|  |  | 
|  | FileId file_id_prev; | 
|  | CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | 
|  | CreateFile(0, kFileName, FPL("fuga"), &file_id_prev); | 
|  |  | 
|  | const base::FilePath kDatabaseDirectory = | 
|  | path().Append(kDirectoryDatabaseName); | 
|  | CloseDatabase(); | 
|  | CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, | 
|  | 0, std::numeric_limits<size_t>::max()); | 
|  | InitDatabase(); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  |  | 
|  | FileId file_id; | 
|  | EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id)); | 
|  | EXPECT_EQ(file_id_prev, file_id); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_Failure) { | 
|  | base::FilePath::StringType kFileName = FPL("bar"); | 
|  |  | 
|  | CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | 
|  | CreateFile(0, kFileName, FPL("fuga"), NULL); | 
|  |  | 
|  | const base::FilePath kDatabaseDirectory = | 
|  | path().Append(kDirectoryDatabaseName); | 
|  | CloseDatabase(); | 
|  | CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile, | 
|  | 0, std::numeric_limits<size_t>::max()); | 
|  | CorruptDatabase(kDatabaseDirectory, leveldb::kLogFile, | 
|  | -1, 1); | 
|  | InitDatabase(); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  |  | 
|  | FileId file_id; | 
|  | EXPECT_FALSE(db()->GetChildWithName(0, kFileName, &file_id)); | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_MissingManifest) { | 
|  | base::FilePath::StringType kFileName = FPL("bar"); | 
|  |  | 
|  | FileId file_id_prev; | 
|  | CreateFile(0, FPL("foo"), FPL("hoge"), NULL); | 
|  | CreateFile(0, kFileName, FPL("fuga"), &file_id_prev); | 
|  |  | 
|  | const base::FilePath kDatabaseDirectory = | 
|  | path().Append(kDirectoryDatabaseName); | 
|  | CloseDatabase(); | 
|  |  | 
|  | DeleteDatabaseFile(kDatabaseDirectory, leveldb::kDescriptorFile); | 
|  |  | 
|  | InitDatabase(); | 
|  | EXPECT_FALSE(db()->IsFileSystemConsistent()); | 
|  |  | 
|  | FileId file_id; | 
|  | EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id)); | 
|  | EXPECT_EQ(file_id_prev, file_id); | 
|  |  | 
|  | EXPECT_TRUE(db()->IsFileSystemConsistent()); | 
|  | } | 
|  |  | 
|  | }  // namespace content |