| // 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 <stddef.h> |
| |
| #include <algorithm> |
| #include <functional> |
| #include <limits> |
| #include <string> |
| #include <vector> |
| |
| #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/macros.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<SandboxOriginDatabase::OriginRecord> 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<SandboxOriginDatabase> 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<size_t>::max()); |
| CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1); |
| |
| base::FilePath path; |
| database.reset(new SandboxOriginDatabase(kFSDir, NULL)); |
| std::vector<SandboxOriginDatabase::OriginRecord> 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<SandboxOriginDatabase> 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<SandboxOriginDatabase::OriginRecord> 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 |