diff --git a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp index 1dbf6e08..2d6686a4 100644 --- a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp @@ -55,7 +55,6 @@ public: static std::unique_ptr config; static std::filesystem::path current_directory; static std::unique_ptr drive; - static lock_data lock_data_; static std::string mount_location; static std::unique_ptr provider; static std::string test_directory; @@ -194,15 +193,20 @@ public: std::cout << "mount command: " << mount_cmd << std::endl; ASSERT_EQ(0, system(mount_cmd.c_str())); 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() { auto unmounted{false}; + + auto unmount_cmd = + "./repertory -dd \"" + config->get_data_directory() + "\" -unmount"; 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) { - std::this_thread::sleep_for(100ms); + std::this_thread::sleep_for(5s); } } @@ -251,8 +255,6 @@ std::filesystem::path fuse_test::current_directory{}; template std::unique_ptr fuse_test::drive{}; -template lock_data fuse_test::lock_data_{}; - template std::string fuse_test::mount_location{}; @@ -262,7 +264,7 @@ std::unique_ptr fuse_test::provider{}; template std::string fuse_test::test_directory; -typedef ::testing::Types fuse_provider_types; +using fuse_provider_types = ::testing::Types; } // namespace repertory #endif // !defined(_WIN32) diff --git a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp index e530ea15..ead09360 100644 --- a/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/winfsp_fixture.hpp @@ -31,133 +31,186 @@ #include "platform/platform.hpp" #include "providers/s3/s3_provider.hpp" #include "providers/sia/sia_provider.hpp" +#include "types/repertory.hpp" +#include "utils/event_capture.hpp" #include "utils/file_utils.hpp" #include "utils/path.hpp" -extern std::size_t PROVIDER_INDEX; +namespace { +std::atomic idx{0U}; +constexpr const auto SLEEP_SECONDS{1.5s}; +} // namespace namespace repertory { -class winfsp_test : public ::testing::Test { +template class winfsp_test : public ::testing::Test { public: - lock_data lock_data_; - std::unique_ptr config; - std::unique_ptr comm; - std::unique_ptr provider; - std::unique_ptr drive; + static std::string cfg_directory; + static std::unique_ptr comm; + static std::unique_ptr config; + static std::filesystem::path current_directory; + static std::unique_ptr drive; + static std::string mount_location; + static std::unique_ptr provider; + static std::string test_directory; protected: - void SetUp() override { - if (PROVIDER_INDEX != 0) { - 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()); + static void SetUpTestCase() { + current_directory = std::filesystem::current_path(); - app_config src_cfg( + test_directory = utils::path::combine( + test::get_test_output_dir(), + { + "winfsp_test", + std::to_string(static_cast(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(provider_t::type, cfg_directory); + + std::vector drive_args{}; + + switch (provider_t::type) { + case provider_type::s3: { + { + app_config src_cfg{ provider_type::s3, - utils::path::combine(test::get_test_input_dir(), {"storj"})); - config = std::make_unique( - provider_type::s3, - 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()); + utils::path::combine(test::get_test_input_dir(), {"storj"}), + }; + config->set_enable_drive_events(true); config->set_event_level(event_level::trace); - config->set_enable_drive_events(true); - event_system::instance().start(); - - comm = std::make_unique(config->get_s3_config()); - provider = std::make_unique(*config, *comm); - drive = std::make_unique(*config, lock_data_, *provider); - return; + config->set_s3_config(src_cfg.get_s3_config()); } - if (PROVIDER_INDEX == 2) { - EXPECT_TRUE(utils::file::directory( - utils::path::combine( - test::get_test_output_dir(), - {"winfsp_test" + std::to_string(PROVIDER_INDEX)})) - .remove_recursively()); + comm = std::make_unique(config->get_s3_config()); + drive_args = std::vector({ + "-s3", + "-na", + "storj", + }); + } break; - app_config src_cfg( + case provider_type::sia: { + { + app_config src_cfg{ provider_type::sia, - utils::path::combine(test::get_test_input_dir(), {"sia"})); - config = std::make_unique( - provider_type::sia, - 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()); + utils::path::combine(test::get_test_input_dir(), {"sia"}), + }; + config->set_enable_drive_events(true); config->set_event_level(event_level::debug); - config->set_enable_drive_events(true); - event_system::instance().start(); - - comm = std::make_unique(config->get_host_config()); - provider = std::make_unique(*config, *comm); - drive = std::make_unique(*config, lock_data_, *provider); - - return; + config->set_host_config(src_cfg.get_host_config()); } + + comm = std::make_unique(config->get_host_config()); + } break; + // case 0U: { + // config = + // std::make_unique(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(config->get_s3_config()); + // provider = std::make_unique(*config, *comm); + // drive_args = std::vector({"-en"}); + // } break; + + default: + throw std::runtime_error("provider type is not implemented"); + return; } + + provider = std::make_unique(*config, *comm); + drive_args.push_back(mount_location); } - void TearDown() override { - if (PROVIDER_INDEX != 0) { - drive.reset(); - provider.reset(); - comm.reset(); - config.reset(); + static void TearDownTestCase() { + execute_unmount(); + std::filesystem::current_path(current_directory); + [[maybe_unused]] auto ret = + utils::file::directory(test_directory).remove_recursively(); + /* if (PROVIDER_INDEX != 0) { + drive.reset(); + provider.reset(); + comm.reset(); + config.reset(); - event_system::instance().stop(); - EXPECT_TRUE(utils::file::directory( - utils::path::combine( - test::get_test_output_dir(), - {"winfsp_test" + std::to_string(PROVIDER_INDEX)})) - .remove_recursively()); + event_system::instance().stop(); + EXPECT_TRUE(utils::file::directory( + utils::path::combine( + test::get_test_output_dir(), + {"winfsp_test" + std::to_string(PROVIDER_INDEX)})) + .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 +std::string winfsp_test::cfg_directory; + +template +std::unique_ptr winfsp_test::config; + +template +std::filesystem::path winfsp_test::current_directory; + +template +std::unique_ptr winfsp_test::comm; + +template +std::unique_ptr winfsp_test::provider; + +template +std::string winfsp_test::test_directory; + +template +std::unique_ptr winfsp_test::drive; + +using winfsp_provider_types = ::testing::Types; } // namespace repertory -#endif +#endif // defined(_WIN32) #endif // REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP diff --git a/repertory/repertory_test/src/winfsp_drive_test.cpp b/repertory/repertory_test/src/winfsp_drive_test.cpp new file mode 100644 index 00000000..b516f969 --- /dev/null +++ b/repertory/repertory_test/src/winfsp_drive_test.cpp @@ -0,0 +1,413 @@ +/* + Copyright <2018-2024> + + 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( \ +// std::string(func) + \ +// "\r\n***********************\r\n***********************") +// +// static auto mount_setup(std::string &mount_point) { +// mount_point = "U:"; +// return std::vector({"unittests", "-f", mount_point}); +// } +// +// static void execute_mount(winfsp_test *test, +// const std::vector &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(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(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(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(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 diff --git a/repertory/repertory_test/src/winfsp_test.cpp b/repertory/repertory_test/src/winfsp_test.cpp deleted file mode 100644 index f14d326c..00000000 --- a/repertory/repertory_test/src/winfsp_test.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - Copyright <2018-2024> - - 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( \ - std::string(func) + \ - "\r\n***********************\r\n***********************") - -static auto mount_setup(std::string &mount_point) { - mount_point = "U:"; - return std::vector({"unittests", "-f", mount_point}); -} - -static void execute_mount(winfsp_test *test, - const std::vector &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(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(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(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(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