refactor winfsp test

This commit is contained in:
Scott E. Graves 2024-10-22 08:00:16 -05:00
parent cdfbaa47b6
commit b4d61649cb
4 changed files with 578 additions and 495 deletions

View File

@ -55,7 +55,6 @@ public:
static std::unique_ptr<app_config> config; static std::unique_ptr<app_config> config;
static std::filesystem::path current_directory; static std::filesystem::path current_directory;
static std::unique_ptr<fuse_drive> drive; static std::unique_ptr<fuse_drive> drive;
static lock_data lock_data_;
static std::string mount_location; static std::string mount_location;
static std::unique_ptr<i_provider> provider; static std::unique_ptr<i_provider> provider;
static std::string test_directory; static std::string test_directory;
@ -194,15 +193,20 @@ public:
std::cout << "mount command: " << mount_cmd << std::endl; std::cout << "mount command: " << mount_cmd << std::endl;
ASSERT_EQ(0, system(mount_cmd.c_str())); ASSERT_EQ(0, system(mount_cmd.c_str()));
std::this_thread::sleep_for(5s); std::this_thread::sleep_for(5s);
EXPECT_EQ(0, system(("mount|grep \"" + mount_location + "\"").c_str())); ASSERT_TRUE(utils::file::directory{mount_location}.exists());
} }
static void execute_unmount() { static void execute_unmount() {
auto unmounted{false}; auto unmounted{false};
auto unmount_cmd =
"./repertory -dd \"" + config->get_data_directory() + "\" -unmount";
for (int i = 0; not unmounted && (i < 50); i++) { for (int i = 0; not unmounted && (i < 50); i++) {
unmounted = (fuse_base::unmount(mount_location) == 0); std::cout << "unmount command: " << unmount_cmd << std::endl;
ASSERT_EQ(0, system(unmount_cmd.c_str()));
unmounted = not utils::file::directory{mount_location}.exists();
if (not unmounted) { if (not unmounted) {
std::this_thread::sleep_for(100ms); std::this_thread::sleep_for(5s);
} }
} }
@ -251,8 +255,6 @@ std::filesystem::path fuse_test<provider_t>::current_directory{};
template <typename provider_t> template <typename provider_t>
std::unique_ptr<fuse_drive> fuse_test<provider_t>::drive{}; std::unique_ptr<fuse_drive> fuse_test<provider_t>::drive{};
template <typename provider_t> lock_data fuse_test<provider_t>::lock_data_{};
template <typename provider_t> template <typename provider_t>
std::string fuse_test<provider_t>::mount_location{}; std::string fuse_test<provider_t>::mount_location{};
@ -262,7 +264,7 @@ std::unique_ptr<i_provider> fuse_test<provider_t>::provider{};
template <typename provider_t> template <typename provider_t>
std::string fuse_test<provider_t>::test_directory; std::string fuse_test<provider_t>::test_directory;
typedef ::testing::Types<s3_provider, sia_provider> fuse_provider_types; using fuse_provider_types = ::testing::Types<s3_provider, sia_provider>;
} // namespace repertory } // namespace repertory
#endif // !defined(_WIN32) #endif // !defined(_WIN32)

View File

@ -31,133 +31,186 @@
#include "platform/platform.hpp" #include "platform/platform.hpp"
#include "providers/s3/s3_provider.hpp" #include "providers/s3/s3_provider.hpp"
#include "providers/sia/sia_provider.hpp" #include "providers/sia/sia_provider.hpp"
#include "types/repertory.hpp"
#include "utils/event_capture.hpp"
#include "utils/file_utils.hpp" #include "utils/file_utils.hpp"
#include "utils/path.hpp" #include "utils/path.hpp"
extern std::size_t PROVIDER_INDEX; namespace {
std::atomic<std::size_t> idx{0U};
constexpr const auto SLEEP_SECONDS{1.5s};
} // namespace
namespace repertory { namespace repertory {
class winfsp_test : public ::testing::Test { template <typename provider_t> class winfsp_test : public ::testing::Test {
public: public:
lock_data lock_data_; static std::string cfg_directory;
std::unique_ptr<app_config> config; static std::unique_ptr<curl_comm> comm;
std::unique_ptr<curl_comm> comm; static std::unique_ptr<app_config> config;
std::unique_ptr<i_provider> provider; static std::filesystem::path current_directory;
std::unique_ptr<winfsp_drive> drive; static std::unique_ptr<winfsp_drive> drive;
static std::string mount_location;
static std::unique_ptr<i_provider> provider;
static std::string test_directory;
protected: protected:
void SetUp() override { static void SetUpTestCase() {
if (PROVIDER_INDEX != 0) { current_directory = std::filesystem::current_path();
if (PROVIDER_INDEX == 1) {
EXPECT_TRUE(utils::file::directory(
utils::path::combine(
test::get_test_output_dir(),
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}))
.remove_recursively());
app_config src_cfg( test_directory = utils::path::combine(
test::get_test_output_dir(),
{
"winfsp_test",
std::to_string(static_cast<std::uint8_t>(provider_t::type)),
});
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>(provider_t::type, cfg_directory);
std::vector<std::string> drive_args{};
switch (provider_t::type) {
case provider_type::s3: {
{
app_config src_cfg{
provider_type::s3, provider_type::s3,
utils::path::combine(test::get_test_input_dir(), {"storj"})); utils::path::combine(test::get_test_input_dir(), {"storj"}),
config = std::make_unique<app_config>( };
provider_type::s3, config->set_enable_drive_events(true);
utils::path::combine(
test::get_test_output_dir(),
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}));
EXPECT_FALSE(config
->set_value_by_name("S3Config.AccessKey",
src_cfg.get_s3_config().access_key)
.empty());
EXPECT_FALSE(config
->set_value_by_name("S3Config.SecretKey",
src_cfg.get_s3_config().secret_key)
.empty());
EXPECT_FALSE(config
->set_value_by_name("S3Config.Region",
src_cfg.get_s3_config().region)
.empty());
EXPECT_FALSE(
config
->set_value_by_name("S3Config.EncryptionToken",
src_cfg.get_s3_config().encryption_token)
.empty());
EXPECT_FALSE(
config
->set_value_by_name("S3Config.URL", src_cfg.get_s3_config().url)
.empty());
EXPECT_FALSE(
config->set_value_by_name("S3Config.Bucket", "repertory").empty());
config->set_event_level(event_level::trace); config->set_event_level(event_level::trace);
config->set_enable_drive_events(true); config->set_s3_config(src_cfg.get_s3_config());
event_system::instance().start();
comm = std::make_unique<curl_comm>(config->get_s3_config());
provider = std::make_unique<s3_provider>(*config, *comm);
drive = std::make_unique<winfsp_drive>(*config, lock_data_, *provider);
return;
} }
if (PROVIDER_INDEX == 2) { comm = std::make_unique<curl_comm>(config->get_s3_config());
EXPECT_TRUE(utils::file::directory( drive_args = std::vector<std::string>({
utils::path::combine( "-s3",
test::get_test_output_dir(), "-na",
{"winfsp_test" + std::to_string(PROVIDER_INDEX)})) "storj",
.remove_recursively()); });
} break;
app_config src_cfg( case provider_type::sia: {
{
app_config src_cfg{
provider_type::sia, provider_type::sia,
utils::path::combine(test::get_test_input_dir(), {"sia"})); utils::path::combine(test::get_test_input_dir(), {"sia"}),
config = std::make_unique<app_config>( };
provider_type::sia, config->set_enable_drive_events(true);
utils::path::combine(
test::get_test_output_dir(),
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}));
[[maybe_unused]] auto val = config->set_value_by_name(
"HostConfig.AgentString", src_cfg.get_host_config().agent_string);
EXPECT_FALSE(
config
->set_value_by_name("HostConfig.ApiPassword",
src_cfg.get_host_config().api_password)
.empty());
EXPECT_FALSE(config
->set_value_by_name(
"HostConfig.ApiPort",
std::to_string(src_cfg.get_host_config().api_port))
.empty());
EXPECT_FALSE(
config
->set_value_by_name("HostConfig.HostNameOrIp",
src_cfg.get_host_config().host_name_or_ip)
.empty());
config->set_event_level(event_level::debug); config->set_event_level(event_level::debug);
config->set_enable_drive_events(true); config->set_host_config(src_cfg.get_host_config());
event_system::instance().start();
comm = std::make_unique<curl_comm>(config->get_host_config());
provider = std::make_unique<sia_provider>(*config, *comm);
drive = std::make_unique<winfsp_drive>(*config, lock_data_, *provider);
return;
} }
comm = std::make_unique<curl_comm>(config->get_host_config());
} 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());
// }
//
// comm = std::make_unique<curl_comm>(config->get_s3_config());
// provider = std::make_unique<s3_provider>(*config, *comm);
// drive_args = std::vector<std::string>({"-en"});
// } break;
default:
throw std::runtime_error("provider type is not implemented");
return;
} }
provider = std::make_unique<provider_t>(*config, *comm);
drive_args.push_back(mount_location);
} }
void TearDown() override { static void TearDownTestCase() {
if (PROVIDER_INDEX != 0) { execute_unmount();
drive.reset(); std::filesystem::current_path(current_directory);
provider.reset(); [[maybe_unused]] auto ret =
comm.reset(); utils::file::directory(test_directory).remove_recursively();
config.reset(); /* if (PROVIDER_INDEX != 0) {
drive.reset();
provider.reset();
comm.reset();
config.reset();
event_system::instance().stop(); event_system::instance().stop();
EXPECT_TRUE(utils::file::directory( EXPECT_TRUE(utils::file::directory(
utils::path::combine( utils::path::combine(
test::get_test_output_dir(), test::get_test_output_dir(),
{"winfsp_test" + std::to_string(PROVIDER_INDEX)})) {"winfsp_test" + std::to_string(PROVIDER_INDEX)}))
.remove_recursively()); .remove_recursively());
} */
}
public:
static void delete_file_and_test(const std::string &file) {
event_capture ec({"file_removed"});
EXPECT_TRUE(utils::file::file(file).remove());
ec.wait_for_empty();
EXPECT_FALSE(utils::file::file(file).exists());
}
static void execute_mount(auto &&drive_args) {
auto mount_cmd = ".\\repertory.exe -dd \"" + config->get_data_directory() +
"\"" + " " + utils::string::join(drive_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());
}
static void execute_unmount() {
auto unmounted{false};
auto unmount_cmd = ".\\repertory.exe -dd \"" +
config->get_data_directory() + "\" -unmount";
for (int i = 0; not unmounted && (i < 50); i++) {
std::cout << "unmount command: " << unmount_cmd << std::endl;
ASSERT_EQ(0, system(unmount_cmd.c_str()));
unmounted = not utils::file::directory{mount_location}.exists();
if (not unmounted) {
std::this_thread::sleep_for(5s);
}
} }
EXPECT_TRUE(unmounted);
} }
}; };
template <typename provider_t>
std::string winfsp_test<provider_t>::cfg_directory;
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>
std::unique_ptr<curl_comm> winfsp_test<provider_t>::comm;
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;
template <typename provider_t>
std::unique_ptr<winfsp_drive> winfsp_test<provider_t>::drive;
using winfsp_provider_types = ::testing::Types<s3_provider, sia_provider>;
} // namespace repertory } // namespace repertory
#endif #endif // defined(_WIN32)
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP #endif // REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP

