blob: 6f4923120efae99c3f1272272524083973c45439 [file]
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/local_file_system.h"
#include <memory>
#include <string>
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/temp_file.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/base/test/status_matchers.h"
#include "test/gtest_and_gmock.h"
namespace perfetto::trace_processor::io {
namespace {
TEST(LocalFileSystemTest, WritesAndReplacesFile) {
base::TempDir dir = base::TempDir::Create();
std::string path = dir.path() + "/output";
auto file_system = CreateLocalFileSystem();
FileOpenOptions options;
options.access = FileAccess::kWriteOnly;
options.create = true;
options.truncate = true;
{
std::unique_ptr<File> file;
ASSERT_OK(file_system->OpenFile(path, options, &file));
ASSERT_OK(file->WriteAt(0, "abc", 3));
}
std::string contents;
ASSERT_TRUE(base::ReadFile(path, &contents));
EXPECT_EQ(contents, "abc");
{
std::unique_ptr<File> file;
ASSERT_OK(file_system->OpenFile(path, options, &file));
ASSERT_OK(file->WriteAt(0, "d", 1));
}
contents.clear();
ASSERT_TRUE(base::ReadFile(path, &contents));
EXPECT_EQ(contents, "d");
ASSERT_OK(file_system->DeleteFile(path));
}
TEST(LocalFileSystemTest, RandomAccessReadWrite) {
base::TempDir dir = base::TempDir::Create();
std::string path = dir.path() + "/output";
auto file_system = CreateLocalFileSystem();
FileOpenOptions options;
options.access = FileAccess::kReadWrite;
options.create = true;
options.truncate = true;
std::unique_ptr<File> file;
ASSERT_OK(file_system->OpenFile(path, options, &file));
ASSERT_OK(file->WriteAt(10, "hello", 5));
ASSERT_OK(file->WriteAt(0, "start ", 6));
ASSERT_OK(file->Flush());
uint64_t size = 0;
ASSERT_OK(file->GetSize(&size));
EXPECT_EQ(size, 15u);
char buffer[16] = {};
size_t read = 0;
ASSERT_OK(file->ReadAt(10, buffer, 7, &read));
EXPECT_EQ(read, 5u);
EXPECT_EQ(std::string(buffer, 5), "hello");
// The gap between the two writes is a sparse hole read back as zeros.
ASSERT_OK(file->ReadAt(0, buffer, 10, &read));
EXPECT_EQ(read, 10u);
EXPECT_EQ(std::string(buffer, 6), "start ");
EXPECT_EQ(std::string(buffer + 6, 4), std::string(4, '\0'));
ASSERT_OK(file->Truncate(6));
ASSERT_OK(file->GetSize(&size));
EXPECT_EQ(size, 6u);
file.reset();
ASSERT_OK(file_system->DeleteFile(path));
}
TEST(LocalFileSystemTest, RejectsReadOnlyCreate) {
base::TempDir dir = base::TempDir::Create();
std::string path = dir.path() + "/output";
auto file_system = CreateLocalFileSystem();
FileOpenOptions options;
options.access = FileAccess::kReadOnly;
options.create = true;
std::unique_ptr<File> file;
EXPECT_THAT(file_system->OpenFile(path, options, &file),
base::gtest_matchers::IsError());
}
TEST(LocalFileSystemTest, NoopFileSystemRejectsAllOperations) {
auto file_system = CreateNoopFileSystem();
FileOpenOptions options;
options.access = FileAccess::kReadWrite;
options.create = true;
std::unique_ptr<File> file;
EXPECT_THAT(file_system->OpenFile("path", options, &file),
base::gtest_matchers::IsError());
EXPECT_THAT(file_system->DeleteFile("path"), base::gtest_matchers::IsError());
bool exists = false;
EXPECT_THAT(file_system->FileExists("path", &exists),
base::gtest_matchers::IsError());
}
TEST(FileSystemConfigTest, DisabledByDefault) {
EXPECT_FALSE(Config().enable_sql_file_access);
}
} // namespace
} // namespace perfetto::trace_processor::io