repertory/tests/fuse_test.cpp
Scott E. Graves 3ff46723b8
Some checks failed
BlockStorage/repertory_osx/pipeline/head There was a failure building this commit
BlockStorage/repertory_windows/pipeline/head This commit looks good
BlockStorage/repertory_linux_builds/pipeline/head This commit looks good
initial commit
2022-03-05 00:30:50 -06:00

1590 lines
69 KiB
C++

/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if !_WIN32
#include "fixtures/fuse_fixture.hpp"
#include "test_common.hpp"
#include "utils/event_capture.hpp"
#include "utils/file_utils.hpp"
#ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
#endif
namespace repertory {
static void retry_unlink(const std::string &file) {
int ret = 0;
std::this_thread::sleep_for(100ms);
for (auto i = 0; ((ret = unlink(file.c_str())) != 0) && (i < 20); i++) {
std::this_thread::sleep_for(100ms);
}
EXPECT_EQ(0, ret);
}
static auto mount_setup(const std::size_t &idx, fuse_test *test, std::string &mount_point) {
// Mock communicator setup
static long i = 0;
if (idx == 0) {
auto uid = std::to_string(getuid());
auto &mock_comm = test->mock_sia_comm_;
mock_comm.push_return("get", "/wallet", {}, {}, api_error::success, true);
json files;
files["files"] = std::vector<json>();
mock_comm.push_return("get", "/renter/files", files, {}, api_error::success, true);
mock_comm.push_return("get", "/renter/file/", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.localized", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.localized", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.hidden", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.hidden", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.DS_Store", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.DS_Store", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/BDMV", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/BDMV", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.xdg-volume-info", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.xdg-volume-info", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/autorun.inf", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/autorun.inf", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.Trash", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.Trash", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/.Trash-" + uid, {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/.Trash-" + uid, {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("post", "/renter/downloads/clear", files, {}, api_error::success, true);
mock_comm.push_return("get", "/renter/prices", {}, {{"message", "offline"}},
api_error::comm_error, true);
mock_comm.push_return(
"get", "/daemon/version",
{{"version", app_config::get_provider_minimum_version(provider_type::sia)}}, {},
api_error::success, true);
} else if (idx == 2) {
#ifdef REPERTORY_ENABLE_S3_TESTING
/* auto &mock_comm = test->mockS3Comm_; */
/* ON_CALL(mock_comm, Exists(_)).WillByDefault(Return(false)); */
/* ON_CALL(mock_comm, get_file_list(_)).WillByDefault(Return(api_error::success)); */
#endif
}
// Mount setup
mount_point = utils::path::absolute("./fuse_mount" + std::to_string(i++));
utils::file::create_full_directory_path(mount_point);
return std::vector<std::string>({"unittests", "-f", mount_point});
}
static void execute_mount(const std::size_t &idx, fuse_test *test,
const std::vector<std::string> &drive_args, std::thread &th) {
ASSERT_EQ(0, std::get<2>(test->provider_tests_[idx])->mount(drive_args));
th.join();
}
static void unmount(const std::string &mount_point) {
auto unmounted = false;
for (int i = 0; not unmounted && (i < 10); i++) {
#if __APPLE__
unmounted = (system(("umount \"" + mount_point + "\"").c_str()) == 0);
#else
unmounted = (system(("fusermount -u \"" + mount_point + "\"").c_str()) == 0);
#endif
if (not unmounted) {
std::this_thread::sleep_for(100ms);
}
}
EXPECT_TRUE(unmounted);
rmdir(mount_point.c_str());
}
TEST_F(fuse_test, mount_and_unmount) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
}
event_capture ec({
"drive_mounted",
"drive_unmounted",
"drive_unmount_pending",
"drive_mount_result",
});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
EXPECT_EQ(0, system(("mount|grep \"" + mount_point + "\"").c_str()));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
event_system::instance().stop();
event_system::instance().start();
}
}
TEST_F(fuse_test, root_creation) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
struct stat st {};
EXPECT_EQ(0, stat(mount_point.c_str(), &st));
EXPECT_EQ(getuid(), st.st_uid);
EXPECT_EQ(getgid(), st.st_gid);
EXPECT_TRUE(S_ISDIR(st.st_mode));
EXPECT_EQ(S_IRUSR | S_IWUSR | S_IXUSR, ACCESSPERMS & st.st_mode);
EXPECT_EQ(0, st.st_size);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, chmod) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
EXPECT_EQ(0, chmod(mount_point.c_str(), S_IRUSR | S_IWUSR));
std::string mode;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/", META_MODE, mode));
EXPECT_EQ(S_IRUSR | S_IWUSR, ACCESSPERMS & utils::string::to_uint32(mode));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, chown_uid) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
EXPECT_EQ(0, chown(mount_point.c_str(), 0, -1));
std::string uid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/", META_UID, uid));
EXPECT_STREQ("0", uid.c_str());
std::string gid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/", META_GID, gid));
if (not gid.empty()) {
EXPECT_EQ(getgid(), utils::string::to_uint32(gid));
}
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, chown_gid) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
EXPECT_EQ(0, chown(mount_point.c_str(), -1, 0));
std::string uid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/", META_UID, uid));
EXPECT_EQ(getuid(), utils::string::to_uint32(uid));
std::string gid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/", META_GID, gid));
EXPECT_STREQ("0", gid.c_str());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, mkdir) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return("post_params", "/renter/dir/new_dir", {}, {}, api_error::success);
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/new_dir", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/new_dir", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/file/new_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._new_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/._new_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return(
"get", "/renter/dir/new_dir",
{{"directories", {{{"siapath", "new_dir"}, {"numfiles", 0}, {"numsubdirs", 0}}}},
{"files", {}}},
{}, api_error::success, true);
} else if (idx == 2) {
#ifdef REPERTORY_ENABLE_S3_TESTING
/* EXPECT_CALL(mockS3Comm_, Exists("/new_dir")).WillRepeatedly(Return(false)); */
/* EXPECT_CALL(mockS3Comm_, Exists(_)).WillRepeatedly(Return(false)); */
// EXPECT_CALL(mockS3Comm_, get_directory_item_count("/new_dir")).WillRepeatedly(Return(2u));
#endif
}
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto newDir = utils::path::combine(mount_point, {"new_dir"});
EXPECT_EQ(0, mkdir(newDir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP));
EXPECT_TRUE(utils::file::is_directory(newDir));
EXPECT_FALSE(utils::file::is_file(newDir));
std::string uid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/new_dir", META_UID, uid));
EXPECT_EQ(getuid(), utils::string::to_uint32(uid));
std::string gid;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/new_dir", META_GID, gid));
EXPECT_EQ(getgid(), utils::string::to_uint32(gid));
std::string mode;
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/new_dir", META_MODE, mode));
EXPECT_EQ(S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP,
ACCESSPERMS & (utils::string::to_uint32(mode)));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, rmdir) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return("post_params", "/renter/dir/rm_dir", {}, {}, api_error::success);
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/file/rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/._rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return(
"get", "/renter/dir/rm_dir",
{{"directories", {{{"siapath", "rm_dir"}, {"numfiles", 0}, {"numsubdirs", 0}}}},
{"files", {}}},
{}, api_error::success);
mock_comm.push_return("post_params", "/renter/dir/rm_dir", {}, {}, api_error::success);
mock_comm.push_return("get", "/renter/dir/rm_dir", {}, {{"message", "no file known"}},
api_error::comm_error, true);
} else if (idx == 2) {
#ifdef REPERTORY_ENABLE_S3_TESTING
/* EXPECT_CALL(mockS3Comm_, Exists("/rm_dir")).WillRepeatedly(Return(false)); */
/* EXPECT_CALL(mockS3Comm_, Exists(_)).WillRepeatedly(Return(false)); */
// EXPECT_CALL(mockS3Comm_, get_directory_item_count("/rm_dir")).WillRepeatedly(Return(2u));
#endif
}
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
event_capture ec2({"directory_removed"});
const auto new_directory = utils::path::combine(mount_point, {"rm_dir"});
EXPECT_EQ(0, mkdir(new_directory.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP));
EXPECT_TRUE(utils::file::is_directory(new_directory));
EXPECT_EQ(0, rmdir(new_directory.c_str()));
EXPECT_FALSE(utils::file::is_directory(new_directory));
api_meta_map meta;
EXPECT_EQ(api_error::item_not_found,
std::get<1>(provider_tests_[idx])->get_item_meta("/rm_dir", meta));
EXPECT_EQ(0, meta.size());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, create_new_file) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._create_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/create_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/create_file.txt",
RENTER_FILE_DATA("create_file.txt", 0), {}, api_error::success, true);
} else if (idx == 2) {
#ifdef REPERTORY_ENABLE_S3_TESTING
/* EXPECT_CALL(mockS3Comm_, upload_file("/create_file.txt", _, _)) */
/* .WillOnce(Return(api_error::success)); */
api_file file{};
file.accessed_date = utils::get_file_time_now();
file.api_path =
utils::path::create_api_path(utils::path::combine("repertory", {"create_file.txt"}));
file.api_parent = utils::path::get_parent_api_path(file.api_path);
file.changed_date = utils::get_file_time_now();
file.created_date = utils::get_file_time_now();
file.file_size = 0u;
file.modified_date = utils::get_file_time_now();
file.recoverable = true;
file.redundancy = 3.0;
/* EXPECT_CALL(mockS3Comm_, GetFile("/create_file.txt", _)) */
/* .WillRepeatedly(DoAll(SetArgReferee<1>(apiFile), Return(api_error::success))); */
/* EXPECT_CALL(mockS3Comm_, Exists(_)).WillRepeatedly(Return(false)); */
#endif
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
event_capture ec2((idx == 0) ? std::vector<std::string>({
"file_upload_begin",
"file_upload_end",
"filesystem_item_handle_closed",
"filesystem_item_closed",
})
: std::vector<std::string>({
"filesystem_item_handle_closed",
"filesystem_item_closed",
}));
const auto file = utils::path::combine(mount_point, {"create_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_TRUE(utils::file::is_file(file));
EXPECT_FALSE(utils::file::is_directory(file));
std::uint64_t file_size;
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
EXPECT_EQ(0, file_size);
std::string uid;
EXPECT_EQ(
api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/create_file.txt", META_UID, uid));
EXPECT_EQ(getuid(), utils::string::to_uint32(uid));
std::string gid;
EXPECT_EQ(
api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/create_file.txt", META_GID, gid));
EXPECT_EQ(getgid(), utils::string::to_uint32(gid));
std::string mode;
EXPECT_EQ(
api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/create_file.txt", META_MODE, mode));
EXPECT_EQ(S_IRUSR | S_IWUSR | S_IRGRP, ACCESSPERMS & (utils::string::to_uint32(mode)));
EXPECT_EQ(0, close(fd));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, unlink) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/unlink_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/unlink_file.txt",
RENTER_FILE_DATA("unlink_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/unlink_file.txt",
RENTER_FILE_DATA("unlink_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/unlink_file.txt",
RENTER_FILE_DATA("unlink_file.txt", 0), {}, api_error::success);
#if __APPLE__
mock_comm.push_return("get", "/renter/file/unlink_file.txt",
RENTER_FILE_DATA("unlink_file.txt", 0), {}, api_error::success);
#endif
mock_comm.push_return("post_params", "/renter/delete/unlink_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/unlink_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
} else if (idx == 2) {
#ifdef REPERTORY_ENABLE_S3_TESTING
/* EXPECT_CALL(mockS3Comm_, upload_file("/unlink_file.txt", _, _)) */
/* .WillOnce(Return(api_error::success)); */
api_file apiFile{};
apiFile.accessed_date = utils::get_file_time_now();
apiFile.api_path =
utils::path::create_api_path(utils::path::combine("repertory", {"unlink_file.txt"}));
apiFile.api_parent = utils::path::get_parent_api_path(apiFile.api_path);
apiFile.changed_date = utils::get_file_time_now();
apiFile.created_date = utils::get_file_time_now();
apiFile.file_size = 0u;
apiFile.modified_date = utils::get_file_time_now();
apiFile.recoverable = true;
apiFile.redundancy = 3.0;
/* EXPECT_CALL(mockS3Comm_, GetFile("/unlink_file.txt", _)) */
/* .WillRepeatedly(DoAll(SetArgReferee<1>(apiFile), Return(api_error::success))); */
/* EXPECT_CALL(mockS3Comm_, Exists(_)).WillRepeatedly(Return(false)); */
/* EXPECT_CALL(mockS3Comm_, RemoveFile("/unlink_file.txt")) */
/* .WillOnce(Return(api_error::success)); */
#endif
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
event_capture ec2({"file_removed"});
const auto file = utils::path::combine(mount_point, {"unlink_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
filesystem_item fsi{};
EXPECT_EQ(
api_error::success,
std::get<1>(provider_tests_[idx])->get_filesystem_item("/unlink_file.txt", false, fsi));
EXPECT_TRUE(utils::file::is_file(file));
EXPECT_TRUE(utils::file::is_file(fsi.source_path));
retry_unlink(file);
EXPECT_FALSE(utils::file::is_file(file));
EXPECT_FALSE(utils::file::is_file(fsi.source_path));
api_meta_map meta;
EXPECT_EQ(api_error::item_not_found,
std::get<1>(provider_tests_[idx])->get_item_meta("/unlink_file.txt", meta));
EXPECT_EQ(0, meta.size());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, write) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/write_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/write_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/write_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/write_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._write_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._write_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/write_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/write_file.txt",
RENTER_FILE_DATA("write_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/write_file.txt",
RENTER_FILE_DATA("write_file.txt", 8), {}, api_error::success, true);
}
event_capture ec((idx == 0)
? std::vector<std::string>({"drive_mounted"})
: std::vector<std::string>({"drive_mounted", "file_upload_queued"}));
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"write_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
std::string data = "TestData";
EXPECT_EQ(data.size(), write(fd, &data[0], data.size()));
EXPECT_EQ(0, close(fd));
std::this_thread::sleep_for(1s);
std::uint64_t file_size;
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
EXPECT_EQ(data.size(), file_size);
filesystem_item fsi{};
EXPECT_EQ(
api_error::success,
std::get<1>(provider_tests_[idx])->get_filesystem_item("/write_file.txt", false, fsi));
EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
EXPECT_EQ(data.size(), file_size);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, read) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/read_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/read_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/file/read_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/file/read_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._read_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._read_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/read_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/read_file.txt",
RENTER_FILE_DATA("read_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/read_file.txt",
RENTER_FILE_DATA("read_file.txt", 8), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"read_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
std::string data = "TestData";
EXPECT_EQ(data.size(), write(fd, &data[0], data.size()));
EXPECT_EQ(0, lseek(fd, 0, SEEK_SET));
std::vector<char> read_data;
read_data.resize(data.size());
EXPECT_EQ(data.size(), read(fd, &read_data[0], read_data.size()));
EXPECT_EQ(0, memcmp(&data[0], &read_data[0], data.size()));
EXPECT_EQ(0, close(fd));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, rename) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/dir/rename_file2.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/rename_file.txt",
RENTER_FILE_DATA("rename_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/rename_file.txt",
RENTER_FILE_DATA("rename_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/rename_file.txt",
RENTER_FILE_DATA("rename_file.txt", 0), {}, api_error::success);
#if __APPLE__
mock_comm.push_return("get", "/renter/file/rename_file.txt",
RENTER_FILE_DATA("rename_file.txt", 0), {}, api_error::success);
#endif
mock_comm.push_return("post_params", "/renter/upload/rename_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/rename_file2.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/rename_file2.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._rename_file2.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._rename_file2.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/rename/rename_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/rename_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/rename_file2.txt",
RENTER_FILE_DATA("rename_file2.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"rename_file.txt"});
const auto new_file = utils::path::combine(mount_point, {"rename_file2.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
api_meta_map meta1{};
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/rename_file.txt", meta1));
EXPECT_EQ(0, rename(file.c_str(), new_file.c_str()));
api_meta_map meta2{};
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])->get_item_meta("/rename_file2.txt", meta2));
EXPECT_STREQ(meta1[META_SOURCE].c_str(), meta2[META_SOURCE].c_str());
filesystem_item fsi{};
EXPECT_EQ(api_error::success, std::get<1>(provider_tests_[idx])
->get_filesystem_item("/rename_file2.txt", false, fsi));
EXPECT_STREQ(meta1[META_SOURCE].c_str(), fsi.source_path.c_str());
filesystem_item fsi2{};
EXPECT_EQ(api_error::success,
std::get<1>(provider_tests_[idx])
->get_filesystem_item_from_source_path(fsi.source_path, fsi2));
EXPECT_STREQ("/rename_file2.txt", fsi2.api_path.c_str());
EXPECT_EQ(-1, unlink(file.c_str()));
EXPECT_EQ(ENOENT, errno);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, truncate) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._truncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/truncate_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/truncate_file.txt",
RENTER_FILE_DATA("truncate_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/truncate_file.txt",
RENTER_FILE_DATA("truncate_file.txt", 0), {}, api_error::success);
#if __APPLE__
mock_comm.push_return("get", "/renter/file/truncate_file.txt",
RENTER_FILE_DATA("truncate_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/truncate_file.txt",
RENTER_FILE_DATA("truncate_file.txt", 0), {}, api_error::success);
#endif
mock_comm.push_return("get", "/renter/file/truncate_file.txt",
RENTER_FILE_DATA("truncate_file.txt", 16), {}, api_error::success,
true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"truncate_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
EXPECT_EQ(0, truncate(file.c_str(), 16));
std::this_thread::sleep_for(1s);
std::uint64_t file_size;
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
EXPECT_EQ(16, file_size);
filesystem_item fsi{};
EXPECT_EQ(api_error::success, std::get<1>(provider_tests_[idx])
->get_filesystem_item("/truncate_file.txt", false, fsi));
file_size = 0;
EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
EXPECT_EQ(16, file_size);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, ftruncate) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._ftruncate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/ftruncate_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/ftruncate_file.txt",
RENTER_FILE_DATA("ftruncate_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/ftruncate_file.txt",
RENTER_FILE_DATA("ftruncate_file.txt", 16), {}, api_error::success,
true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"ftruncate_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, ftruncate(fd, 16));
std::uint64_t file_size;
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
EXPECT_EQ(16, file_size);
EXPECT_EQ(0, close(fd));
filesystem_item fsi{};
EXPECT_EQ(api_error::success, std::get<1>(provider_tests_[idx])
->get_filesystem_item("/ftruncate_file.txt", false, fsi));
file_size = 0;
EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
EXPECT_EQ(16, file_size);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
#ifdef __APPLE__
TEST_F(FUSETest, fallocate) {}
#else
TEST_F(fuse_test, fallocate) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/fallocate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/fallocate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/fallocate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/fallocate_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/fallocate_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/fallocate_file.txt",
RENTER_FILE_DATA("fallocate_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/fallocate_file.txt",
RENTER_FILE_DATA("fallocate_file.txt", 16), {}, api_error::success,
true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"fallocate_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, fallocate(fd, 0, 0, 16));
std::uint64_t file_size;
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
EXPECT_EQ(16, file_size);
EXPECT_EQ(0, close(fd));
filesystem_item fsi{};
EXPECT_EQ(api_error::success, std::get<1>(provider_tests_[idx])
->get_filesystem_item("/fallocate_file.txt", false, fsi));
file_size = 0;
EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
EXPECT_EQ(16, file_size);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
#endif
#if !__APPLE__ && HAS_SETXATTR
TEST_F(fuse_test, invalid_setxattr) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::string attr = "moose";
EXPECT_EQ(-1, setxattr(nullptr, "user.test_attr", &attr[0], attr.size(), XATTR_CREATE));
EXPECT_EQ(errno, EFAULT);
EXPECT_EQ(-1, setxattr(file.c_str(), nullptr, &attr[0], attr.size(), XATTR_CREATE));
EXPECT_EQ(errno, EFAULT);
EXPECT_EQ(-1, setxattr(file.c_str(), "user.test_attr", nullptr, attr.size(), XATTR_CREATE));
EXPECT_EQ(errno, EFAULT);
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", nullptr, 0, XATTR_CREATE));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, create_and_get_extended_attribute) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_CREATE));
std::string val;
val.resize(attr.size());
EXPECT_EQ(attr.size(), getxattr(file.c_str(), "user.test_attr", &val[0], val.size()));
EXPECT_STREQ(attr.c_str(), val.c_str());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, replace_extended_attribute) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::this_thread::sleep_for(1s);
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_CREATE));
attr = "cow";
EXPECT_EQ(0,
setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_REPLACE));
std::string val;
val.resize(attr.size());
EXPECT_EQ(attr.size(), getxattr(file.c_str(), "user.test_attr", &val[0], val.size()));
EXPECT_STREQ(attr.c_str(), val.c_str());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, default_create_extended_attribute) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::this_thread::sleep_for(1s);
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), 0));
std::string val;
val.resize(attr.size());
EXPECT_EQ(attr.size(), getxattr(file.c_str(), "user.test_attr", &val[0], val.size()));
EXPECT_STREQ(attr.c_str(), val.c_str());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, default_replace_extended_attribute) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::this_thread::sleep_for(1s);
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), 0));
attr = "cow";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), 0));
std::string val;
val.resize(attr.size());
EXPECT_EQ(attr.size(), getxattr(file.c_str(), "user.test_attr", &val[0], val.size()));
EXPECT_STREQ(attr.c_str(), val.c_str());
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, create_extended_attribute_fails_if_exists) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), 0));
EXPECT_EQ(-1,
setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_CREATE));
EXPECT_EQ(EEXIST, errno);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, replace_extended_attribute_fails_if_not_exists) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::string attr = "moose";
EXPECT_EQ(-1,
setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_REPLACE));
EXPECT_EQ(ENODATA, errno);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
TEST_F(fuse_test, removexattr) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/xattr_file.txt", {}, {{"message", "no file known"}},
api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/xattr_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("post_params", "/renter/upload/xattr_file.txt", {}, {},
api_error::success);
mock_comm.push_return("get", "/renter/file/xattr_file.txt",
RENTER_FILE_DATA("xattr_file.txt", 0), {}, api_error::success, true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"xattr_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
EXPECT_EQ(0, close(fd));
std::this_thread::sleep_for(1s);
std::string attr = "moose";
EXPECT_EQ(0, setxattr(file.c_str(), "user.test_attr", &attr[0], attr.size(), XATTR_CREATE));
EXPECT_EQ(0, removexattr(file.c_str(), "user.test_attr"));
std::string val;
val.resize(attr.size());
EXPECT_EQ(-1, getxattr(file.c_str(), "user.test_attr", &val[0], val.size()));
EXPECT_EQ(ENODATA, errno);
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
#endif
TEST_F(fuse_test, write_fails_if_file_is_read_only) {
for (std::size_t idx = 0; idx < provider_tests_.size(); idx++) {
std::string mount_point;
const auto drive_args = mount_setup(idx, this, mount_point);
if (idx == 0) {
auto &mock_comm = mock_sia_comm_;
mock_comm.push_return(
"get", "/renter/dir/",
{{"directories",
{{{"siapath", ""}, {"numfiles", 0}, {"numsubdirs", 0}, {"aggregatenumfiles", 1}}}},
{"files", {}}},
{}, api_error::success, true);
mock_comm.push_return("get", "/renter/dir/write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/file/write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error);
mock_comm.push_return("get", "/renter/dir/._write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("get", "/renter/file/._write_fails_file.txt", {},
{{"message", "no file known"}}, api_error::comm_error, true);
mock_comm.push_return("post_params", "/renter/upload/write_fails_file.txt", {}, {},
api_error::success, true);
mock_comm.push_return("get", "/renter/file/write_fails_file.txt",
RENTER_FILE_DATA("write_fails_file.txt", 0), {}, api_error::success);
mock_comm.push_return("get", "/renter/file/write_fails_file.txt",
RENTER_FILE_DATA("write_fails_file.txt", 8), {}, api_error::success,
true);
}
event_capture ec({"drive_mounted"});
std::thread th([&] {
const auto mounted = ec.wait_for_event("drive_mounted");
EXPECT_TRUE(mounted);
if (mounted) {
const auto file = utils::path::combine(mount_point, {"write_fails_file.txt"});
auto fd = open(file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
EXPECT_LE(1, fd);
std::string data = "TestData";
EXPECT_EQ(data.size(), write(fd, &data[0], data.size()));
EXPECT_EQ(0, close(fd));
fd = open(file.c_str(), O_RDONLY);
EXPECT_LE(1, fd);
EXPECT_EQ(-1, write(fd, &data[0], data.size()));
#ifndef __APPLE__
EXPECT_EQ(-1, fallocate(fd, 0, 0, 16));
#endif
EXPECT_EQ(-1, ftruncate(fd, 100));
EXPECT_EQ(0, close(fd));
}
unmount(mount_point);
});
execute_mount(idx, this, drive_args, th);
}
}
} // namespace repertory
#endif