View File

@ -0,0 +1,413 @@
/*
Copyright <2018-2024> <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 0
#if defined(_WIN32)
#include "fixtures/winfsp_fixture.hpp"
namespace repertory {
// void launch_app(std::string cmd) {
// PROCESS_INFORMATION pi{};
// STARTUPINFO si{};
// si.cb = sizeof(si);
//
// if (!::CreateProcessA(nullptr, (LPSTR)cmd.c_str(), nullptr, nullptr, FALSE,
// CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, nullptr,
// nullptr, &si, &pi)) {
// throw std::runtime_error("CreateProcess failed (" +
// std::to_string(::GetLastError()) + ")");
// }
//
// ::WaitForSingleObject(pi.hProcess, INFINITE);
// DWORD code{};
// ::GetExitCodeProcess(pi.hProcess, &code);
//
// ::CloseHandle(pi.hProcess);
// ::CloseHandle(pi.hThread);
// EXPECT_EQ(0, code);
// }
//
// E_SIMPLE1(test_begin, info, false, std::string, test_name, TN, E_FROM_STRING);
// #define TEST_HEADER(func) \
// event_system::instance().raise<test_begin>( \
// std::string(func) + \
// "\r\n***********************\r\n***********************")
//
// static auto mount_setup(std::string &mount_point) {
// mount_point = "U:";
// return std::vector<std::string>({"unittests", "-f", mount_point});
// }
//
// static void execute_mount(winfsp_test *test,
// const std::vector<std::string> &drive_args,
// std::thread &th) {
// ASSERT_EQ(0, test->drive->mount(drive_args));
// th.join();
// }
//
// static void unmount(winfsp_test *test, const std::string &mount_point) {
// test->drive->shutdown();
// auto mounted = utils::file::directory(mount_point).exists();
// for (auto i = 0; mounted && (i < 50); i++) {
// std::this_thread::sleep_for(100ms);
// mounted = utils::file::directory(mount_point).exists();
// }
// EXPECT_FALSE(utils::file::directory(mount_point).exists());
// }
//
// static void root_creation_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
// WIN32_FILE_ATTRIBUTE_DATA ad{};
// EXPECT_TRUE(
// ::GetFileAttributesEx(mount_point.c_str(), GetFileExInfoStandard, &ad));
// EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes);
// EXPECT_EQ(0, ad.nFileSizeHigh);
// EXPECT_EQ(0, ad.nFileSizeLow);
// }
//
// static auto create_test(winfsp_test *test, const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
//
// auto file = utils::path::combine(mount_point, {{"test_create.txt"}});
// auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
// CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
// EXPECT_TRUE(::CloseHandle(handle));
//
// EXPECT_TRUE(utils::file::file(file).exists());
//
// auto opt_size = utils::file::file(file).size();
// EXPECT_TRUE(opt_size.has_value());
// EXPECT_EQ(0, opt_size.value());
//
// std::string attr;
// EXPECT_EQ(api_error::success, test->provider->get_item_meta(
// "/test_create.txt", META_ATTRIBUTES, attr));
// EXPECT_EQ(FILE_ATTRIBUTE_NORMAL, utils::string::to_uint32(attr));
//
// return file;
// }
//
// static void delete_file_test(const std::string &file) {
// TEST_HEADER(__FUNCTION__);
// event_capture ec({"file_removed"});
// EXPECT_TRUE(utils::file::file(file).remove());
// EXPECT_FALSE(utils::file::file(file).exists());
// }
//
// static void create_directory_test(const std::string &directory) {
// TEST_HEADER(__FUNCTION__);
//
// EXPECT_FALSE(::PathIsDirectory(&directory[0]));
// EXPECT_TRUE(::CreateDirectoryA(&directory[0], nullptr));
// EXPECT_TRUE(::PathIsDirectory(&directory[0]));
// }
//
// static void remove_directory_test(const std::string &directory) {
// TEST_HEADER(__FUNCTION__);
//
// event_capture ec({"directory_removed"});
// EXPECT_TRUE(::PathIsDirectory(&directory[0]));
// EXPECT_TRUE(::RemoveDirectoryA(&directory[0]));
// EXPECT_FALSE(::PathIsDirectory(&directory[0]));
// }
//
// static void write_file_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
//
// const auto file = utils::path::combine(mount_point, {"test_write.txt"});
// auto handle =
// ::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
// nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
// const std::string data = "0123456789";
// DWORD bytes_written = 0;
// EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
// &bytes_written, nullptr));
// EXPECT_EQ(10, bytes_written);
// EXPECT_TRUE(::CloseHandle(handle));
//
// EXPECT_TRUE(utils::file::file(file).exists());
//
// auto opt_size = utils::file::file(file).size();
// EXPECT_TRUE(opt_size.has_value());
// EXPECT_EQ(10U, opt_size.value());
// }
//
// static void read_file_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
//
// const auto file = utils::path::combine(mount_point, {"test_read.txt"});
// auto handle =
// ::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
// nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
// const std::string data = "0123456789";
// DWORD bytes_written = 0;
// EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
// &bytes_written, nullptr));
// EXPECT_EQ(10, bytes_written);
//
// data_buffer data2;
// data2.resize(10);
// DWORD bytes_read = 0;
// EXPECT_EQ(0, ::SetFilePointer(handle, 0, nullptr, FILE_BEGIN));
// EXPECT_TRUE(::ReadFile(handle, &data2[0], static_cast<DWORD>(data2.size()),
// &bytes_read, nullptr));
// EXPECT_EQ(10, bytes_read);
// for (auto i = 0; i < data.size(); i++) {
// EXPECT_EQ(data[i], data2[i]);
// }
// EXPECT_TRUE(::CloseHandle(handle));
// }
//
// static void rename_file_test(winfsp_test *test,
// const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
// const auto file = utils::path::combine(mount_point, {"rename_file.txt"});
// auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
// CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
// EXPECT_TRUE(::CloseHandle(handle));
//
// api_meta_map meta1{};
// EXPECT_EQ(api_error::success,
// test->provider->get_item_meta("/rename_file.txt", meta1));
//
// const auto file2 = utils::path::combine(mount_point, {"rename_file2.txt"});
// EXPECT_TRUE(::MoveFile(&file[0], &file2[0]));
//
// EXPECT_TRUE(utils::file::file(file2).exists());
// EXPECT_FALSE(utils::file::file(file).exists());
//
// api_meta_map meta2{};
// EXPECT_EQ(api_error::success,
// test->provider->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, test->provider->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,
// test->provider->get_filesystem_item_from_source_path(
// fsi.source_path, fsi2));
// EXPECT_STREQ("/rename_file2.txt", fsi2.api_path.c_str());
//
// EXPECT_EQ(api_error::item_not_found,
// test->provider->get_item_meta("/rename_file.txt", meta2));
// }
//
// static void rename_directory_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
// std::string directory = "rename_dir";
// const auto full_directory = utils::path::combine(mount_point, {directory});
// std::string directory2 = "rename_dir2";
// const auto full_directory2 = utils::path::combine(mount_point, {directory2});
//
// EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
// EXPECT_TRUE(::CreateDirectoryA(&full_directory[0], nullptr));
// EXPECT_TRUE(::PathIsDirectory(&full_directory[0]));
// EXPECT_TRUE(::MoveFile(&full_directory[0], &full_directory2[0]));
// EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
// EXPECT_TRUE(::PathIsDirectory(&full_directory2[0]));
// }
//
// static void get_set_basic_info_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
//
// const auto file =
// utils::path::combine(mount_point, {"setbasicinfo_file.txt"});
// auto handle =
// ::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
// nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
//
// SYSTEMTIME st{};
// ::GetSystemTime(&st);
// st.wMinute = 0;
//
// FILETIME test_ch_time{};
// st.wMinute++;
// ::SystemTimeToFileTime(&st, &test_ch_time);
//
// FILETIME test_cr_time{};
// st.wMinute++;
// ::SystemTimeToFileTime(&st, &test_cr_time);
//
// FILETIME test_la_time{};
// st.wMinute++;
// ::SystemTimeToFileTime(&st, &test_la_time);
//
// FILETIME test_lw_time{};
// st.wMinute++;
// ::SystemTimeToFileTime(&st, &test_lw_time);
//
// FILE_BASIC_INFO fbi{};
// fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
// fbi.ChangeTime.HighPart = test_ch_time.dwHighDateTime;
// fbi.ChangeTime.LowPart = test_ch_time.dwLowDateTime;
// fbi.CreationTime = *(LARGE_INTEGER *)&test_cr_time;
// fbi.LastAccessTime = *(LARGE_INTEGER *)&test_la_time;
// fbi.LastWriteTime = *(LARGE_INTEGER *)&test_lw_time;
//
// EXPECT_TRUE(::SetFileInformationByHandle(handle, FileBasicInfo, &fbi,
// sizeof(FILE_BASIC_INFO)));
//
// FILE_BASIC_INFO fbi2{};
// EXPECT_TRUE(::GetFileInformationByHandleEx(handle, FileBasicInfo, &fbi2,
// sizeof(FILE_BASIC_INFO)));
//
// EXPECT_EQ(0, memcmp(&fbi, &fbi2, sizeof(FILE_BASIC_INFO)));
//
// std::cout << fbi.FileAttributes << " " << fbi.ChangeTime.QuadPart << " "
// << fbi.CreationTime.QuadPart << " " << fbi.LastAccessTime.QuadPart
// << " " << fbi.LastWriteTime.QuadPart << std::endl;
// std::cout << fbi2.FileAttributes << " " << fbi2.ChangeTime.QuadPart << " "
// << fbi2.CreationTime.QuadPart << " " << fbi2.LastAccessTime.QuadPart
// << " " << fbi2.LastWriteTime.QuadPart << std::endl;
//
// EXPECT_TRUE(::CloseHandle(handle));
// }
//
// static void overwrite_file_test(const std::string &mount_point) {
// TEST_HEADER(__FUNCTION__);
//
// const auto file = utils::path::combine("./", {"test_overwrite.txt"});
// auto handle =
// ::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
// nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// EXPECT_NE(INVALID_HANDLE_VALUE, handle);
// if (handle != INVALID_HANDLE_VALUE) {
// const std::string data = "0123456789";
// DWORD bytes_written = 0;
// EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
// &bytes_written, nullptr));
// EXPECT_EQ(10, bytes_written);
// EXPECT_TRUE(::CloseHandle(handle));
//
// if (bytes_written == 10) {
// const auto file2 =
// utils::path::combine(mount_point, {"test_overwrite2.txt"});
// EXPECT_TRUE(::CopyFile(&file[0], &file2[0], TRUE));
//
// EXPECT_FALSE(::CopyFile(&file[0], &file2[0], TRUE));
// }
// }
// }
//
// TEST_F(winfsp_test, all_tests) {
// if (PROVIDER_INDEX == 0) {
// for (std::size_t idx = 0U; idx < 2U; idx++) {
// launch_app(
// ("cmd.exe /c unittests.exe --gtest_filter=winfsp_test.all_tests "
// "--provider_index " +
// std::to_string(idx) + " > unittests" + std::to_string(idx) +
// ".log 2>&1"));
// }
//
// return;
// }
//
// if (PROVIDER_INDEX == 1U) {
// return;
// }
//
// std::string mount_point;
// const auto drive_args = mount_setup(mount_point);
//
// 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) {
// root_creation_test(mount_point);
// {
// const auto file = create_test(this, mount_point);
// delete_file_test(file);
// }
// {
// const auto dir = utils::path::combine(mount_point, {"TestDir"});
// create_directory_test(dir);
// remove_directory_test(dir);
// }
// write_file_test(mount_point);
// read_file_test(mount_point);
// // TODO enable after rename support is available
// // rename_file_test(this, mount_point);
// // rename_directory_test(mount_point);
// overwrite_file_test(mount_point);
// get_set_basic_info_test(mount_point);
// }
//
// if (mounted) {
// unmount(this, mount_point);
// ec.wait_for_empty();
// }
// });
//
// execute_mount(this, drive_args, th);
// }
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
TYPED_TEST(winfsp_test, root_is_created) {
WIN32_FILE_ATTRIBUTE_DATA ad{};
ASSERT_TRUE(
::GetFileAttributesEx(mount_location.c_str(), GetFileExInfoStandard, &ad));
EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes);
EXPECT_EQ(0, ad.nFileSizeHigh);
EXPECT_EQ(0, ad.nFileSizeLow);
}
TYPED_TEST(winfsp_test, can_create_and_delete_file) {
auto file = utils::path::combine(mount_location, {"test_create.txt"});
auto handle = ::CreateFileA(file.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
EXPECT_TRUE(::CloseHandle(handle));
EXPECT_TRUE(utils::file::file(file).exists());
auto opt_size = utils::file::file(file).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(
"/test_create.txt", META_ATTRIBUTES, attr));
EXPECT_EQ(FILE_ATTRIBUTE_NORMAL, utils::string::to_uint32(attr));
delete_file_and_test(file);
}
} // namespace repertory
#endif // defined(_WIN32)
#endif // 0

View File

@ -1,385 +0,0 @@
/*
Copyright <2018-2024> <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 0
#if defined(_WIN32)
#include "test_common.hpp"
#include "fixtures/winfsp_fixture.hpp"
#include "types/repertory.hpp"
#include "utils/event_capture.hpp"
namespace repertory {
void launch_app(std::string cmd) {
PROCESS_INFORMATION pi{};
STARTUPINFO si{};
si.cb = sizeof(si);
if (!::CreateProcessA(nullptr, (LPSTR)cmd.c_str(), nullptr, nullptr, FALSE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, nullptr,
nullptr, &si, &pi)) {
throw std::runtime_error("CreateProcess failed (" +
std::to_string(::GetLastError()) + ")");
}
::WaitForSingleObject(pi.hProcess, INFINITE);
DWORD code{};
::GetExitCodeProcess(pi.hProcess, &code);
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
EXPECT_EQ(0, code);
}
E_SIMPLE1(test_begin, info, false, std::string, test_name, TN, E_FROM_STRING);
#define TEST_HEADER(func) \
event_system::instance().raise<test_begin>( \
std::string(func) + \
"\r\n***********************\r\n***********************")
static auto mount_setup(std::string &mount_point) {
mount_point = "U:";
return std::vector<std::string>({"unittests", "-f", mount_point});
}
static void execute_mount(winfsp_test *test,
const std::vector<std::string> &drive_args,
std::thread &th) {
ASSERT_EQ(0, test->drive->mount(drive_args));
th.join();
}
static void unmount(winfsp_test *test, const std::string &mount_point) {
test->drive->shutdown();
auto mounted = utils::file::directory(mount_point).exists();
for (auto i = 0; mounted && (i < 50); i++) {
std::this_thread::sleep_for(100ms);
mounted = utils::file::directory(mount_point).exists();
}
EXPECT_FALSE(utils::file::directory(mount_point).exists());
}
static void root_creation_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
WIN32_FILE_ATTRIBUTE_DATA ad{};
EXPECT_TRUE(
::GetFileAttributesEx(mount_point.c_str(), GetFileExInfoStandard, &ad));
EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes);
EXPECT_EQ(0, ad.nFileSizeHigh);
EXPECT_EQ(0, ad.nFileSizeLow);
}
static auto create_test(winfsp_test *test, const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
auto file = utils::path::combine(mount_point, {{"test_create.txt"}});
auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
EXPECT_TRUE(::CloseHandle(handle));
EXPECT_TRUE(utils::file::file(file).exists());
auto opt_size = utils::file::file(file).size();
EXPECT_TRUE(opt_size.has_value());
EXPECT_EQ(0, opt_size.value());
std::string attr;
EXPECT_EQ(api_error::success, test->provider->get_item_meta(
"/test_create.txt", META_ATTRIBUTES, attr));
EXPECT_EQ(FILE_ATTRIBUTE_NORMAL, utils::string::to_uint32(attr));
return file;
}
static void delete_file_test(const std::string &file) {
TEST_HEADER(__FUNCTION__);
event_capture ec({"file_removed"});
EXPECT_TRUE(utils::file::file(file).remove());
EXPECT_FALSE(utils::file::file(file).exists());
}
static void create_directory_test(const std::string &directory) {
TEST_HEADER(__FUNCTION__);
EXPECT_FALSE(::PathIsDirectory(&directory[0]));
EXPECT_TRUE(::CreateDirectoryA(&directory[0], nullptr));
EXPECT_TRUE(::PathIsDirectory(&directory[0]));
}
static void remove_directory_test(const std::string &directory) {
TEST_HEADER(__FUNCTION__);
event_capture ec({"directory_removed"});
EXPECT_TRUE(::PathIsDirectory(&directory[0]));
EXPECT_TRUE(::RemoveDirectoryA(&directory[0]));
EXPECT_FALSE(::PathIsDirectory(&directory[0]));
}
static void write_file_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
const auto file = utils::path::combine(mount_point, {"test_write.txt"});
auto handle =
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
const std::string data = "0123456789";
DWORD bytes_written = 0;
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
&bytes_written, nullptr));
EXPECT_EQ(10, bytes_written);
EXPECT_TRUE(::CloseHandle(handle));
EXPECT_TRUE(utils::file::file(file).exists());
auto opt_size = utils::file::file(file).size();
EXPECT_TRUE(opt_size.has_value());
EXPECT_EQ(10U, opt_size.value());
}
static void read_file_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
const auto file = utils::path::combine(mount_point, {"test_read.txt"});
auto handle =
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
const std::string data = "0123456789";
DWORD bytes_written = 0;
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
&bytes_written, nullptr));
EXPECT_EQ(10, bytes_written);
data_buffer data2;
data2.resize(10);
DWORD bytes_read = 0;
EXPECT_EQ(0, ::SetFilePointer(handle, 0, nullptr, FILE_BEGIN));
EXPECT_TRUE(::ReadFile(handle, &data2[0], static_cast<DWORD>(data2.size()),
&bytes_read, nullptr));
EXPECT_EQ(10, bytes_read);
for (auto i = 0; i < data.size(); i++) {
EXPECT_EQ(data[i], data2[i]);
}
EXPECT_TRUE(::CloseHandle(handle));
}
static void rename_file_test(winfsp_test *test,
const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
const auto file = utils::path::combine(mount_point, {"rename_file.txt"});
auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
EXPECT_TRUE(::CloseHandle(handle));
api_meta_map meta1{};
EXPECT_EQ(api_error::success,
test->provider->get_item_meta("/rename_file.txt", meta1));
const auto file2 = utils::path::combine(mount_point, {"rename_file2.txt"});
EXPECT_TRUE(::MoveFile(&file[0], &file2[0]));
EXPECT_TRUE(utils::file::file(file2).exists());
EXPECT_FALSE(utils::file::file(file).exists());
api_meta_map meta2{};
EXPECT_EQ(api_error::success,
test->provider->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, test->provider->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,
test->provider->get_filesystem_item_from_source_path(
fsi.source_path, fsi2));
EXPECT_STREQ("/rename_file2.txt", fsi2.api_path.c_str());
EXPECT_EQ(api_error::item_not_found,
test->provider->get_item_meta("/rename_file.txt", meta2));
}
static void rename_directory_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
std::string directory = "rename_dir";
const auto full_directory = utils::path::combine(mount_point, {directory});
std::string directory2 = "rename_dir2";
const auto full_directory2 = utils::path::combine(mount_point, {directory2});
EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
EXPECT_TRUE(::CreateDirectoryA(&full_directory[0], nullptr));
EXPECT_TRUE(::PathIsDirectory(&full_directory[0]));
EXPECT_TRUE(::MoveFile(&full_directory[0], &full_directory2[0]));
EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
EXPECT_TRUE(::PathIsDirectory(&full_directory2[0]));
}
static void get_set_basic_info_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
const auto file =
utils::path::combine(mount_point, {"setbasicinfo_file.txt"});
auto handle =
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
SYSTEMTIME st{};
::GetSystemTime(&st);
st.wMinute = 0;
FILETIME test_ch_time{};
st.wMinute++;
::SystemTimeToFileTime(&st, &test_ch_time);
FILETIME test_cr_time{};
st.wMinute++;
::SystemTimeToFileTime(&st, &test_cr_time);
FILETIME test_la_time{};
st.wMinute++;
::SystemTimeToFileTime(&st, &test_la_time);
FILETIME test_lw_time{};
st.wMinute++;
::SystemTimeToFileTime(&st, &test_lw_time);
FILE_BASIC_INFO fbi{};
fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
fbi.ChangeTime.HighPart = test_ch_time.dwHighDateTime;
fbi.ChangeTime.LowPart = test_ch_time.dwLowDateTime;
fbi.CreationTime = *(LARGE_INTEGER *)&test_cr_time;
fbi.LastAccessTime = *(LARGE_INTEGER *)&test_la_time;
fbi.LastWriteTime = *(LARGE_INTEGER *)&test_lw_time;
EXPECT_TRUE(::SetFileInformationByHandle(handle, FileBasicInfo, &fbi,
sizeof(FILE_BASIC_INFO)));
FILE_BASIC_INFO fbi2{};
EXPECT_TRUE(::GetFileInformationByHandleEx(handle, FileBasicInfo, &fbi2,
sizeof(FILE_BASIC_INFO)));
EXPECT_EQ(0, memcmp(&fbi, &fbi2, sizeof(FILE_BASIC_INFO)));
std::cout << fbi.FileAttributes << " " << fbi.ChangeTime.QuadPart << " "
<< fbi.CreationTime.QuadPart << " " << fbi.LastAccessTime.QuadPart
<< " " << fbi.LastWriteTime.QuadPart << std::endl;
std::cout << fbi2.FileAttributes << " " << fbi2.ChangeTime.QuadPart << " "
<< fbi2.CreationTime.QuadPart << " " << fbi2.LastAccessTime.QuadPart
<< " " << fbi2.LastWriteTime.QuadPart << std::endl;
EXPECT_TRUE(::CloseHandle(handle));
}
static void overwrite_file_test(const std::string &mount_point) {
TEST_HEADER(__FUNCTION__);
const auto file = utils::path::combine("./", {"test_overwrite.txt"});
auto handle =
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
if (handle != INVALID_HANDLE_VALUE) {
const std::string data = "0123456789";
DWORD bytes_written = 0;
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
&bytes_written, nullptr));
EXPECT_EQ(10, bytes_written);
EXPECT_TRUE(::CloseHandle(handle));
if (bytes_written == 10) {
const auto file2 =
utils::path::combine(mount_point, {"test_overwrite2.txt"});
EXPECT_TRUE(::CopyFile(&file[0], &file2[0], TRUE));
EXPECT_FALSE(::CopyFile(&file[0], &file2[0], TRUE));
}
}
}
TEST_F(winfsp_test, all_tests) {
if (PROVIDER_INDEX == 0) {
for (std::size_t idx = 0U; idx < 2U; idx++) {
launch_app(
("cmd.exe /c unittests.exe --gtest_filter=winfsp_test.all_tests "
"--provider_index " +
std::to_string(idx) + " > unittests" + std::to_string(idx) +
".log 2>&1"));
}
return;
}
if (PROVIDER_INDEX == 1U) {
return;
}
std::string mount_point;
const auto drive_args = mount_setup(mount_point);
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) {
root_creation_test(mount_point);
{
const auto file = create_test(this, mount_point);
delete_file_test(file);
}
{
const auto dir = utils::path::combine(mount_point, {"TestDir"});
create_directory_test(dir);
remove_directory_test(dir);
}
write_file_test(mount_point);
read_file_test(mount_point);
// TODO enable after rename support is available
// rename_file_test(this, mount_point);
// rename_directory_test(mount_point);
overwrite_file_test(mount_point);
get_set_basic_info_test(mount_point);
}
if (mounted) {
unmount(this, mount_point);
ec.wait_for_empty();
}
});
execute_mount(this, drive_args, th);
}
} // namespace repertory
#endif // defined(_WIN32)
#endif // 0