| Index: webkit/fileapi/file_system_origin_database_unittest.cc
|
| ===================================================================
|
| --- webkit/fileapi/file_system_origin_database_unittest.cc (revision 131715)
|
| +++ webkit/fileapi/file_system_origin_database_unittest.cc (working copy)
|
| @@ -1,24 +1,105 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2012 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 "testing/gtest/include/gtest/gtest.h"
|
|
|
| +#include <algorithm>
|
| #include <string>
|
|
|
| +#include "base/file_path.h"
|
| #include "base/file_util.h"
|
| +#include "base/platform_file.h"
|
| #include "base/scoped_temp_dir.h"
|
| +#include "base/stl_util.h"
|
| +#include "third_party/leveldatabase/src/db/filename.h"
|
| +#include "third_party/leveldatabase/src/include/leveldb/db.h"
|
| #include "webkit/fileapi/file_system_origin_database.h"
|
| +#include "webkit/fileapi/file_system_util.h"
|
|
|
| namespace fileapi {
|
|
|
| +namespace {
|
| +const FilePath::CharType kFileSystemDirName[] =
|
| + FILE_PATH_LITERAL("File System");
|
| +const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins");
|
| +
|
| +void CorruptDatabase(const FilePath& db_path,
|
| + leveldb::FileType type,
|
| + ptrdiff_t offset,
|
| + size_t size) {
|
| + file_util::FileEnumerator file_enum(
|
| + db_path, false /* recursive */,
|
| + static_cast<file_util::FileEnumerator::FileType>(
|
| + file_util::FileEnumerator::DIRECTORIES |
|
| + file_util::FileEnumerator::FILES));
|
| + FilePath file_path;
|
| + FilePath picked_file_path;
|
| + uint64 picked_file_number = kuint64max;
|
| +
|
| + while (!(file_path = file_enum.Next()).empty()) {
|
| + uint64 number = kuint64max;
|
| + leveldb::FileType file_type;
|
| + EXPECT_TRUE(leveldb::ParseFileName(FilePathToString(file_path.BaseName()),
|
| + &number, &file_type));
|
| + if (file_type == type &&
|
| + (picked_file_number == kuint64max || picked_file_number < number)) {
|
| + picked_file_path = file_path;
|
| + picked_file_number = number;
|
| + }
|
| + }
|
| +
|
| + EXPECT_FALSE(picked_file_path.empty());
|
| + EXPECT_NE(kuint64max, picked_file_number);
|
| +
|
| + bool created = true;
|
| + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
|
| + base::PlatformFile file =
|
| + CreatePlatformFile(picked_file_path,
|
| + base::PLATFORM_FILE_OPEN |
|
| + base::PLATFORM_FILE_READ |
|
| + base::PLATFORM_FILE_WRITE,
|
| + &created, &error);
|
| + EXPECT_EQ(base::PLATFORM_FILE_OK, error);
|
| + EXPECT_FALSE(created);
|
| +
|
| + base::PlatformFileInfo file_info;
|
| + EXPECT_TRUE(base::GetPlatformFileInfo(file, &file_info));
|
| + if (offset < 0)
|
| + offset += file_info.size;
|
| + EXPECT_GE(offset, 0);
|
| + EXPECT_LE(offset, file_info.size);
|
| +
|
| + size = std::min(size, static_cast<size_t>(file_info.size - offset));
|
| +
|
| + std::vector<char> buf(size);
|
| + int read_size = base::ReadPlatformFile(file, offset,
|
| + vector_as_array(&buf), buf.size());
|
| + EXPECT_LT(0, read_size);
|
| + EXPECT_GE(buf.size(), static_cast<size_t>(read_size));
|
| + buf.resize(read_size);
|
| +
|
| + std::transform(buf.begin(), buf.end(), buf.begin(),
|
| + std::logical_not<char>());
|
| +
|
| + int written_size = base::WritePlatformFile(file, offset,
|
| + vector_as_array(&buf), buf.size());
|
| + EXPECT_GT(written_size, 0);
|
| + EXPECT_EQ(buf.size(), static_cast<size_t>(written_size));
|
| +
|
| + base::ClosePlatformFile(file);
|
| +}
|
| +
|
| +}
|
| +
|
| TEST(FileSystemOriginDatabaseTest, BasicTest) {
|
| ScopedTempDir dir;
|
| ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| - const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
|
| - EXPECT_FALSE(file_util::PathExists(kDBFile));
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
|
|
| - FileSystemOriginDatabase database(kDBFile);
|
| + FileSystemOriginDatabase database(kFSDir);
|
| std::string origin("origin");
|
|
|
| EXPECT_FALSE(database.HasOriginPath(origin));
|
| @@ -38,16 +119,17 @@
|
| EXPECT_FALSE(path1.empty());
|
| EXPECT_EQ(path0, path1);
|
|
|
| - EXPECT_TRUE(file_util::PathExists(kDBFile));
|
| + EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
|
| }
|
|
|
| TEST(FileSystemOriginDatabaseTest, TwoPathTest) {
|
| ScopedTempDir dir;
|
| ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| - const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
|
| - EXPECT_FALSE(file_util::PathExists(kDBFile));
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
|
|
| - FileSystemOriginDatabase database(kDBFile);
|
| + FileSystemOriginDatabase database(kFSDir);
|
| std::string origin0("origin0");
|
| std::string origin1("origin1");
|
|
|
| @@ -65,16 +147,17 @@
|
| EXPECT_FALSE(path1.empty());
|
| EXPECT_NE(path0, path1);
|
|
|
| - EXPECT_TRUE(file_util::PathExists(kDBFile));
|
| + EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
|
| }
|
|
|
| TEST(FileSystemOriginDatabaseTest, DropDatabaseTest) {
|
| ScopedTempDir dir;
|
| ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| - const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
|
| - EXPECT_FALSE(file_util::PathExists(kDBFile));
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
|
|
| - FileSystemOriginDatabase database(kDBFile);
|
| + FileSystemOriginDatabase database(kFSDir);
|
| std::string origin("origin");
|
|
|
| EXPECT_FALSE(database.HasOriginPath(origin));
|
| @@ -84,7 +167,7 @@
|
| EXPECT_TRUE(database.HasOriginPath(origin));
|
| EXPECT_FALSE(path0.empty());
|
|
|
| - EXPECT_TRUE(file_util::PathExists(kDBFile));
|
| + EXPECT_TRUE(file_util::PathExists(kFSDir.Append(kOriginDatabaseName)));
|
|
|
| database.DropDatabase();
|
|
|
| @@ -98,10 +181,11 @@
|
| TEST(FileSystemOriginDatabaseTest, DeleteOriginTest) {
|
| ScopedTempDir dir;
|
| ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| - const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
|
| - EXPECT_FALSE(file_util::PathExists(kDBFile));
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
|
|
| - FileSystemOriginDatabase database(kDBFile);
|
| + FileSystemOriginDatabase database(kFSDir);
|
| std::string origin("origin");
|
|
|
| EXPECT_FALSE(database.HasOriginPath(origin));
|
| @@ -124,12 +208,13 @@
|
| TEST(FileSystemOriginDatabaseTest, ListOriginsTest) {
|
| ScopedTempDir dir;
|
| ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| - const FilePath kDBFile = dir.path().AppendASCII("fsod.db");
|
| - EXPECT_FALSE(file_util::PathExists(kDBFile));
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
|
|
| std::vector<FileSystemOriginDatabase::OriginRecord> origins;
|
|
|
| - FileSystemOriginDatabase database(kDBFile);
|
| + FileSystemOriginDatabase database(kFSDir);
|
| EXPECT_TRUE(database.ListAllOrigins(&origins));
|
| EXPECT_TRUE(origins.empty());
|
| origins.clear();
|
| @@ -163,4 +248,79 @@
|
| }
|
| }
|
|
|
| +TEST(FileSystemOriginDatabaseTest, DatabaseRecoveryTest) {
|
| + // Checks if FileSystemOriginDatabase 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.
|
| +
|
| + ScopedTempDir dir;
|
| + ASSERT_TRUE(dir.CreateUniqueTempDir());
|
| + const FilePath kFSDir = dir.path().Append(kFileSystemDirName);
|
| + const FilePath kDBDir = kFSDir.Append(kOriginDatabaseName);
|
| + EXPECT_FALSE(file_util::PathExists(kFSDir));
|
| + EXPECT_TRUE(file_util::CreateDirectory(kFSDir));
|
| +
|
| + const std::string kOrigins[] = {
|
| + "foo.example.com",
|
| + "bar.example.com",
|
| + "baz.example.com",
|
| + "hoge.example.com",
|
| + "fuga.example.com",
|
| + };
|
| +
|
| + scoped_ptr<FileSystemOriginDatabase> database(
|
| + new FileSystemOriginDatabase(kFSDir));
|
| + for (size_t i = 0; i < arraysize(kOrigins); ++i) {
|
| + 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(file_util::CreateDirectory(kFSDir.Append(path)));
|
| + }
|
| + database.reset();
|
| +
|
| + const FilePath kGarbageDir = kFSDir.AppendASCII("foo");
|
| + const FilePath kGarbageFile = kGarbageDir.AppendASCII("bar");
|
| + EXPECT_TRUE(file_util::CreateDirectory(kGarbageDir));
|
| + bool created = false;
|
| + base::PlatformFileError error;
|
| + base::PlatformFile file = base::CreatePlatformFile(
|
| + kGarbageFile,
|
| + base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
|
| + &created, &error);
|
| + EXPECT_EQ(base::PLATFORM_FILE_OK, error);
|
| + EXPECT_TRUE(created);
|
| + EXPECT_TRUE(base::ClosePlatformFile(file));
|
| +
|
| + // 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);
|
| +
|
| + FilePath path;
|
| + database.reset(new FileSystemOriginDatabase(kFSDir));
|
| + std::vector<FileSystemOriginDatabase::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(file_util::PathExists(kGarbageFile));
|
| + EXPECT_FALSE(file_util::PathExists(kGarbageDir));
|
| +}
|
| +
|
| } // namespace fileapi
|
|
|