winfsp unit tests and fixes-support remote mount
This commit is contained in:
parent
f5993d472c
commit
cda89d0588
@ -986,16 +986,14 @@ auto remote_server::winfsp_create(PWSTR file_name, UINT32 create_options,
|
||||
{utils::string::to_utf8(file_name)}))
|
||||
.exists());
|
||||
|
||||
auto create_flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
auto create_flags{FILE_FLAG_BACKUP_SEMANTICS};
|
||||
if ((create_options & FILE_DIRECTORY_FILE) != 0U) {
|
||||
create_flags |= FILE_FLAG_POSIX_SEMANTICS;
|
||||
attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
} else {
|
||||
attributes &= static_cast<UINT32>(
|
||||
~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NORMAL));
|
||||
attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
attributes |=
|
||||
((create_options & FILE_DIRECTORY_FILE) == 0U ? FILE_ATTRIBUTE_ARCHIVE
|
||||
: FILE_ATTRIBUTE_DIRECTORY);
|
||||
auto *handle = ::CreateFileW(
|
||||
file_path.c_str(), granted_access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
|
||||
@ -1161,34 +1159,23 @@ auto remote_server::winfsp_overwrite(PVOID file_desc, UINT32 attributes,
|
||||
auto *handle = reinterpret_cast<HANDLE>(file_desc);
|
||||
auto ret = has_open_info(handle, STATUS_INVALID_HANDLE);
|
||||
if (ret == STATUS_SUCCESS) {
|
||||
if (replace_attributes != 0U) {
|
||||
if (attributes == 0U) {
|
||||
attributes = FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
if (replace_attributes != 0U) {
|
||||
FILE_BASIC_INFO basic_info{};
|
||||
basic_info.FileAttributes = attributes;
|
||||
if (::SetFileInformationByHandle(handle, FileBasicInfo, &basic_info,
|
||||
sizeof(FILE_BASIC_INFO)) == 0) {
|
||||
ret = FspNtStatusFromWin32(::GetLastError());
|
||||
}
|
||||
} else if (attributes != 0U) {
|
||||
} else {
|
||||
FILE_ATTRIBUTE_TAG_INFO tag_info{};
|
||||
if (::GetFileInformationByHandleEx(
|
||||
handle, FileAttributeTagInfo, &tag_info,
|
||||
sizeof(FILE_ATTRIBUTE_TAG_INFO)) == 0) {
|
||||
ret = FspNtStatusFromWin32(::GetLastError());
|
||||
if (::GetFileInformationByHandleEx(handle, FileAttributeTagInfo,
|
||||
&tag_info,
|
||||
sizeof(FILE_ATTRIBUTE_TAG_INFO))) {
|
||||
attributes |= tag_info.FileAttributes;
|
||||
} else {
|
||||
FILE_BASIC_INFO basic_info{};
|
||||
basic_info.FileAttributes =
|
||||
attributes | (tag_info.FileAttributes &
|
||||
static_cast<UINT32>(~FILE_ATTRIBUTE_NORMAL));
|
||||
if ((basic_info.FileAttributes != tag_info.FileAttributes)) {
|
||||
if (::SetFileInformationByHandle(handle, FileBasicInfo, &basic_info,
|
||||
sizeof(FILE_BASIC_INFO)) == 0) {
|
||||
ret = FspNtStatusFromWin32(::GetLastError());
|
||||
}
|
||||
}
|
||||
ret = FspNtStatusFromWin32(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp"
|
||||
#include "drives/winfsp/winfsp_drive.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
@ -42,215 +42,242 @@ constexpr const auto SLEEP_SECONDS{1.5s};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
struct local_s3 final {
|
||||
static constexpr const provider_type type{provider_type::s3};
|
||||
static constexpr const provider_type type2{provider_type::s3};
|
||||
};
|
||||
|
||||
struct local_sia final {
|
||||
static constexpr const provider_type type{provider_type::sia};
|
||||
static constexpr const provider_type type2{provider_type::sia};
|
||||
};
|
||||
|
||||
struct remote_s3 final {
|
||||
static constexpr const provider_type type{provider_type::remote};
|
||||
static constexpr const provider_type type2{provider_type::s3};
|
||||
};
|
||||
|
||||
struct remote_sia final {
|
||||
static constexpr const provider_type type{provider_type::remote};
|
||||
static constexpr const provider_type type2{provider_type::sia};
|
||||
};
|
||||
|
||||
template <typename provider_t> class winfsp_test : public ::testing::Test {
|
||||
public:
|
||||
static std::string cfg_directory;
|
||||
static std::unique_ptr<curl_comm> comm;
|
||||
static std::unique_ptr<app_config> config;
|
||||
static std::filesystem::path current_directory;
|
||||
static std::unique_ptr<winfsp_drive> drive;
|
||||
static std::vector<std::string> drive_args;
|
||||
static std::string mount_location;
|
||||
static std::unique_ptr<i_provider> provider;
|
||||
static std::string test_directory;
|
||||
static provider_type current_provider;
|
||||
static std::vector<std::string> drive_args;
|
||||
static std::vector<std::string> drive_args2;
|
||||
static std::string mount_location;
|
||||
static std::string mount_location2;
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase() {
|
||||
current_directory = std::filesystem::current_path();
|
||||
|
||||
test_directory = utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{
|
||||
"winfsp_test",
|
||||
app_config::get_provider_name(current_provider),
|
||||
});
|
||||
|
||||
mount_location = "U:";
|
||||
|
||||
cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||
|
||||
config = std::make_unique<app_config>(current_provider, cfg_directory);
|
||||
|
||||
switch (current_provider) {
|
||||
case provider_type::s3: {
|
||||
const auto mount_s3 = [&]() {
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::s3,
|
||||
utils::path::combine(test::get_test_config_dir(), {"s3"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
config->set_s3_config(src_cfg.get_s3_config());
|
||||
auto test_directory = utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{
|
||||
"winfsp_test",
|
||||
app_config::get_provider_name(provider_type::s3),
|
||||
});
|
||||
|
||||
mount_location = "U:";
|
||||
|
||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||
|
||||
auto config =
|
||||
std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::s3,
|
||||
utils::path::combine(test::get_test_config_dir(), {"s3"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
config->set_s3_config(src_cfg.get_s3_config());
|
||||
config->set_enable_remote_mount(true);
|
||||
config->set_remote_port(30000U);
|
||||
}
|
||||
|
||||
drive_args = std::vector<std::string>({
|
||||
"-dd",
|
||||
config->get_data_directory(),
|
||||
"-s3",
|
||||
"-na",
|
||||
"s3",
|
||||
mount_location,
|
||||
});
|
||||
}
|
||||
execute_mount(drive_args, mount_location);
|
||||
};
|
||||
|
||||
const auto mount_sia = [&]() {
|
||||
{
|
||||
auto test_directory = utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{
|
||||
"winfsp_test",
|
||||
app_config::get_provider_name(provider_type::sia),
|
||||
});
|
||||
|
||||
mount_location = "U:";
|
||||
|
||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||
|
||||
auto config =
|
||||
std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::sia,
|
||||
utils::path::combine(test::get_test_config_dir(), {"sia"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
config->set_host_config(src_cfg.get_host_config());
|
||||
config->set_sia_config(src_cfg.get_sia_config());
|
||||
config->set_enable_remote_mount(true);
|
||||
config->set_remote_port(30000U);
|
||||
}
|
||||
|
||||
drive_args = std::vector<std::string>({
|
||||
"-dd",
|
||||
config->get_data_directory(),
|
||||
"-na",
|
||||
"sia",
|
||||
mount_location,
|
||||
});
|
||||
}
|
||||
|
||||
drive_args = std::vector<std::string>({
|
||||
"-s3",
|
||||
"-na",
|
||||
"s3",
|
||||
});
|
||||
execute_mount(drive_args, mount_location);
|
||||
};
|
||||
|
||||
const auto mount_remote = [&]() {
|
||||
{
|
||||
auto test_directory = utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{
|
||||
"winfsp_test",
|
||||
app_config::get_provider_name(provider_type::remote),
|
||||
});
|
||||
|
||||
mount_location2 = mount_location;
|
||||
mount_location = "V:";
|
||||
|
||||
auto cfg_directory = utils::path::combine(test_directory, {"cfg2"});
|
||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||
|
||||
auto config =
|
||||
std::make_unique<app_config>(provider_type::remote, cfg_directory);
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
|
||||
drive_args2 = std::vector<std::string>({
|
||||
"-dd",
|
||||
config->get_data_directory(),
|
||||
"-rm",
|
||||
"localhost:30000",
|
||||
mount_location,
|
||||
});
|
||||
}
|
||||
|
||||
execute_mount(drive_args2, mount_location);
|
||||
};
|
||||
|
||||
switch (provider_t::type) {
|
||||
case provider_type::s3: {
|
||||
mount_s3();
|
||||
} break;
|
||||
|
||||
case provider_type::sia: {
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::sia,
|
||||
utils::path::combine(test::get_test_config_dir(), {"sia"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
config->set_host_config(src_cfg.get_host_config());
|
||||
config->set_sia_config(src_cfg.get_sia_config());
|
||||
mount_sia();
|
||||
} break;
|
||||
|
||||
case provider_type::remote: {
|
||||
switch (provider_t::type2) {
|
||||
case provider_type::s3: {
|
||||
mount_s3();
|
||||
} break;
|
||||
|
||||
case provider_type::sia: {
|
||||
mount_sia();
|
||||
} break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("remote provider type is not implemented");
|
||||
return;
|
||||
}
|
||||
|
||||
drive_args = std::vector<std::string>({
|
||||
"-na",
|
||||
"sia",
|
||||
});
|
||||
mount_remote();
|
||||
} break;
|
||||
// case 0U: {
|
||||
// config =
|
||||
// std::make_unique<app_config>(provider_type::encrypt,
|
||||
// cfg_directory);
|
||||
// {
|
||||
// app_config src_cfg(
|
||||
// provider_type::s3,
|
||||
// utils::path::combine(test::get_test_input_dir(), {"encrypt"}));
|
||||
// config->set_enable_drive_events(true);
|
||||
// config->set_event_level(event_level::trace);
|
||||
// config->set_s3_config(src_cfg.get_s3_config());
|
||||
// }
|
||||
// } break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("provider type is not implemented");
|
||||
return;
|
||||
}
|
||||
|
||||
drive_args.push_back(mount_location);
|
||||
execute_mount();
|
||||
}
|
||||
|
||||
static void TearDownTestCase() {
|
||||
execute_unmount();
|
||||
if (provider_t::type == provider_type::remote) {
|
||||
execute_unmount(drive_args2, mount_location);
|
||||
execute_unmount(drive_args, mount_location2);
|
||||
} else {
|
||||
execute_unmount(drive_args, mount_location);
|
||||
}
|
||||
std::filesystem::current_path(current_directory);
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] static auto create_directory_and_test(std::string &dir_name)
|
||||
-> std::string {
|
||||
dir_name += std::to_string(++idx);
|
||||
auto api_path = utils::path::create_api_path(dir_name);
|
||||
auto dir_path = utils::path::combine(mount_location, {dir_name});
|
||||
|
||||
EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
EXPECT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||
EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
return dir_path;
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto create_file_and_test(std::string &file_name)
|
||||
-> std::string {
|
||||
file_name += std::to_string(++idx);
|
||||
auto api_path = utils::path::create_api_path(file_name);
|
||||
auto file_path = utils::path::combine(mount_location, {file_name});
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file_path).exists());
|
||||
|
||||
auto opt_size = utils::file::file(file_path).size();
|
||||
EXPECT_TRUE(opt_size.has_value());
|
||||
EXPECT_EQ(0, opt_size.value());
|
||||
|
||||
std::string attr;
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider->get_item_meta(api_path, META_ATTRIBUTES, attr));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_ARCHIVE, utils::string::to_uint32(attr));
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static void delete_directory_and_test(const std::string &dir_path) {
|
||||
EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
}
|
||||
|
||||
static void delete_file_and_test(std::string_view file_path) {
|
||||
EXPECT_TRUE(utils::file::file(file_path).remove());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
}
|
||||
|
||||
static void execute_mount() {
|
||||
auto mount_cmd = "start .\\repertory.exe -f -dd \"" +
|
||||
config->get_data_directory() + "\"" + " " +
|
||||
utils::string::join(drive_args, ' ');
|
||||
static void execute_mount(auto args, auto location) {
|
||||
auto mount_cmd =
|
||||
"start .\\repertory.exe -f " + utils::string::join(args, ' ');
|
||||
std::cout << "mount command: " << mount_cmd << std::endl;
|
||||
ASSERT_EQ(0, system(mount_cmd.c_str()));
|
||||
std::this_thread::sleep_for(5s);
|
||||
ASSERT_TRUE(utils::file::directory{mount_location}.exists());
|
||||
ASSERT_TRUE(utils::file::directory{location}.exists());
|
||||
}
|
||||
|
||||
static void execute_unmount() {
|
||||
static void execute_unmount(auto args, auto location) {
|
||||
auto unmounted{false};
|
||||
|
||||
auto unmount_cmd = ".\\repertory.exe -dd \"" +
|
||||
config->get_data_directory() + "\"" + " " +
|
||||
utils::string::join(drive_args, ' ') + " -unmount";
|
||||
for (int i = 0; not unmounted && (i < 50); i++) {
|
||||
auto unmount_cmd =
|
||||
".\\repertory.exe " + utils::string::join(args, ' ') + " -unmount";
|
||||
for (int i = 0; not unmounted && (i < 6); i++) {
|
||||
std::cout << "unmount command: " << unmount_cmd << std::endl;
|
||||
system(unmount_cmd.c_str());
|
||||
unmounted = not utils::file::directory{mount_location}.exists();
|
||||
unmounted = not utils::file::directory{location}.exists();
|
||||
if (not unmounted) {
|
||||
std::this_thread::sleep_for(5s);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unmounted);
|
||||
ASSERT_TRUE(unmounted);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::cfg_directory;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<curl_comm> winfsp_test<provider_t>::comm;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<app_config> winfsp_test<provider_t>::config;
|
||||
|
||||
template <typename provider_t>
|
||||
std::filesystem::path winfsp_test<provider_t>::current_directory;
|
||||
|
||||
template <typename provider_t>
|
||||
provider_type winfsp_test<provider_t>::current_provider{provider_t::type};
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<winfsp_drive> winfsp_test<provider_t>::drive;
|
||||
provider_type winfsp_test<provider_t>::current_provider{provider_t::type2};
|
||||
|
||||
template <typename provider_t>
|
||||
std::vector<std::string> winfsp_test<provider_t>::drive_args;
|
||||
|
||||
template <typename provider_t>
|
||||
std::vector<std::string> winfsp_test<provider_t>::drive_args2;
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::mount_location;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<i_provider> winfsp_test<provider_t>::provider;
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::test_directory;
|
||||
|
||||
using winfsp_provider_types = ::testing::Types<s3_provider>;
|
||||
// using winfsp_provider_types = ::testing::Types<s3_provider, sia_provider>;
|
||||
std::string winfsp_test<provider_t>::mount_location2;
|
||||
// using winfsp_provider_types = ::testing::Types<local_s3, local_sia,
|
||||
// remote_s3, remote_sia>;
|
||||
using winfsp_provider_types = ::testing::Types<local_s3, remote_s3>;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
|
@ -138,6 +138,9 @@ TYPED_TEST(winfsp_test, info_can_get_file_name_info) {
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
FILETIME file_time{};
|
||||
::GetSystemTimeAsFileTime(&file_time);
|
||||
|
||||
auto time_low = ((PLARGE_INTEGER)&file_time)->QuadPart;
|
||||
auto time_high = time_low + 10000 * 10000 /* 10 seconds */;
|
||||
|
||||
@ -153,14 +156,14 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandle(handle, &file_info));
|
||||
|
||||
EXPECT_LE(time_low, file_info.ftCreationTime.QuadPart);
|
||||
EXPECT_GT(time_high, file_info.ftCreationTime.QuadPart);
|
||||
EXPECT_LE(time_low, file_info.ftCreationTime.dwLowDateTime);
|
||||
EXPECT_GT(time_high, file_info.ftCreationTime.dwHighDateTime);
|
||||
|
||||
EXPECT_LE(time_low, file_info.ftLastAccessTime.QuadPart);
|
||||
EXPECT_GT(time_high, file_info.ftLastAccessTime.QuadPart);
|
||||
EXPECT_LE(time_low, file_info.ftLastAccessTime.dwLowDateTime);
|
||||
EXPECT_GT(time_high, file_info.ftLastAccessTime.dwHighDateTime);
|
||||
|
||||
EXPECT_LE(time_low, file_info.ftLastWriteTime.QuadPart);
|
||||
EXPECT_GT(time_high, file_info.ftLastWriteTime.QuadPart);
|
||||
EXPECT_LE(time_low, file_info.ftLastWriteTime.dwLowDateTime);
|
||||
EXPECT_GT(time_high, file_info.ftLastWriteTime.dwHighDateTime);
|
||||
|
||||
EXPECT_EQ(0U, file_info.nFileSizeHigh);
|
||||
EXPECT_EQ(0U, file_info.nFileSizeLow);
|
||||
@ -169,7 +172,7 @@ TYPED_TEST(winfsp_test, info_can_get_file_info) {
|
||||
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_ARCHIVE, file_info.dwFileAttributes);
|
||||
|
||||
EXPECT_EQ(0U, file_info.dwVolumeSerialNumber)
|
||||
EXPECT_EQ(0U, file_info.dwVolumeSerialNumber);
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user