#include <glog/logging.h>
#include <gtest/gtest.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include "file_interface.h"
namespace mooncake {
class PosixFileTest : public ::testing::Test {
protected:
void SetUp() override {
google::InitGoogleLogging("PosixFileTest");
FLAGS_logtostderr = 1;
test_filename = "test_file.txt";
test_fd = open(test_filename.c_str(), O_CREAT | O_RDWR, 0644);
ASSERT_GE(test_fd, 0) << "Failed to open test file";
}
void TearDown() override {
google::ShutdownGoogleLogging();
if (test_fd >= 0) {
close(test_fd);
}
remove(test_filename.c_str());
}
std::string test_filename;
int test_fd = -1;
};
TEST_F(PosixFileTest, FileLifecycle) {
PosixFile posix_file(test_filename, test_fd);
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::OK);
}
TEST_F(PosixFileTest, BasicWrite) {
PosixFile posix_file(test_filename, test_fd);
std::string test_data = "Test write data";
auto result = posix_file.write(test_data, test_data.size());
ASSERT_TRUE(result) << "Write failed with error: "
<< toString(result.error());
EXPECT_EQ(*result, test_data.size());
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::OK);
}
TEST_F(PosixFileTest, BasicRead) {
ASSERT_EQ(ftruncate(test_fd, 0), 0) << "Failed to truncate file";
ASSERT_NE(lseek(test_fd, 0, SEEK_SET), -1) << "Seek failed";
const char* test_data = "Test read data";
ssize_t written = write(test_fd, test_data, strlen(test_data));
ASSERT_EQ(written, static_cast<ssize_t>(strlen(test_data)))
<< "Write failed";
ASSERT_NE(lseek(test_fd, 0, SEEK_SET), -1) << "Seek failed";
PosixFile posix_file(test_filename, test_fd);
std::string buffer;
auto result = posix_file.read(
buffer, strlen(test_data));
ASSERT_TRUE(result) << "Read failed with error: "
<< toString(result.error());
EXPECT_EQ(*result, strlen(test_data));
EXPECT_EQ(buffer, test_data);
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::OK);
}
TEST_F(PosixFileTest, VectorizedWrite) {
PosixFile posix_file(test_filename, test_fd);
std::string data1 = "First part ";
std::string data2 = "Second part";
iovec iov[2];
iov[0].iov_base = const_cast<char*>(data1.data());
iov[0].iov_len = data1.size();
iov[1].iov_base = const_cast<char*>(data2.data());
iov[1].iov_len = data2.size();
auto result = posix_file.vector_write(iov, 2, 0);
ASSERT_TRUE(result) << "Vector write failed with error: "
<< toString(result.error());
EXPECT_EQ(*result, data1.size() + data2.size());
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::OK);
}
TEST_F(PosixFileTest, VectorizedRead) {
ASSERT_EQ(ftruncate(test_fd, 0), 0) << "Failed to truncate file";
ASSERT_NE(lseek(test_fd, 0, SEEK_SET), -1) << "Seek failed";
const char* test_data = "Vectorized read test data";
ssize_t written = write(test_fd, test_data, strlen(test_data));
ASSERT_EQ(written, static_cast<ssize_t>(strlen(test_data)))
<< "Write failed";
ASSERT_NE(lseek(test_fd, 0, SEEK_SET), -1) << "Seek failed";
PosixFile posix_file(test_filename, test_fd);
char buf1[11] = {0};
char buf2[16] = {0};
iovec iov[2];
iov[0].iov_base = buf1;
iov[0].iov_len = 10;
iov[1].iov_base = buf2;
iov[1].iov_len = 15;
auto result = posix_file.vector_read(iov, 2, 0);
ASSERT_TRUE(result) << "Vector read failed with error: "
<< toString(result.error());
EXPECT_EQ(*result, strlen(test_data));
EXPECT_STREQ(buf1, "Vectorized");
EXPECT_STREQ(buf2, " read test data");
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::OK);
}
TEST_F(PosixFileTest, ErrorCases) {
PosixFile posix_file("invalid.txt", -1);
EXPECT_EQ(posix_file.get_error_code(), ErrorCode::FILE_INVALID_HANDLE);
std::string test_data = "test";
auto write_result = posix_file.write(test_data, test_data.size());
EXPECT_FALSE(write_result);
EXPECT_EQ(write_result.error(), ErrorCode::FILE_NOT_FOUND);
std::string buffer;
auto read_result = posix_file.read(buffer, test_data.size());
EXPECT_FALSE(read_result);
EXPECT_EQ(read_result.error(), ErrorCode::FILE_NOT_FOUND);
}
TEST_F(PosixFileTest, FileLocking) {
PosixFile posix_file(test_filename, test_fd);
{
auto lock = posix_file.acquire_write_lock();
EXPECT_TRUE(lock.is_locked());
std::string buffer;
auto result = posix_file.read(buffer, 10);
EXPECT_FALSE(result);
}
{
auto lock = posix_file.acquire_read_lock();
EXPECT_TRUE(lock.is_locked());
}
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}