blob: 50aa92c9d05cdd7ee5375e14d78aa879a821b7e2 [file] [log] [blame]
// 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 <memory>
#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 "storage/browser/fileapi/sandbox_origin_database.h"
#include "storage/browser/test/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/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.GetPath().Append(kFileSystemDirName);
EXPECT_FALSE(base::PathExists(kFSDir));
EXPECT_TRUE(base::CreateDirectory(kFSDir));
SandboxOriginDatabase database(kFSDir, nullptr);
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.GetPath().Append(kFileSystemDirName);
EXPECT_FALSE(base::PathExists(kFSDir));
EXPECT_TRUE(base::CreateDirectory(kFSDir));
SandboxOriginDatabase database(kFSDir, nullptr);
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.GetPath().Append(kFileSystemDirName);
EXPECT_FALSE(base::PathExists(kFSDir));
EXPECT_TRUE(base::CreateDirectory(kFSDir));
SandboxOriginDatabase database(kFSDir, nullptr);
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.GetPath().Append(kFileSystemDirName);
EXPECT_FALSE(base::PathExists(kFSDir));
EXPECT_TRUE(base::CreateDirectory(kFSDir));
SandboxOriginDatabase database(kFSDir, nullptr);
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.GetPath().Append(kFileSystemDirName);
EXPECT_FALSE(base::PathExists(kFSDir));
EXPECT_TRUE(base::CreateDirectory(kFSDir));
std::vector<SandboxOriginDatabase::OriginRecord> origins;
SandboxOriginDatabase database(kFSDir, nullptr);
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.GetPath().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",
};
std::unique_ptr<SandboxOriginDatabase> database(
new SandboxOriginDatabase(kFSDir, nullptr));
for (size_t i = 0; i < base::size(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, nullptr));
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(base::size(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 (const auto& file_type : kLevelDBFileTypes) {
base::ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir());
const base::FilePath kFSDir = dir.GetPath().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;
std::unique_ptr<SandboxOriginDatabase> database(
new SandboxOriginDatabase(kFSDir, nullptr));
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, file_type);
database.reset(new SandboxOriginDatabase(kFSDir, nullptr));
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