// 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 #include #include #include #include #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/stl_util.h" #include "content/browser/fileapi/sandbox_database_test_helper.h" #include "storage/browser/fileapi/sandbox_origin_database.h" #include "storage/common/fileapi/file_system_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/src/db/filename.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" using storage::SandboxOriginDatabase; namespace content { namespace { const base::FilePath::CharType kFileSystemDirName[] = FILE_PATH_LITERAL("File System"); const base::FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins"); } // namespace TEST(SandboxOriginDatabaseTest, BasicTest) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); SandboxOriginDatabase database(kFSDir, NULL); std::string origin("origin"); EXPECT_FALSE(database.HasOriginPath(origin)); // Double-check to make sure that had no side effects. EXPECT_FALSE(database.HasOriginPath(origin)); base::FilePath path0; base::FilePath path1; // Empty strings aren't valid origins. EXPECT_FALSE(database.GetPathForOrigin(std::string(), &path0)); EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); EXPECT_TRUE(database.HasOriginPath(origin)); EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); EXPECT_FALSE(path0.empty()); EXPECT_FALSE(path1.empty()); EXPECT_EQ(path0, path1); EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName))); } TEST(SandboxOriginDatabaseTest, TwoPathTest) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); SandboxOriginDatabase database(kFSDir, NULL); std::string origin0("origin0"); std::string origin1("origin1"); EXPECT_FALSE(database.HasOriginPath(origin0)); EXPECT_FALSE(database.HasOriginPath(origin1)); base::FilePath path0; base::FilePath path1; EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0)); EXPECT_TRUE(database.HasOriginPath(origin0)); EXPECT_FALSE(database.HasOriginPath(origin1)); EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1)); EXPECT_TRUE(database.HasOriginPath(origin1)); EXPECT_FALSE(path0.empty()); EXPECT_FALSE(path1.empty()); EXPECT_NE(path0, path1); EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName))); } TEST(SandboxOriginDatabaseTest, DropDatabaseTest) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); SandboxOriginDatabase database(kFSDir, NULL); std::string origin("origin"); EXPECT_FALSE(database.HasOriginPath(origin)); base::FilePath path0; EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); EXPECT_TRUE(database.HasOriginPath(origin)); EXPECT_FALSE(path0.empty()); EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName))); database.DropDatabase(); base::FilePath path1; EXPECT_TRUE(database.HasOriginPath(origin)); EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); EXPECT_FALSE(path1.empty()); EXPECT_EQ(path0, path1); } TEST(SandboxOriginDatabaseTest, DeleteOriginTest) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); SandboxOriginDatabase database(kFSDir, NULL); std::string origin("origin"); EXPECT_FALSE(database.HasOriginPath(origin)); EXPECT_TRUE(database.RemovePathForOrigin(origin)); base::FilePath path0; EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); EXPECT_TRUE(database.HasOriginPath(origin)); EXPECT_FALSE(path0.empty()); EXPECT_TRUE(database.RemovePathForOrigin(origin)); EXPECT_FALSE(database.HasOriginPath(origin)); base::FilePath path1; EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); EXPECT_FALSE(path1.empty()); EXPECT_NE(path0, path1); } TEST(SandboxOriginDatabaseTest, ListOriginsTest) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); std::vector origins; SandboxOriginDatabase database(kFSDir, NULL); EXPECT_TRUE(database.ListAllOrigins(&origins)); EXPECT_TRUE(origins.empty()); origins.clear(); std::string origin0("origin0"); std::string origin1("origin1"); EXPECT_FALSE(database.HasOriginPath(origin0)); EXPECT_FALSE(database.HasOriginPath(origin1)); base::FilePath path0; base::FilePath path1; EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0)); EXPECT_TRUE(database.ListAllOrigins(&origins)); EXPECT_EQ(origins.size(), 1UL); EXPECT_EQ(origins[0].origin, origin0); EXPECT_EQ(origins[0].path, path0); origins.clear(); EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1)); EXPECT_TRUE(database.ListAllOrigins(&origins)); EXPECT_EQ(origins.size(), 2UL); if (origins[0].origin == origin0) { EXPECT_EQ(origins[0].path, path0); EXPECT_EQ(origins[1].origin, origin1); EXPECT_EQ(origins[1].path, path1); } else { EXPECT_EQ(origins[0].origin, origin1); EXPECT_EQ(origins[0].path, path1); EXPECT_EQ(origins[1].origin, origin0); EXPECT_EQ(origins[1].path, path0); } } TEST(SandboxOriginDatabaseTest, DatabaseRecoveryTest) { // Checks if SandboxOriginDatabase properly handles database corruption. // In this test, we'll register some origins to the origin database, then // corrupt database and its log file. // After repairing, the origin database should be consistent even when some // entries lost. base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); const base::FilePath kDBDir = kFSDir.Append(kOriginDatabaseName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); const std::string kOrigins[] = { "foo.example.com", "bar.example.com", "baz.example.com", "hoge.example.com", "fuga.example.com", }; scoped_ptr database( new SandboxOriginDatabase(kFSDir, NULL)); for (size_t i = 0; i < arraysize(kOrigins); ++i) { base::FilePath path; EXPECT_FALSE(database->HasOriginPath(kOrigins[i])); EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path)); EXPECT_FALSE(path.empty()); EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path)); if (i != 1) EXPECT_TRUE(base::CreateDirectory(kFSDir.Append(path))); } database.reset(); const base::FilePath kGarbageDir = kFSDir.AppendASCII("foo"); const base::FilePath kGarbageFile = kGarbageDir.AppendASCII("bar"); EXPECT_TRUE(base::CreateDirectory(kGarbageDir)); base::File file(kGarbageFile, base::File::FLAG_CREATE | base::File::FLAG_WRITE); EXPECT_TRUE(file.IsValid()); file.Close(); // Corrupt database itself and last log entry to drop last 1 database // operation. The database should detect the corruption and should recover // its consistency after recovery. CorruptDatabase(kDBDir, leveldb::kDescriptorFile, 0, std::numeric_limits::max()); CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1); base::FilePath path; database.reset(new SandboxOriginDatabase(kFSDir, NULL)); std::vector origins_in_db; EXPECT_TRUE(database->ListAllOrigins(&origins_in_db)); // Expect all but last added origin will be repaired back, and kOrigins[1] // should be dropped due to absence of backing directory. EXPECT_EQ(arraysize(kOrigins) - 2, origins_in_db.size()); const std::string kOrigin("piyo.example.org"); EXPECT_FALSE(database->HasOriginPath(kOrigin)); EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path)); EXPECT_FALSE(path.empty()); EXPECT_TRUE(database->HasOriginPath(kOrigin)); EXPECT_FALSE(base::PathExists(kGarbageFile)); EXPECT_FALSE(base::PathExists(kGarbageDir)); } TEST(SandboxOriginDatabaseTest, DatabaseRecoveryForMissingDBFileTest) { const leveldb::FileType kLevelDBFileTypes[] = { leveldb::kLogFile, leveldb::kDBLockFile, leveldb::kTableFile, leveldb::kDescriptorFile, leveldb::kCurrentFile, leveldb::kTempFile, leveldb::kInfoLogFile, }; for (size_t i = 0; i < arraysize(kLevelDBFileTypes); ++i) { base::ScopedTempDir dir; ASSERT_TRUE(dir.CreateUniqueTempDir()); const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName); const base::FilePath kDBDir = kFSDir.Append(kOriginDatabaseName); EXPECT_FALSE(base::PathExists(kFSDir)); EXPECT_TRUE(base::CreateDirectory(kFSDir)); const std::string kOrigin = "foo.example.com"; base::FilePath path; scoped_ptr database( new SandboxOriginDatabase(kFSDir, NULL)); EXPECT_FALSE(database->HasOriginPath(kOrigin)); EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path)); EXPECT_FALSE(path.empty()); EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path)); EXPECT_TRUE(base::CreateDirectory(kFSDir.Append(path))); database.reset(); DeleteDatabaseFile(kDBDir, kLevelDBFileTypes[i]); database.reset(new SandboxOriginDatabase(kFSDir, NULL)); std::vector origins_in_db; EXPECT_TRUE(database->ListAllOrigins(&origins_in_db)); const std::string kOrigin2("piyo.example.org"); EXPECT_FALSE(database->HasOriginPath(kOrigin2)); EXPECT_TRUE(database->GetPathForOrigin(kOrigin2, &path)); EXPECT_FALSE(path.empty()); EXPECT_TRUE(database->HasOriginPath(kOrigin2)); } } } // namespace content