blob: bceacbda5738d314b6805f232210da9ddf6d6513 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/persistent_cache/sqlite/vfs/sqlite_sandboxed_vfs.h"
#include <memory>
#include <utility>
#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/test/gmock_expected_support.h"
#include "components/persistent_cache/sqlite/test_utils.h"
#include "components/persistent_cache/sqlite/vfs/sqlite_database_vfs_file_set.h"
#include "sql/database.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
namespace persistent_cache {
namespace {
const base::FilePath kNonExistentVirtualFilePath =
base::FilePath::FromASCII("NotFound");
} // namespace
class SqliteSandboxedVfsTest : public testing::Test {
public:
std::optional<SqliteVfsFileSet> CreateFilesAndBuildVfsFileSet() {
return temporary_vfs_file_set_provider_.CreateFilesAndBuildVfsFileSet();
}
private:
test_utils::TestHelper temporary_vfs_file_set_provider_;
};
TEST_F(SqliteSandboxedVfsTest, NoAccessWithoutRegistering) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
EXPECT_FALSE(SqliteSandboxedVfsDelegate::GetInstance()
->OpenFile(kNonExistentVirtualFilePath, 0)
.IsValid());
}
TEST_F(SqliteSandboxedVfsTest, AccessAfterRegistering) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
EXPECT_TRUE(SqliteSandboxedVfsDelegate::GetInstance()
->OpenFile(virtual_file_path_to_file.first, 0)
.IsValid());
}
}
TEST_F(SqliteSandboxedVfsTest, NoAccessAfterUnregistering) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
// Register and immediately unregister.
{
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
}
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
EXPECT_FALSE(SqliteSandboxedVfsDelegate::GetInstance()
->OpenFile(virtual_file_path_to_file.first, 0)
.IsValid());
}
}
TEST_F(SqliteSandboxedVfsTest, AccessAfterReRegistering) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
// Register and immediately unregister.
{
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
}
// Register again.
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
EXPECT_TRUE(SqliteSandboxedVfsDelegate::GetInstance()
->OpenFile(virtual_file_path_to_file.first, 0)
.IsValid());
}
}
TEST_F(SqliteSandboxedVfsTest, DeleteFileAlwaysImpossible) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
// Impossible to delete non-registered files.
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
EXPECT_EQ(SqliteSandboxedVfsDelegate::GetInstance()->DeleteFile(
virtual_file_path_to_file.first, true),
SQLITE_NOTFOUND);
}
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
// Impossible to delete registered files.
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
EXPECT_EQ(SqliteSandboxedVfsDelegate::GetInstance()->DeleteFile(
virtual_file_path_to_file.first, true),
SQLITE_IOERR_DELETE);
}
}
TEST_F(SqliteSandboxedVfsTest, OpenFile) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
int64_t length = 0;
for (auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
virtual_file_path_to_file.second->UnderlyingFileForTesting().SetLength(
length += 100);
}
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
for (const auto& virtual_file_path_to_file : vfs_file_set.GetFiles()) {
base::File::Info info_from_map;
virtual_file_path_to_file.second->UnderlyingFileForTesting().GetInfo(
&info_from_map);
// Simulate an open from the VFS.
base::File from_delegate =
SqliteSandboxedVfsDelegate::GetInstance()->OpenFile(
virtual_file_path_to_file.first, 0);
base::File::Info info_from_delegate;
from_delegate.GetInfo(&info_from_delegate);
EXPECT_EQ(info_from_delegate.size, info_from_map.size);
// Simulate the binding done by the VFS.
virtual_file_path_to_file.second->OnFileOpened(std::move(from_delegate));
base::File::Info info_from_opened_file;
virtual_file_path_to_file.second->OpenedFileForTesting().GetInfo(
&info_from_opened_file);
EXPECT_EQ(info_from_opened_file.size, info_from_map.size);
}
}
TEST_F(SqliteSandboxedVfsTest, SqliteIntegration) {
ASSERT_OK_AND_ASSIGN(SqliteVfsFileSet vfs_file_set,
CreateFilesAndBuildVfsFileSet());
SqliteSandboxedVfsDelegate::UnregisterRunner unregister_runner =
SqliteSandboxedVfsDelegate::GetInstance()->RegisterSandboxedFiles(
vfs_file_set);
sql::Database db(sql::DatabaseOptions().set_vfs_name_discouraged(
SqliteSandboxedVfsDelegate::kSqliteVfsName),
"Test");
EXPECT_TRUE(db.Open(vfs_file_set.GetDbVirtualFilePath()));
}
} // namespace persistent_cache