move to new build system
This commit is contained in:
1
repertory2/repertory2_test/encrypt/sub10/moose.txt
Normal file
1
repertory2/repertory2_test/encrypt/sub10/moose.txt
Normal file
@@ -0,0 +1 @@
|
||||
test
|
1
repertory2/repertory2_test/encrypt/test.txt
Normal file
1
repertory2/repertory2_test/encrypt/test.txt
Normal file
@@ -0,0 +1 @@
|
||||
moose
|
148
repertory2/repertory2_test/include/fixtures/winfsp_fixture.hpp
Normal file
148
repertory2/repertory2_test/include/fixtures/winfsp_fixture.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef REPERTORY_WINFSP_FIXTURE_H
|
||||
#define REPERTORY_WINFSP_FIXTURE_H
|
||||
#if _WIN32
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "drives/winfsp/winfsp_drive.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/s3/s3_provider.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
|
||||
extern std::size_t PROVIDER_INDEX;
|
||||
|
||||
namespace repertory {
|
||||
class winfsp_test : public ::testing::Test {
|
||||
public:
|
||||
lock_data lock_data_;
|
||||
std::unique_ptr<app_config> config;
|
||||
std::unique_ptr<curl_comm> comm;
|
||||
std::unique_ptr<i_provider> provider;
|
||||
std::unique_ptr<winfsp_drive> drive;
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
if (PROVIDER_INDEX != 0) {
|
||||
if (PROVIDER_INDEX == 1) {
|
||||
#ifdef REPERTORY_ENABLE_S3
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively(
|
||||
"./winfsp_test" + std::to_string(PROVIDER_INDEX)));
|
||||
|
||||
app_config src_cfg(provider_type::s3,
|
||||
utils::path::combine(get_test_dir(), {"storj"}));
|
||||
config = std::make_unique<app_config>(
|
||||
provider_type::s3,
|
||||
"./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::verbose);
|
||||
config->set_enable_drive_events(true);
|
||||
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);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (PROVIDER_INDEX == 2) {
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively(
|
||||
"./winfsp_test" + std::to_string(PROVIDER_INDEX)));
|
||||
|
||||
app_config src_cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
config = std::make_unique<app_config>(
|
||||
provider_type::sia,
|
||||
"./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_enable_drive_events(true);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (PROVIDER_INDEX != 0) {
|
||||
drive.reset();
|
||||
provider.reset();
|
||||
comm.reset();
|
||||
config.reset();
|
||||
|
||||
event_system::instance().stop();
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively(
|
||||
"./winfsp_test" + std::to_string(PROVIDER_INDEX)));
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif
|
||||
#endif // REPERTORY_WINFSP_FIXTURE_H
|
158
repertory2/repertory2_test/include/mocks/mock_fuse_drive.hpp
Normal file
158
repertory2/repertory2_test/include/mocks/mock_fuse_drive.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_MOCKS_MOCK_FUSE_DRIVE_HPP_
|
||||
#define TESTS_MOCKS_MOCK_FUSE_DRIVE_HPP_
|
||||
#ifndef _WIN32
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "drives/fuse/i_fuse_drive.hpp"
|
||||
#include "types/remote.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class mock_fuse_drive final : public virtual i_fuse_drive {
|
||||
public:
|
||||
explicit mock_fuse_drive(std::string mount_location)
|
||||
: mount_location_(std::move(mount_location)) {}
|
||||
|
||||
private:
|
||||
std::string mount_location_;
|
||||
std::unordered_map<std::string, api_meta_map> meta_;
|
||||
|
||||
public:
|
||||
auto check_owner(const std::string &) const -> api_error override {
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto check_parent_access(const std::string &, int) const
|
||||
-> api_error override {
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto get_directory_item_count(const std::string &) const
|
||||
-> std::uint64_t override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto get_directory_items(const std::string &) const
|
||||
-> directory_item_list override {
|
||||
directory_item_list list{};
|
||||
|
||||
directory_item dir_item{};
|
||||
dir_item.api_path = ".";
|
||||
dir_item.directory = true;
|
||||
dir_item.size = 0;
|
||||
dir_item.meta = {
|
||||
{META_ATTRIBUTES, "16"},
|
||||
{META_MODIFIED, std::to_string(utils::get_file_time_now())},
|
||||
{META_WRITTEN, std::to_string(utils::get_file_time_now())},
|
||||
{META_ACCESSED, std::to_string(utils::get_file_time_now())},
|
||||
{META_CREATION, std::to_string(utils::get_file_time_now())}};
|
||||
list.emplace_back(dir_item);
|
||||
|
||||
dir_item.api_path = "..";
|
||||
list.emplace_back(dir_item);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
auto get_file_size(const std::string &) const -> std::uint64_t override {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
auto get_item_meta(const std::string &api_path, api_meta_map &meta) const
|
||||
-> api_error override {
|
||||
meta = const_cast<mock_fuse_drive *>(this)->meta_[api_path];
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto get_item_meta(const std::string &api_path, const std::string &name,
|
||||
std::string &value) const -> api_error override {
|
||||
value = const_cast<mock_fuse_drive *>(this)->meta_[api_path][name];
|
||||
if (value.empty()) {
|
||||
value = "0";
|
||||
}
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto get_total_drive_space() const -> std::uint64_t override {
|
||||
return 100ULL * 1024ULL * 1024ULL;
|
||||
}
|
||||
|
||||
auto get_total_item_count() const -> std::uint64_t override { return 0U; }
|
||||
|
||||
auto get_used_drive_space() const -> std::uint64_t override { return 0U; }
|
||||
|
||||
void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
||||
std::string &volume_label) const override {
|
||||
free_size = 100u;
|
||||
total_size = 200u;
|
||||
volume_label = "TestVolumeLabel";
|
||||
}
|
||||
|
||||
auto rename_directory(const std::string &from_api_path,
|
||||
const std::string &to_api_path) -> int override {
|
||||
const auto from_file_path =
|
||||
utils::path::combine(mount_location_, {from_api_path});
|
||||
const auto to_file_path =
|
||||
utils::path::combine(mount_location_, {to_api_path});
|
||||
return rename(from_file_path.c_str(), to_file_path.c_str());
|
||||
}
|
||||
|
||||
auto rename_file(const std::string &from_api_path,
|
||||
const std::string &to_api_path, bool overwrite)
|
||||
-> int override {
|
||||
const auto from_file_path =
|
||||
utils::path::combine(mount_location_, {from_api_path});
|
||||
const auto to_file_path =
|
||||
utils::path::combine(mount_location_, {to_api_path});
|
||||
|
||||
if (overwrite) {
|
||||
if (not utils::file::retry_delete_file(to_file_path)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (utils::file::is_directory(to_file_path) ||
|
||||
utils::file::is_file(to_file_path)) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rename(from_file_path.c_str(), to_file_path.c_str());
|
||||
}
|
||||
|
||||
auto is_processing(const std::string &) const -> bool override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_item_meta(const std::string &api_path, const std::string &key,
|
||||
const std::string &value) override {
|
||||
meta_[api_path][key] = value;
|
||||
}
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // TESTS_MOCKS_MOCK_FUSE_DRIVE_HPP_
|
98
repertory2/repertory2_test/include/mocks/mock_open_file.hpp
Normal file
98
repertory2/repertory2_test/include/mocks/mock_open_file.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_MOCKS_MOCK_OPEN_FILE_HPP_
|
||||
#define TESTS_MOCKS_MOCK_OPEN_FILE_HPP_
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "file_manager/i_open_file.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class mock_open_file : public virtual i_closeable_open_file {
|
||||
public:
|
||||
MOCK_METHOD(std::string, get_api_path, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::size_t, get_chunk_size, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::uint64_t, get_file_size, (), (const, override));
|
||||
|
||||
MOCK_METHOD(filesystem_item, get_filesystem_item, (), (const, override));
|
||||
|
||||
MOCK_METHOD(open_file_data, get_open_data, (std::uint64_t handle),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(std::size_t, get_open_file_count, (), (const, override));
|
||||
|
||||
MOCK_METHOD(boost::dynamic_bitset<>, get_read_state, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, get_read_state, (std::size_t chunk), (const, override));
|
||||
|
||||
MOCK_METHOD(std::string, get_source_path, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, has_handle, (std::uint64_t handle), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, is_directory, (), (const, override));
|
||||
|
||||
MOCK_METHOD(api_error, native_operation, (native_operation_callback callback),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, native_operation,
|
||||
(std::uint64_t new_file_size, native_operation_callback callback),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, read,
|
||||
(std::size_t read_size, std::uint64_t read_offset,
|
||||
data_buffer &data),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, resize, (std::uint64_t new_file_size), (override));
|
||||
|
||||
MOCK_METHOD(void, set_api_path, (const std::string &api_path), (override));
|
||||
|
||||
MOCK_METHOD(api_error, write,
|
||||
(std::uint64_t write_offset, const data_buffer &data,
|
||||
std::size_t &bytes_written),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void, add, (std::uint64_t handle, open_file_data ofd),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(bool, can_close, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, close, (), (override));
|
||||
|
||||
MOCK_METHOD(std::vector<std::uint64_t>, get_handles, (), (const, override));
|
||||
|
||||
MOCK_METHOD((std::map<std::uint64_t, open_file_data>), get_open_data, (),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(bool, is_complete, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, is_modified, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, is_write_supported, (), (const, override));
|
||||
|
||||
MOCK_METHOD(void, remove, (std::uint64_t handle), (override));
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // TESTS_MOCKS_MOCK_OPEN_FILE_HPP_
|
162
repertory2/repertory2_test/include/mocks/mock_provider.hpp
Normal file
162
repertory2/repertory2_test/include/mocks/mock_provider.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_MOCKS_MOCK_PROVIDER_HPP_
|
||||
#define TESTS_MOCKS_MOCK_PROVIDER_HPP_
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "providers/i_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class mock_provider : public virtual i_provider {
|
||||
public:
|
||||
mock_provider(bool allow_rename = true) : allow_rename_(allow_rename) {}
|
||||
|
||||
private:
|
||||
const bool allow_rename_;
|
||||
|
||||
public:
|
||||
MOCK_METHOD(api_error, create_directory,
|
||||
(const std::string &api_path, api_meta_map &meta), (override));
|
||||
|
||||
MOCK_METHOD(api_error, create_directory_clone_source_meta,
|
||||
(const std::string &source_api_path, const std::string &api_path),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, create_file,
|
||||
(const std::string &api_path, api_meta_map &meta), (override));
|
||||
|
||||
MOCK_METHOD(api_error, get_api_path_from_source,
|
||||
(const std::string &source_path, std::string &api_path),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(std::uint64_t, get_directory_item_count,
|
||||
(const std::string &api_path), (const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_directory_items,
|
||||
(const std::string &api_path, directory_item_list &list),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_file,
|
||||
(const std::string &api_path, api_file &file), (const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_file_list, (api_file_list & list),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_file_size,
|
||||
(const std::string &api_path, std::uint64_t &file_size),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_filesystem_item,
|
||||
(const std::string &api_path, bool directory,
|
||||
filesystem_item &fsi),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_filesystem_item_and_file,
|
||||
(const std::string &api_path, api_file &file,
|
||||
filesystem_item &fsi),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_filesystem_item_from_source_path,
|
||||
(const std::string &source_path, filesystem_item &fsi),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_item_meta,
|
||||
(const std::string &api_path, api_meta_map &meta),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(api_error, get_item_meta,
|
||||
(const std::string &api_path, const std::string &key,
|
||||
std::string &value),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD((std::vector<std::string>), get_pinned_files, (),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(provider_type, get_provider_type, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::uint64_t, get_total_drive_space, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::uint64_t, get_total_item_count, (), (const, override));
|
||||
|
||||
MOCK_METHOD(std::uint64_t, get_used_drive_space, (), (const, override));
|
||||
|
||||
MOCK_METHOD(bool, is_direct_only, (), (const, override));
|
||||
|
||||
MOCK_METHOD(api_error, is_directory,
|
||||
(const std::string &api_path, bool &exists), (const, override));
|
||||
|
||||
MOCK_METHOD(api_error, is_file, (const std::string &api_path, bool &exists),
|
||||
(const, override));
|
||||
|
||||
bool is_file_writeable(const std::string & /* api_path */) const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOCK_METHOD(bool, is_online, (), (const, override));
|
||||
|
||||
bool is_rename_supported() const override { return allow_rename_; }
|
||||
|
||||
MOCK_METHOD(api_error, read_file_bytes,
|
||||
(const std::string &path, std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data, stop_type &stop_requested),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, remove_directory, (const std::string &api_path),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, remove_file, (const std::string &api_path),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, remove_item_meta,
|
||||
(const std::string &api_path, const std::string &key),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, rename_file,
|
||||
(const std::string &from_api_path,
|
||||
const std::string &to_api_path),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, set_item_meta,
|
||||
(const std::string &api_path, const std::string &key,
|
||||
const std::string &value),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(api_error, set_item_meta,
|
||||
(const std::string &api_path, const api_meta_map &meta),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(bool, start,
|
||||
(api_item_added_callback api_item_added, i_file_manager *fm),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void, stop, (), (override));
|
||||
|
||||
MOCK_METHOD(api_error, upload_file,
|
||||
(const std::string &api_path, const std::string &source_path,
|
||||
stop_type &stop_requested),
|
||||
(override));
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // TESTS_MOCKS_MOCK_PROVIDER_HPP_
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_MOCKS_MOCK_UPLOAD_MANAGER_HPP_
|
||||
#define TESTS_MOCKS_MOCK_UPLOAD_MANAGER_HPP_
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "file_manager/i_upload_manager.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class mock_upload_manager : public i_upload_manager {
|
||||
public:
|
||||
MOCK_METHOD(void, queue_upload, (const i_open_file &o), (override));
|
||||
|
||||
MOCK_METHOD(void, remove_resume,
|
||||
(const std::string &api_path, const std::string &source_path),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void, remove_upload, (const std::string &api_path), (override));
|
||||
|
||||
MOCK_METHOD(void, store_resume, (const i_open_file &o), (override));
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // TESTS_MOCKS_MOCK_UPLOAD_MANAGER_HPP_
|
168
repertory2/repertory2_test/include/mocks/mock_winfsp_drive.hpp
Normal file
168
repertory2/repertory2_test/include/mocks/mock_winfsp_drive.hpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_MOCKS_MOCK_WINFSP_DRIVE_HPP_
|
||||
#define TESTS_MOCKS_MOCK_WINFSP_DRIVE_HPP_
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "drives/winfsp/i_winfsp_drive.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class mock_winfsp_drive final : public virtual i_winfsp_drive {
|
||||
public:
|
||||
explicit mock_winfsp_drive(std::string mount_location)
|
||||
: mount_location_(std::move(mount_location)) {}
|
||||
|
||||
private:
|
||||
const std::string mount_location_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto
|
||||
get_directory_item_count(const std::string & /*api_path*/) const
|
||||
-> std::uint64_t override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_directory_items(const std::string & /*api_path*/) const
|
||||
-> directory_item_list override {
|
||||
directory_item_list list{};
|
||||
|
||||
directory_item di{};
|
||||
di.api_path = ".";
|
||||
di.directory = true;
|
||||
di.size = 0u;
|
||||
di.meta = {{META_ATTRIBUTES, "16"},
|
||||
{META_MODIFIED, std::to_string(utils::get_file_time_now())},
|
||||
{META_WRITTEN, std::to_string(utils::get_file_time_now())},
|
||||
{META_ACCESSED, std::to_string(utils::get_file_time_now())},
|
||||
{META_CREATION, std::to_string(utils::get_file_time_now())}};
|
||||
list.emplace_back(di);
|
||||
|
||||
di.api_path = "..";
|
||||
list.emplace_back(di);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_file_size(const std::string & /*api_path*/) const
|
||||
-> std::uint64_t override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto get_item_meta(const std::string & /*api_path*/, api_meta_map &meta) const
|
||||
-> api_error override {
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto get_item_meta(const std::string & /*api_path*/,
|
||||
const std::string & /*name*/,
|
||||
std::string & /*value*/) const -> api_error override {
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto get_security_by_name(PWSTR /*file_name*/, PUINT32 attributes,
|
||||
PSECURITY_DESCRIPTOR descriptor,
|
||||
std::uint64_t *descriptor_size)
|
||||
-> NTSTATUS override {
|
||||
auto ret = STATUS_SUCCESS;
|
||||
|
||||
if (attributes) {
|
||||
*attributes = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
if (descriptor_size) {
|
||||
ULONG sz = 0;
|
||||
PSECURITY_DESCRIPTOR sd = nullptr;
|
||||
if (::ConvertStringSecurityDescriptorToSecurityDescriptor(
|
||||
"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)",
|
||||
SDDL_REVISION_1, &sd, &sz)) {
|
||||
if (sz > *descriptor_size) {
|
||||
ret = STATUS_BUFFER_TOO_SMALL;
|
||||
} else {
|
||||
::CopyMemory(descriptor, sd, sz);
|
||||
}
|
||||
*descriptor_size = sz;
|
||||
::LocalFree(sd);
|
||||
} else {
|
||||
ret = FspNtStatusFromWin32(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override {
|
||||
return 100 * 1024 * 1024;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_total_item_count() const -> std::uint64_t override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_used_drive_space() const -> std::uint64_t override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
||||
std::string &volume_label) const override {
|
||||
free_size = 100;
|
||||
total_size = 200;
|
||||
volume_label = "TestVolumeLabel";
|
||||
}
|
||||
|
||||
auto populate_file_info(const std::string &api_path,
|
||||
remote::file_info &file_info) -> api_error override {
|
||||
const auto file_path = utils::path::combine(mount_location_, {api_path});
|
||||
const auto directory = utils::file::is_directory(file_path);
|
||||
const auto attributes =
|
||||
FILE_FLAG_BACKUP_SEMANTICS |
|
||||
(directory ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL);
|
||||
const auto share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
auto handle = ::CreateFileA(&file_path[0], GENERIC_READ, share_mode,
|
||||
nullptr, OPEN_EXISTING, attributes, nullptr);
|
||||
FILE_BASIC_INFO fi{};
|
||||
::GetFileInformationByHandleEx(handle, FileBasicInfo, &fi, sizeof(fi));
|
||||
if (not directory) {
|
||||
utils::file::get_file_size(file_path, file_info.FileSize);
|
||||
}
|
||||
file_info.AllocationSize =
|
||||
directory ? 0
|
||||
: utils::divide_with_ceiling(file_info.FileSize,
|
||||
WINFSP_ALLOCATION_UNIT) *
|
||||
WINFSP_ALLOCATION_UNIT;
|
||||
file_info.FileAttributes = fi.FileAttributes;
|
||||
file_info.ChangeTime = fi.ChangeTime.QuadPart;
|
||||
file_info.CreationTime = fi.CreationTime.QuadPart;
|
||||
file_info.LastAccessTime = fi.LastAccessTime.QuadPart;
|
||||
file_info.LastWriteTime = fi.LastWriteTime.QuadPart;
|
||||
::CloseHandle(handle);
|
||||
return api_error::success;
|
||||
}
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // TESTS_MOCKS_MOCK_WINFSP_DRIVE_HPP_
|
66
repertory2/repertory2_test/include/test_common.hpp
Normal file
66
repertory2/repertory2_test/include/test_common.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_TEST_COMMON_HPP_
|
||||
#define TESTS_TEST_COMMON_HPP_
|
||||
|
||||
#ifdef U
|
||||
#undef U
|
||||
#endif
|
||||
|
||||
REPERTORY_IGNORE_WARNINGS_ENABLE()
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
REPERTORY_IGNORE_WARNINGS_DISABLE()
|
||||
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/events.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/native_file.hpp"
|
||||
|
||||
#define COMMA ,
|
||||
|
||||
using ::testing::_;
|
||||
using namespace ::testing;
|
||||
|
||||
namespace repertory {
|
||||
[[nodiscard]] auto create_random_file(std::string path, std::size_t size)
|
||||
-> native_file_ptr;
|
||||
|
||||
void delete_generated_files();
|
||||
|
||||
[[nodiscard]] auto
|
||||
generate_test_file_name(const std::string &directory,
|
||||
const std::string &file_name_no_extension)
|
||||
-> std::string;
|
||||
|
||||
template <typename T, typename T2>
|
||||
static void decrypt_and_verify(const T &buffer, const std::string &token,
|
||||
T2 &result) {
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(token, buffer, result));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_test_dir() -> std::string;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // TESTS_TEST_COMMON_HPP_
|
108
repertory2/repertory2_test/include/utils/event_capture.hpp
Normal file
108
repertory2/repertory2_test/include/utils/event_capture.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef TESTS_UTILS_EVENT_CAPTURE_HPP_
|
||||
#define TESTS_UTILS_EVENT_CAPTURE_HPP_
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class event_capture final {
|
||||
E_CONSUMER();
|
||||
|
||||
public:
|
||||
explicit event_capture(std::vector<std::string> event_names,
|
||||
std::vector<std::string> non_fired_event_names = {})
|
||||
: event_names_(std::move(event_names)),
|
||||
non_fired_event_names_(std::move(non_fired_event_names)) {
|
||||
E_SUBSCRIBE_ALL(process_event);
|
||||
}
|
||||
|
||||
~event_capture() {
|
||||
wait_for_empty();
|
||||
|
||||
E_CONSUMER_RELEASE();
|
||||
|
||||
EXPECT_TRUE(event_names_.empty());
|
||||
for (const auto &event_name : event_names_) {
|
||||
std::cerr << '\t' << event_name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> event_names_;
|
||||
std::vector<std::string> fired_event_names_;
|
||||
std::vector<std::string> non_fired_event_names_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable notify_;
|
||||
|
||||
public:
|
||||
void process_event(const event &event) {
|
||||
unique_mutex_lock l(mutex_);
|
||||
utils::remove_element_from(event_names_, event.get_name());
|
||||
fired_event_names_.emplace_back(event.get_name());
|
||||
notify_.notify_all();
|
||||
l.unlock();
|
||||
|
||||
for (size_t i = 0; i < non_fired_event_names_.size(); i++) {
|
||||
const auto it = std::find(non_fired_event_names_.begin(),
|
||||
non_fired_event_names_.end(), event.get_name());
|
||||
EXPECT_EQ(non_fired_event_names_.end(), it);
|
||||
if (it != non_fired_event_names_.end()) {
|
||||
std::cerr << '\t' << *it << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait_for_empty() {
|
||||
const auto start_time = std::chrono::system_clock::now();
|
||||
unique_mutex_lock l(mutex_);
|
||||
while (not event_names_.empty() &&
|
||||
(std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now() - start_time)
|
||||
.count() < 10)) {
|
||||
notify_.wait_for(l, 1s);
|
||||
}
|
||||
l.unlock();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto wait_for_event(const std::string &event_name) -> bool {
|
||||
auto missing = true;
|
||||
const auto start_time = std::chrono::system_clock::now();
|
||||
|
||||
unique_mutex_lock l(mutex_);
|
||||
while ((std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now() - start_time)
|
||||
.count() < 10) &&
|
||||
(missing =
|
||||
(std::find(fired_event_names_.begin(), fired_event_names_.end(),
|
||||
event_name) == fired_event_names_.end()))) {
|
||||
notify_.wait_for(l, 1s);
|
||||
}
|
||||
l.unlock();
|
||||
return not missing;
|
||||
}
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // TESTS_UTILS_EVENT_CAPTURE_HPP_
|
62
repertory2/repertory2_test/main.cpp
Normal file
62
repertory2/repertory2_test/main.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "initialize.hpp"
|
||||
#include "test_common.hpp"
|
||||
#ifdef _WIN32
|
||||
#include "utils/cli_utils.hpp"
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace repertory;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::size_t PROVIDER_INDEX{0U};
|
||||
#endif // _WIN32
|
||||
|
||||
auto main(int argc, char **argv) -> int {
|
||||
if (not repertory::project_initialize()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::vector<const char *> args;
|
||||
{
|
||||
auto args_span = std::span(argv, static_cast<std::size_t>(argc));
|
||||
std::copy(args_span.begin(), args_span.end(), std::back_inserter(args));
|
||||
}
|
||||
|
||||
if (utils::cli::has_option(args, "--provider_index")) {
|
||||
PROVIDER_INDEX = static_cast<std::size_t>(
|
||||
utils::string::to_uint64(
|
||||
utils::cli::parse_option(args, "--provider_index", 1U)[0U]) +
|
||||
1U);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
auto ret = RUN_ALL_TESTS();
|
||||
|
||||
delete_generated_files();
|
||||
|
||||
repertory::project_cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
807
repertory2/repertory2_test/src/config_test.cpp
Normal file
807
repertory2/repertory2_test/src/config_test.cpp
Normal file
@@ -0,0 +1,807 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
class config_test : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(utils::file::delete_directory_recursively(
|
||||
utils::path::absolute("./data")));
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively(
|
||||
utils::path::absolute("./data")));
|
||||
}
|
||||
};
|
||||
|
||||
const auto DEFAULT_SIA_CONFIG = "{\n"
|
||||
" \"ApiAuth\": \"\",\n"
|
||||
" \"ApiPort\": 10000,\n"
|
||||
" \"ApiUser\": \"repertory\",\n"
|
||||
" \"ChunkDownloaderTimeoutSeconds\": 30,\n"
|
||||
" \"EnableChunkDownloaderTimeout\": true,\n"
|
||||
" \"EnableCommDurationEvents\": false,\n"
|
||||
" \"EnableDriveEvents\": false,\n"
|
||||
" \"EnableMaxCacheSize\": false,\n"
|
||||
#ifdef _WIN32
|
||||
" \"EnableMountManager\": false,\n"
|
||||
#endif
|
||||
" \"EventLevel\": \"normal\",\n"
|
||||
" \"EvictionDelayMinutes\": 10,\n"
|
||||
" \"EvictionUsesAccessedTime\": false,\n"
|
||||
" \"HighFreqIntervalSeconds\": 30,\n"
|
||||
" \"HostConfig\": {\n"
|
||||
" \"AgentString\": \"Sia-Agent\",\n"
|
||||
" \"ApiPassword\": \"\",\n"
|
||||
" \"ApiPort\": 9980,\n"
|
||||
" \"HostNameOrIp\": \"localhost\",\n"
|
||||
" \"TimeoutMs\": 60000\n"
|
||||
" },\n"
|
||||
" \"LowFreqIntervalSeconds\": 3600,\n"
|
||||
" \"MaxCacheSizeBytes\": 21474836480,\n"
|
||||
" \"MaxUploadCount\": 5,\n"
|
||||
" \"OnlineCheckRetrySeconds\": 60,\n"
|
||||
" \"OrphanedFileRetentionDays\": 15,\n"
|
||||
" \"PreferredDownloadType\": \"fallback\",\n"
|
||||
" \"ReadAheadCount\": 4,\n"
|
||||
" \"RemoteMount\": {\n"
|
||||
" \"EnableRemoteMount\": false,\n"
|
||||
" \"IsRemoteMount\": false,\n"
|
||||
" \"RemoteClientPoolSize\": 10,\n"
|
||||
" \"RemoteHostNameOrIp\": \"\",\n"
|
||||
" \"RemoteMaxConnections\": 20,\n"
|
||||
" \"RemotePort\": 20000,\n"
|
||||
" \"RemoteReceiveTimeoutSeconds\": 120,\n"
|
||||
" \"RemoteSendTimeoutSeconds\": 30,\n"
|
||||
" \"RemoteToken\": \"\"\n"
|
||||
" },\n"
|
||||
" \"RetryReadCount\": 6,\n"
|
||||
" \"RingBufferFileSize\": 512,\n"
|
||||
" \"Version\": " +
|
||||
std::to_string(REPERTORY_CONFIG_VERSION) +
|
||||
"\n"
|
||||
"}";
|
||||
|
||||
const auto DEFAULT_S3_CONFIG = "{\n"
|
||||
" \"ApiAuth\": \"\",\n"
|
||||
" \"ApiPort\": 10100,\n"
|
||||
" \"ApiUser\": \"repertory\",\n"
|
||||
" \"ChunkDownloaderTimeoutSeconds\": 30,\n"
|
||||
" \"EnableChunkDownloaderTimeout\": true,\n"
|
||||
" \"EnableCommDurationEvents\": false,\n"
|
||||
" \"EnableDriveEvents\": false,\n"
|
||||
" \"EnableMaxCacheSize\": false,\n"
|
||||
#ifdef _WIN32
|
||||
" \"EnableMountManager\": false,\n"
|
||||
#endif
|
||||
" \"EventLevel\": \"normal\",\n"
|
||||
" \"EvictionDelayMinutes\": 10,\n"
|
||||
" \"EvictionUsesAccessedTime\": false,\n"
|
||||
" \"HighFreqIntervalSeconds\": 30,\n"
|
||||
" \"LowFreqIntervalSeconds\": 3600,\n"
|
||||
" \"MaxCacheSizeBytes\": 21474836480,\n"
|
||||
" \"MaxUploadCount\": 5,\n"
|
||||
" \"OnlineCheckRetrySeconds\": 60,\n"
|
||||
" \"OrphanedFileRetentionDays\": 15,\n"
|
||||
" \"PreferredDownloadType\": \"fallback\",\n"
|
||||
" \"ReadAheadCount\": 4,\n"
|
||||
" \"RemoteMount\": {\n"
|
||||
" \"EnableRemoteMount\": false,\n"
|
||||
" \"IsRemoteMount\": false,\n"
|
||||
" \"RemoteClientPoolSize\": 10,\n"
|
||||
" \"RemoteHostNameOrIp\": \"\",\n"
|
||||
" \"RemoteMaxConnections\": 20,\n"
|
||||
" \"RemotePort\": 20100,\n"
|
||||
" \"RemoteReceiveTimeoutSeconds\": 120,\n"
|
||||
" \"RemoteSendTimeoutSeconds\": 30,\n"
|
||||
" \"RemoteToken\": \"\"\n"
|
||||
" },\n"
|
||||
" \"RetryReadCount\": 6,\n"
|
||||
" \"RingBufferFileSize\": 512,\n"
|
||||
" \"S3Config\": {\n"
|
||||
" \"AccessKey\": \"\",\n"
|
||||
" \"Bucket\": \"\",\n"
|
||||
" \"CacheTimeoutSeconds\": 60,\n"
|
||||
" \"EncryptionToken\": \"\",\n"
|
||||
" \"Region\": \"any\",\n"
|
||||
" \"SecretKey\": \"\",\n"
|
||||
" \"TimeoutMs\": 60000,\n"
|
||||
" \"URL\": \"\",\n"
|
||||
" \"UsePathStyle\": false,\n"
|
||||
" \"UseRegionInURL\": false\n"
|
||||
" },\n"
|
||||
" \"Version\": " +
|
||||
std::to_string(REPERTORY_CONFIG_VERSION) +
|
||||
"\n"
|
||||
"}";
|
||||
|
||||
TEST_F(config_test, sia_default_settings) {
|
||||
const auto config_file = utils::path::absolute(
|
||||
utils::path::combine("./data/sia", {"config.json"}));
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
app_config config(provider_type::sia, "./data/sia");
|
||||
config.set_remote_token("");
|
||||
config.set_api_auth("");
|
||||
EXPECT_TRUE(config.set_value_by_name("HostConfig.ApiPassword", "").empty());
|
||||
json data;
|
||||
EXPECT_TRUE(utils::file::read_json_file(config_file, data));
|
||||
EXPECT_STREQ(DEFAULT_SIA_CONFIG.c_str(), data.dump(2).c_str());
|
||||
EXPECT_TRUE(utils::file::is_directory("./data/sia/cache"));
|
||||
EXPECT_TRUE(utils::file::is_directory("./data/sia/logs"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, s3_default_settings) {
|
||||
const auto config_file =
|
||||
utils::path::absolute(utils::path::combine("./data/s3", {"config.json"}));
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
app_config config(provider_type::s3, "./data/s3");
|
||||
config.set_remote_token("");
|
||||
config.set_api_auth("");
|
||||
json data;
|
||||
EXPECT_TRUE(utils::file::read_json_file(config_file, data));
|
||||
EXPECT_STREQ(DEFAULT_S3_CONFIG.c_str(), data.dump(2).c_str());
|
||||
EXPECT_TRUE(utils::file::is_directory("./data/s3/cache"));
|
||||
EXPECT_TRUE(utils::file::is_directory("./data/s3/logs"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, api_path) {
|
||||
std::string original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_api_auth();
|
||||
EXPECT_EQ(48U, original_value.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, api_auth) {
|
||||
std::string original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_api_auth();
|
||||
config.set_api_auth(original_value.substr(0, 20));
|
||||
EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, api_port) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_api_port();
|
||||
config.set_api_port(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_api_port());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_api_port());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, api_user) {
|
||||
std::string original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_api_user();
|
||||
config.set_api_user(original_value.substr(0, 2));
|
||||
EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, chunk_downloader_timeout_secs) {
|
||||
std::uint8_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_chunk_downloader_timeout_secs();
|
||||
config.set_chunk_downloader_timeout_secs(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_chunk_downloader_timeout_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_chunk_downloader_timeout_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_chunk_download_timeout) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_chunk_download_timeout();
|
||||
config.set_enable_chunk_downloader_timeout(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_chunk_download_timeout());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_chunk_download_timeout());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_comm_duration_events) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_comm_duration_events();
|
||||
config.set_enable_comm_duration_events(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_comm_duration_events());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_comm_duration_events());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_drive_events) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_drive_events();
|
||||
config.set_enable_drive_events(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_drive_events());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_drive_events());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_max_cache_size) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_max_cache_size();
|
||||
config.set_enable_max_cache_size(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_max_cache_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_max_cache_size());
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
TEST_F(config_test, enable_mount_manager) {
|
||||
bool original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_mount_manager();
|
||||
config.set_enable_mount_manager(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_mount_manager());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_mount_manager());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TEST_F(config_test, event_level) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_event_level(event_level::debug);
|
||||
EXPECT_EQ(event_level::debug, config.get_event_level());
|
||||
config.set_event_level(event_level::warn);
|
||||
EXPECT_EQ(event_level::warn, config.get_event_level());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(event_level::warn, config.get_event_level());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, eviction_delay_mins) {
|
||||
std::uint32_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_eviction_delay_mins();
|
||||
config.set_eviction_delay_mins(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, eviction_uses_accessed_time) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_eviction_uses_accessed_time();
|
||||
config.set_eviction_uses_accessed_time(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
|
||||
}
|
||||
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, high_frequency_interval_secs) {
|
||||
std::uint8_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_high_frequency_interval_secs();
|
||||
config.set_high_frequency_interval_secs(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_high_frequency_interval_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_high_frequency_interval_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, low_frequency_interval_secs) {
|
||||
std::uint32_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_low_frequency_interval_secs();
|
||||
config.set_low_frequency_interval_secs(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_low_frequency_interval_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_low_frequency_interval_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, max_cache_size_bytes) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_max_cache_size_bytes(100 * 1024 * 1024);
|
||||
EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, max_upload_count) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_max_upload_count(8U);
|
||||
EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_max_upload_count(0U);
|
||||
EXPECT_EQ(std::uint8_t(1U), config.get_max_upload_count());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, online_check_retry_secs) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_online_check_retry_secs();
|
||||
config.set_online_check_retry_secs(original_value + 1);
|
||||
EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, online_check_retry_secs_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_online_check_retry_secs(14);
|
||||
EXPECT_EQ(15, config.get_online_check_retry_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, orphaned_file_retention_days) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_orphaned_file_retention_days();
|
||||
config.set_orphaned_file_retention_days(original_value + 1);
|
||||
EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, orphaned_file_retention_days_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_orphaned_file_retention_days(0);
|
||||
EXPECT_EQ(1, config.get_orphaned_file_retention_days());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, orphaned_file_retention_days_maximum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_orphaned_file_retention_days(32);
|
||||
EXPECT_EQ(31, config.get_orphaned_file_retention_days());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, read_ahead_count) {
|
||||
std::uint8_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_read_ahead_count();
|
||||
config.set_read_ahead_count(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_read_ahead_count());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_read_ahead_count());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_cache_directory) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data/sia");
|
||||
EXPECT_STREQ(utils::path::absolute("./data/sia/cache").c_str(),
|
||||
config.get_cache_directory().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_config_file_path) {
|
||||
{
|
||||
const auto config_file = utils::path::absolute(
|
||||
utils::path::combine("./data/sia", {"config.json"}));
|
||||
|
||||
app_config config(provider_type::sia, "./data/sia");
|
||||
EXPECT_STREQ(config_file.c_str(), config.get_config_file_path().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_data_directory) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data/sia");
|
||||
EXPECT_STREQ(utils::path::absolute("./data/sia").c_str(),
|
||||
config.get_data_directory().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_log_directory) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data/sia");
|
||||
EXPECT_STREQ(utils::path::absolute("./data/sia/logs").c_str(),
|
||||
config.get_log_directory().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, ring_buffer_file_size) {
|
||||
std::uint16_t original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_ring_buffer_file_size();
|
||||
config.set_ring_buffer_file_size(original_value + 5u);
|
||||
EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, ring_buffer_file_size_minimum_size) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_ring_buffer_file_size(63u);
|
||||
EXPECT_EQ(64u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(64u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, ring_buffer_file_size_maximum_size) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_ring_buffer_file_size(1025u);
|
||||
EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, preferred_download_type) {
|
||||
download_type original_value;
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_preferred_download_type();
|
||||
config.set_preferred_download_type(download_type::ring_buffer);
|
||||
EXPECT_NE(original_value, config.get_preferred_download_type());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_NE(original_value, config.get_preferred_download_type());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, default_agent_name) {
|
||||
EXPECT_STREQ("Sia-Agent",
|
||||
app_config::default_agent_name(provider_type::sia).c_str());
|
||||
}
|
||||
|
||||
TEST_F(config_test, default_api_port) {
|
||||
EXPECT_EQ(9980U, app_config::default_api_port(provider_type::sia));
|
||||
}
|
||||
|
||||
TEST_F(config_test, default_data_directory) {
|
||||
const std::array<std::string, 1U> data_directory = {
|
||||
app_config::default_data_directory(provider_type::sia),
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto local_app_data = utils::get_environment_variable("localappdata");
|
||||
#endif
|
||||
#if __linux__
|
||||
const auto local_app_data =
|
||||
utils::path::combine(utils::get_environment_variable("HOME"), {".local"});
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
const auto local_app_data = utils::path::combine(
|
||||
utils::get_environment_variable("HOME"), {"Library/Application Support"});
|
||||
#endif
|
||||
auto expected_directory =
|
||||
utils::path::combine(local_app_data, {"/repertory2/sia"});
|
||||
EXPECT_STREQ(expected_directory.c_str(), data_directory[0].c_str());
|
||||
}
|
||||
|
||||
TEST_F(config_test, default_rpc_port) {
|
||||
EXPECT_EQ(10000U, app_config::default_rpc_port(provider_type::sia));
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_provider_display_name) {
|
||||
EXPECT_STREQ(
|
||||
"Sia", app_config::get_provider_display_name(provider_type::sia).c_str());
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_provider_name) {
|
||||
EXPECT_STREQ("sia",
|
||||
app_config::get_provider_name(provider_type::sia).c_str());
|
||||
}
|
||||
|
||||
TEST_F(config_test, get_version) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(REPERTORY_CONFIG_VERSION, config.get_version());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_remote_mount) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_enable_remote_mount();
|
||||
config.set_enable_remote_mount(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, is_remote_mount) {
|
||||
bool original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_is_remote_mount();
|
||||
config.set_is_remote_mount(not original_value);
|
||||
EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, enable_remote_mount_fails_if_remote_mount_is_true) {
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_is_remote_mount(true);
|
||||
config.set_enable_remote_mount(true);
|
||||
EXPECT_FALSE(config.get_enable_remote_mount());
|
||||
EXPECT_TRUE(config.get_is_remote_mount());
|
||||
}
|
||||
|
||||
TEST_F(config_test, set_is_remote_mount_fails_if_enable_remote_mount_is_true) {
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_enable_remote_mount(true);
|
||||
config.set_is_remote_mount(true);
|
||||
EXPECT_FALSE(config.get_is_remote_mount());
|
||||
EXPECT_TRUE(config.get_enable_remote_mount());
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_host_name_or_ip) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_remote_host_name_or_ip("my.host.name");
|
||||
EXPECT_STREQ("my.host.name", config.get_remote_host_name_or_ip().c_str());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_STREQ("my.host.name", config.get_remote_host_name_or_ip().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_port) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_remote_port();
|
||||
config.set_remote_port(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_port());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_port());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_receive_timeout_secs) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_remote_receive_timeout_secs();
|
||||
config.set_remote_receive_timeout_secs(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_send_timeout_secs) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_remote_send_timeout_secs();
|
||||
config.set_remote_send_timeout_secs(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_token) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_remote_token("myToken");
|
||||
EXPECT_STREQ("myToken", config.get_remote_token().c_str());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_STREQ("myToken", config.get_remote_token().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_client_pool_size) {
|
||||
std::uint8_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_remote_client_pool_size();
|
||||
config.set_remote_client_pool_size(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_client_pool_size_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_remote_client_pool_size(0);
|
||||
EXPECT_EQ(5, config.get_remote_client_pool_size());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(5, config.get_remote_client_pool_size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_max_connections) {
|
||||
std::uint8_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_remote_max_connections();
|
||||
config.set_remote_max_connections(original_value + 5);
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, remote_max_connections_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_remote_max_connections(0);
|
||||
EXPECT_EQ(1, config.get_remote_max_connections());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(1, config.get_remote_max_connections());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, retry_read_count) {
|
||||
std::uint16_t original_value{};
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
original_value = config.get_retry_read_count();
|
||||
config.set_retry_read_count(original_value + 1);
|
||||
EXPECT_EQ(original_value + 1, config.get_retry_read_count());
|
||||
}
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
EXPECT_EQ(original_value + 1, config.get_retry_read_count());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, retry_read_count_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::sia, "./data");
|
||||
config.set_retry_read_count(1);
|
||||
EXPECT_EQ(2, config.get_retry_read_count());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(config_test, cache_timeout_seconds_minimum_value) {
|
||||
{
|
||||
app_config config(provider_type::s3, "./data");
|
||||
EXPECT_FALSE(
|
||||
config.set_value_by_name("S3Config.CacheTimeoutSeconds", "1").empty());
|
||||
EXPECT_EQ(std::uint16_t(5U), config.get_s3_config().cache_timeout_secs);
|
||||
}
|
||||
}
|
||||
} // namespace repertory
|
77
repertory2/repertory2_test/src/curl_comm_test.cpp
Normal file
77
repertory2/repertory2_test/src/curl_comm_test.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(curl_comm, can_create_s3_host_config) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, false);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("repertory.s3.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_TRUE(hc.path.empty());
|
||||
}
|
||||
|
||||
TEST(curl_comm, can_create_s3_host_config_with_path_style) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, true);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("s3.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_STREQ("/repertory", hc.path.c_str());
|
||||
}
|
||||
|
||||
TEST(curl_comm, can_create_s3_host_config_with_region) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, false);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("repertory.s3.any.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_TRUE(hc.path.empty());
|
||||
}
|
||||
|
||||
TEST(curl_comm, can_create_s3_host_config_with_region_and_path_style) {
|
||||
s3_config config{};
|
||||
config.bucket = "repertory";
|
||||
config.url = "https://s3.test.com";
|
||||
config.region = "any";
|
||||
config.use_region_in_url = true;
|
||||
|
||||
auto hc = curl_comm::create_host_config(config, true);
|
||||
EXPECT_STREQ("https", hc.protocol.c_str());
|
||||
EXPECT_STREQ("s3.any.test.com", hc.host_name_or_ip.c_str());
|
||||
EXPECT_STREQ("/repertory", hc.path.c_str());
|
||||
}
|
||||
} // namespace repertory
|
124
repertory2/repertory2_test/src/database_test.cpp
Normal file
124
repertory2/repertory2_test/src/database_test.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "database/db_common.hpp"
|
||||
#include "database/db_insert.hpp"
|
||||
#include "database/db_select.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(database, db_insert) {
|
||||
console_consumer consumer1;
|
||||
event_system::instance().start();
|
||||
{
|
||||
db::db3_t db3;
|
||||
{
|
||||
sqlite3 *db3_ptr{nullptr};
|
||||
auto res = sqlite3_open_v2(
|
||||
utils::path::absolute(
|
||||
utils::path::combine(get_test_dir(), {"test.db3"}))
|
||||
.c_str(),
|
||||
&db3_ptr, SQLITE_OPEN_READWRITE, nullptr);
|
||||
ASSERT_EQ(SQLITE_OK, res);
|
||||
ASSERT_TRUE(db3_ptr != nullptr);
|
||||
|
||||
db3.reset(db3_ptr);
|
||||
}
|
||||
|
||||
auto query = db::db_insert{*db3.get(), "table"}
|
||||
.column_value("column1", "test9")
|
||||
.column_value("column2", "test9");
|
||||
auto query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(INSERT INTO "table" ("column1", "column2") VALUES (?1, ?2);)",
|
||||
query_str.c_str());
|
||||
|
||||
query = db::db_insert{*db3.get(), "table"}
|
||||
.or_replace()
|
||||
.column_value("column1", "test1")
|
||||
.column_value("column2", "test2");
|
||||
query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(INSERT OR REPLACE INTO "table" ("column1", "column2") VALUES (?1, ?2);)",
|
||||
query_str.c_str());
|
||||
|
||||
auto res = query.go();
|
||||
EXPECT_TRUE(res.ok());
|
||||
EXPECT_FALSE(res.has_row());
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(database, db_select) {
|
||||
console_consumer consumer1;
|
||||
event_system::instance().start();
|
||||
{
|
||||
db::db3_t db3;
|
||||
{
|
||||
sqlite3 *db3_ptr{nullptr};
|
||||
auto res = sqlite3_open_v2(
|
||||
utils::path::combine(get_test_dir(), {"test.db3"}).c_str(), &db3_ptr,
|
||||
SQLITE_OPEN_READWRITE, nullptr);
|
||||
ASSERT_EQ(SQLITE_OK, res);
|
||||
ASSERT_TRUE(db3_ptr != nullptr);
|
||||
|
||||
db3.reset(db3_ptr);
|
||||
}
|
||||
|
||||
auto query = db::db_select{*db3.get(), "table"}
|
||||
.where("column1")
|
||||
.equals("test1")
|
||||
.and_where("column2")
|
||||
.equals("test2");
|
||||
auto query_str = query.dump();
|
||||
std::cout << query_str << std::endl;
|
||||
EXPECT_STREQ(
|
||||
R"(SELECT * FROM "table" WHERE ("column1"=?1 AND "column2"=?2);)",
|
||||
query_str.c_str());
|
||||
auto res = query.go();
|
||||
|
||||
EXPECT_TRUE(res.ok());
|
||||
EXPECT_TRUE(res.has_row());
|
||||
std::size_t row_count{};
|
||||
while (res.has_row()) {
|
||||
std::optional<db::db_select::row> row;
|
||||
EXPECT_TRUE(res.get_row(row));
|
||||
EXPECT_TRUE(row.has_value());
|
||||
if (row.has_value()) {
|
||||
for (const auto &column : row.value().get_columns()) {
|
||||
std::cout << column.get_index() << ':';
|
||||
std::cout << column.get_name() << ':';
|
||||
std::cout << column.get_value<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
++row_count;
|
||||
}
|
||||
EXPECT_EQ(std::size_t(1U), row_count);
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
} // namespace repertory
|
187
repertory2/repertory2_test/src/encrypt_provider_test.cpp
Normal file
187
repertory2/repertory2_test/src/encrypt_provider_test.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "providers/encrypt/encrypt_provider.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
/*
|
||||
TEST(encrypt_provider, can_construct_encrypt_provider) {
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
|
||||
// console_consumer consumer{};
|
||||
// event_system::instance().start();
|
||||
{
|
||||
app_config cfg(provider_type::encrypt, "./encrypt_provider_test");
|
||||
EXPECT_FALSE(
|
||||
cfg.set_value_by_name("EncryptConfig.Path", "c:\\src").empty());
|
||||
encrypt_provider provider(cfg);
|
||||
file_manager mgr(cfg, provider);
|
||||
mgr.start();
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&provider](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
&mgr));
|
||||
|
||||
directory_item_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
||||
|
||||
provider.stop();
|
||||
mgr.stop();
|
||||
}
|
||||
|
||||
// event_system::instance().stop();
|
||||
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
}
|
||||
|
||||
TEST(encrypt_provider, can_get_file_list) {
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
|
||||
{
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
const auto path = std::filesystem::path(utils::path::absolute(__FILE__))
|
||||
.parent_path()
|
||||
.string();
|
||||
|
||||
app_config cfg(provider_type::encrypt, "./encrypt_provider_test");
|
||||
EXPECT_STREQ(
|
||||
path.c_str(),
|
||||
cfg.set_value_by_name("EncryptConfig.Path", path.c_str()).c_str());
|
||||
EXPECT_STREQ(
|
||||
"test_token",
|
||||
cfg.set_value_by_name("EncryptConfig.EncryptionToken", "test_token")
|
||||
.c_str());
|
||||
encrypt_provider provider(cfg);
|
||||
|
||||
api_file_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file_list(list));
|
||||
|
||||
api_file_list list2{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file_list(list2));
|
||||
|
||||
EXPECT_EQ(list.size(), list2.size());
|
||||
for (std::size_t idx = 0U; idx < list.size(); idx++) {
|
||||
EXPECT_STREQ(list.at(idx).api_path.c_str(),
|
||||
list2.at(idx).api_path.c_str());
|
||||
EXPECT_STREQ(list.at(idx).api_parent.c_str(),
|
||||
list2.at(idx).api_parent.c_str());
|
||||
EXPECT_EQ(list.at(idx).accessed_date, list2.at(idx).accessed_date);
|
||||
EXPECT_EQ(list.at(idx).changed_date, list2.at(idx).changed_date);
|
||||
EXPECT_EQ(list.at(idx).file_size, list2.at(idx).file_size);
|
||||
EXPECT_TRUE(list.at(idx).key.empty());
|
||||
EXPECT_TRUE(list2.at(idx).key.empty());
|
||||
EXPECT_EQ(list.at(idx).modified_date, list2.at(idx).modified_date);
|
||||
EXPECT_STREQ(list.at(idx).source_path.c_str(),
|
||||
list2.at(idx).source_path.c_str());
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
}
|
||||
|
||||
TEST(encrypt_provider, can_encrypt_and_decrypt_file) {
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
|
||||
{
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
const auto path = std::filesystem::path(utils::path::absolute(__FILE__))
|
||||
.parent_path()
|
||||
.string();
|
||||
|
||||
app_config cfg(provider_type::encrypt, "./encrypt_provider_test");
|
||||
EXPECT_STREQ(
|
||||
path.c_str(),
|
||||
cfg.set_value_by_name("EncryptConfig.Path", path.c_str()).c_str());
|
||||
EXPECT_STREQ(
|
||||
"test_token",
|
||||
cfg.set_value_by_name("EncryptConfig.EncryptionToken", "test_token")
|
||||
.c_str());
|
||||
encrypt_provider provider(cfg);
|
||||
|
||||
api_file_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file_list(list));
|
||||
for (const auto &file : list) {
|
||||
std::string file_path{file.api_path};
|
||||
EXPECT_EQ(api_error::success,
|
||||
utils::encryption::decrypt_file_path(
|
||||
cfg.get_encrypt_config().encryption_token, file_path));
|
||||
file_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {file_path});
|
||||
|
||||
EXPECT_TRUE(std::filesystem::equivalent(file.source_path, file_path));
|
||||
|
||||
std::vector<char> encrypted_data{};
|
||||
stop_type stop_requested = false;
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.read_file_bytes(file.api_path, file.file_size, 0U,
|
||||
encrypted_data, stop_requested));
|
||||
EXPECT_EQ(file.file_size, encrypted_data.size());
|
||||
|
||||
std::vector<char> decrypted_data{};
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(
|
||||
cfg.get_encrypt_config().encryption_token, encrypted_data,
|
||||
decrypted_data));
|
||||
|
||||
native_file::native_file_ptr nf{};
|
||||
EXPECT_EQ(api_error::success, native_file::open(file.source_path, nf));
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(nf->get_file_size(file_size));
|
||||
EXPECT_EQ(file_size, decrypted_data.size());
|
||||
|
||||
std::size_t bytes_read{};
|
||||
std::vector<char> file_data{};
|
||||
file_data.resize(file_size);
|
||||
EXPECT_TRUE(nf->read_bytes(file_data.data(), file_size, 0U, bytes_read));
|
||||
nf->close();
|
||||
|
||||
EXPECT_EQ(file_size, bytes_read);
|
||||
for (std::uint64_t i = 0U; i < bytes_read; i++) {
|
||||
ASSERT_EQ(file_data[i], decrypted_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(
|
||||
utils::file::delete_directory_recursively("./encrypt_provider_test"));
|
||||
} */
|
||||
} // namespace repertory
|
282
repertory2/repertory2_test/src/encrypting_reader_test.cpp
Normal file
282
repertory2/repertory2_test/src/encrypting_reader_test.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
static auto get_source_file_name() -> std::string {
|
||||
return generate_test_file_name("./", "encrypting_reader");
|
||||
}
|
||||
|
||||
TEST(encrypting_reader, get_encrypted_file_name) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
ASSERT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto source_file = create_random_file(source_file_name, 1024UL);
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader(
|
||||
"test.dat", source_file_name, stop_requested, token, std::nullopt);
|
||||
|
||||
auto file_name = reader.get_encrypted_file_name();
|
||||
std::cout << file_name << std::endl;
|
||||
|
||||
EXPECT_EQ(api_error::success,
|
||||
utils::encryption::decrypt_file_name(token, file_name));
|
||||
std::cout << file_name << std::endl;
|
||||
EXPECT_STREQ("test.dat", file_name.c_str());
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
}
|
||||
|
||||
TEST(encrypting_reader, file_data) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto source_file = create_random_file(
|
||||
source_file_name,
|
||||
8U * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader("test.dat", source_file_name,
|
||||
stop_requested, token);
|
||||
|
||||
for (std::uint8_t i = 0U; i < 8U; i++) {
|
||||
data_buffer buffer(
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size());
|
||||
for (std::uint8_t j = 0U; j < 2U; j++) {
|
||||
EXPECT_EQ(buffer.size() / 2U,
|
||||
utils::encryption::encrypting_reader::reader_function(
|
||||
&buffer[(buffer.size() / 2U) * j], buffer.size() / 2U, 1U,
|
||||
&reader));
|
||||
}
|
||||
|
||||
data_buffer decrypted_data;
|
||||
EXPECT_TRUE(
|
||||
utils::encryption::decrypt_data(token, buffer, decrypted_data));
|
||||
|
||||
EXPECT_EQ(utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||
decrypted_data.size());
|
||||
|
||||
std::size_t bytes_read{};
|
||||
data_buffer file_data(decrypted_data.size());
|
||||
EXPECT_TRUE(source_file->read_bytes(
|
||||
file_data.data(), file_data.size(),
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size() * i,
|
||||
bytes_read));
|
||||
EXPECT_EQ(0, std::memcmp(file_data.data(), decrypted_data.data(),
|
||||
file_data.size()));
|
||||
}
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
}
|
||||
|
||||
TEST(encrypting_reader, file_data_in_multiple_chunks) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
ASSERT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto source_file = create_random_file(
|
||||
source_file_name,
|
||||
8U * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader("test.dat", source_file_name,
|
||||
stop_requested, token);
|
||||
|
||||
for (std::uint8_t i = 0U; i < 8U; i += 2U) {
|
||||
data_buffer buffer(
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size() *
|
||||
2U);
|
||||
EXPECT_EQ(buffer.size(),
|
||||
utils::encryption::encrypting_reader::reader_function(
|
||||
buffer.data(), buffer.size(), 1U, &reader));
|
||||
|
||||
for (std::uint8_t j = 0U; j < 2U; j++) {
|
||||
data_buffer decrypted_data;
|
||||
const auto offset = (j * (buffer.size() / 2U));
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(
|
||||
token,
|
||||
data_buffer(
|
||||
std::next(buffer.begin(), static_cast<std::int64_t>(offset)),
|
||||
std::next(buffer.begin(), static_cast<std::int64_t>(
|
||||
offset + (buffer.size() / 2U)))),
|
||||
decrypted_data));
|
||||
|
||||
EXPECT_EQ(utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||
decrypted_data.size());
|
||||
|
||||
std::size_t bytes_read{};
|
||||
data_buffer file_data(decrypted_data.size());
|
||||
EXPECT_TRUE(source_file->read_bytes(
|
||||
file_data.data(), file_data.size(),
|
||||
(utils::encryption::encrypting_reader::get_data_chunk_size() * i) +
|
||||
(j *
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size()),
|
||||
bytes_read));
|
||||
EXPECT_EQ(0, std::memcmp(file_data.data(), decrypted_data.data(),
|
||||
file_data.size()));
|
||||
}
|
||||
}
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
}
|
||||
|
||||
TEST(encrypting_reader, file_data_as_stream) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
ASSERT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto source_file = create_random_file(
|
||||
source_file_name,
|
||||
8U * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader("test.dat", source_file_name,
|
||||
stop_requested, token);
|
||||
auto io_stream = reader.create_iostream();
|
||||
EXPECT_FALSE(io_stream->seekg(0, std::ios_base::end).fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
EXPECT_EQ(reader.get_total_size(),
|
||||
static_cast<std::uint64_t>(io_stream->tellg()));
|
||||
EXPECT_FALSE(io_stream->seekg(0, std::ios_base::beg).fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
|
||||
for (std::uint8_t i = 0U; i < 8U; i++) {
|
||||
data_buffer buffer(
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size());
|
||||
EXPECT_FALSE(
|
||||
io_stream->seekg(static_cast<std::streamoff>(i * buffer.size()))
|
||||
.fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
for (std::uint8_t j = 0U; j < 2U; j++) {
|
||||
EXPECT_FALSE(
|
||||
io_stream
|
||||
->read(&buffer[(buffer.size() / 2U) * j],
|
||||
static_cast<std::streamsize>(buffer.size()) / 2U)
|
||||
.fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
}
|
||||
|
||||
data_buffer decrypted_data;
|
||||
EXPECT_TRUE(
|
||||
utils::encryption::decrypt_data(token, buffer, decrypted_data));
|
||||
|
||||
EXPECT_EQ(utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||
decrypted_data.size());
|
||||
|
||||
std::size_t bytes_read{};
|
||||
data_buffer file_data(decrypted_data.size());
|
||||
EXPECT_TRUE(source_file->read_bytes(
|
||||
file_data.data(), file_data.size(),
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size() * i,
|
||||
bytes_read));
|
||||
EXPECT_EQ(0, std::memcmp(file_data.data(), decrypted_data.data(),
|
||||
file_data.size()));
|
||||
}
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
}
|
||||
|
||||
TEST(encrypting_reader, file_data_in_multiple_chunks_as_stream) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
ASSERT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto source_file = create_random_file(
|
||||
source_file_name,
|
||||
8u * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader("test.dat", source_file_name,
|
||||
stop_requested, token);
|
||||
auto io_stream = reader.create_iostream();
|
||||
EXPECT_FALSE(io_stream->seekg(0, std::ios_base::end).fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
EXPECT_EQ(reader.get_total_size(),
|
||||
static_cast<std::uint64_t>(io_stream->tellg()));
|
||||
EXPECT_FALSE(io_stream->seekg(0, std::ios_base::beg).fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
|
||||
for (std::uint8_t i = 0U; i < 8U; i += 2U) {
|
||||
data_buffer buffer(
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size() *
|
||||
2U);
|
||||
EXPECT_FALSE(
|
||||
io_stream
|
||||
->read(buffer.data(), static_cast<std::streamsize>(buffer.size()))
|
||||
.fail());
|
||||
EXPECT_TRUE(io_stream->good());
|
||||
|
||||
for (std::uint8_t j = 0U; j < 2U; j++) {
|
||||
data_buffer decrypted_data;
|
||||
const auto offset = (j * (buffer.size() / 2U));
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(
|
||||
token,
|
||||
data_buffer(
|
||||
std::next(buffer.begin(), static_cast<std::int64_t>(offset)),
|
||||
std::next(buffer.begin(), static_cast<std::int64_t>(
|
||||
offset + (buffer.size() / 2U)))),
|
||||
decrypted_data));
|
||||
|
||||
EXPECT_EQ(utils::encryption::encrypting_reader::get_data_chunk_size(),
|
||||
decrypted_data.size());
|
||||
|
||||
std::size_t bytes_read{};
|
||||
data_buffer file_data(decrypted_data.size());
|
||||
EXPECT_TRUE(source_file->read_bytes(
|
||||
file_data.data(), file_data.size(),
|
||||
(utils::encryption::encrypting_reader::get_data_chunk_size() * i) +
|
||||
(j *
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size()),
|
||||
bytes_read));
|
||||
EXPECT_EQ(0, std::memcmp(file_data.data(), decrypted_data.data(),
|
||||
file_data.size()));
|
||||
}
|
||||
}
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
}
|
||||
} // namespace repertory
|
125
repertory2/repertory2_test/src/encryption_test.cpp
Normal file
125
repertory2/repertory2_test/src/encryption_test.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
static const std::string buffer = "cow moose dog chicken";
|
||||
static const std::string token = "moose";
|
||||
|
||||
static void test_encrypted_result(const data_buffer &result) {
|
||||
EXPECT_EQ(buffer.size() +
|
||||
utils::encryption::encrypting_reader::get_header_size(),
|
||||
result.size());
|
||||
std::string data;
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(token, result, data));
|
||||
EXPECT_EQ(buffer.size(), data.size());
|
||||
EXPECT_STREQ(buffer.c_str(), data.c_str());
|
||||
}
|
||||
|
||||
TEST(encryption, generate_key) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
const auto str = utils::to_hex_string(key);
|
||||
EXPECT_STREQ(
|
||||
"182072537ada59e4d6b18034a80302ebae935f66adbdf0f271d3d36309c2d481",
|
||||
str.c_str());
|
||||
}
|
||||
|
||||
TEST(encryption, encrypt_data_buffer) {
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(token, buffer, result);
|
||||
test_encrypted_result(result);
|
||||
}
|
||||
|
||||
TEST(encryption, encrypt_data_buffer_with_key) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, buffer, result);
|
||||
test_encrypted_result(result);
|
||||
}
|
||||
|
||||
TEST(encryption, encrypt_data_pointer) {
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(token, &buffer[0u], buffer.size(), result);
|
||||
test_encrypted_result(result);
|
||||
}
|
||||
|
||||
TEST(encryption, encrypt_data_pointer_with_key) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, &buffer[0u], buffer.size(), result);
|
||||
test_encrypted_result(result);
|
||||
}
|
||||
|
||||
TEST(encryption, decrypt_data_pointer) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, &buffer[0u], buffer.size(), result);
|
||||
|
||||
std::string data;
|
||||
EXPECT_TRUE(
|
||||
utils::encryption::decrypt_data(token, &result[0u], result.size(), data));
|
||||
|
||||
EXPECT_EQ(buffer.size(), data.size());
|
||||
EXPECT_STREQ(buffer.c_str(), data.c_str());
|
||||
}
|
||||
|
||||
TEST(encryption, decrypt_data_buffer_with_key) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, &buffer[0u], buffer.size(), result);
|
||||
|
||||
std::string data;
|
||||
EXPECT_TRUE(utils::encryption::decrypt_data(key, result, data));
|
||||
|
||||
EXPECT_EQ(buffer.size(), data.size());
|
||||
EXPECT_STREQ(buffer.c_str(), data.c_str());
|
||||
}
|
||||
|
||||
TEST(encryption, decrypt_data_pointer_with_key) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, &buffer[0u], buffer.size(), result);
|
||||
|
||||
std::string data;
|
||||
EXPECT_TRUE(
|
||||
utils::encryption::decrypt_data(key, &result[0u], result.size(), data));
|
||||
|
||||
EXPECT_EQ(buffer.size(), data.size());
|
||||
EXPECT_STREQ(buffer.c_str(), data.c_str());
|
||||
}
|
||||
|
||||
TEST(encryption, decryption_failure) {
|
||||
const auto key = utils::encryption::generate_key(token);
|
||||
data_buffer result;
|
||||
utils::encryption::encrypt_data(key, &buffer[0u], buffer.size(), result);
|
||||
result[0u] = 0u;
|
||||
result[1u] = 1u;
|
||||
result[2u] = 2u;
|
||||
|
||||
std::string data;
|
||||
EXPECT_FALSE(utils::encryption::decrypt_data(key, result, data));
|
||||
}
|
||||
} // namespace repertory
|
676
repertory2/repertory2_test/src/file_manager_open_file_test.cpp
Normal file
676
repertory2/repertory2_test/src/file_manager_open_file_test.cpp
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "mocks/mock_provider.hpp"
|
||||
#include "mocks/mock_upload_manager.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/event_capture.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
static constexpr const std::size_t test_chunk_size = 1024u;
|
||||
|
||||
static void test_closeable_open_file(const file_manager::open_file &o,
|
||||
bool directory, const api_error &e,
|
||||
std::uint64_t size,
|
||||
const std::string &source_path) {
|
||||
EXPECT_EQ(directory, o.is_directory());
|
||||
EXPECT_EQ(e, o.get_api_error());
|
||||
EXPECT_EQ(std::size_t(0u), o.get_open_file_count());
|
||||
EXPECT_EQ(std::uint64_t(size), o.get_file_size());
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
EXPECT_TRUE(o.can_close());
|
||||
}
|
||||
|
||||
static void validate_write(file_manager::open_file &o, std::size_t offset,
|
||||
data_buffer data, std::size_t bytes_written) {
|
||||
EXPECT_EQ(data.size(), bytes_written);
|
||||
|
||||
data_buffer read_data{};
|
||||
EXPECT_EQ(api_error::success, o.read(data.size(), offset, read_data));
|
||||
|
||||
EXPECT_TRUE(std::equal(data.begin(), data.end(), read_data.begin()));
|
||||
}
|
||||
|
||||
TEST(open_file, properly_initializes_state_for_0_byte_file) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = 0u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
EXPECT_EQ(std::size_t(0u), o.get_read_state().size());
|
||||
EXPECT_FALSE(o.is_modified());
|
||||
EXPECT_EQ(test_chunk_size, o.get_chunk_size());
|
||||
}
|
||||
|
||||
TEST(open_file, properly_initializes_state_based_on_chunk_size) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = 8u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
EXPECT_CALL(um, remove_resume)
|
||||
.WillOnce(
|
||||
[&fsi](const std::string &api_path, const std::string &source_path2) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
EXPECT_EQ(fsi.source_path, source_path2);
|
||||
});
|
||||
|
||||
file_manager::open_file o(1u, 0U, fsi, mp, um);
|
||||
EXPECT_EQ(std::size_t(8u), o.get_read_state().size());
|
||||
EXPECT_TRUE(o.get_read_state().none());
|
||||
|
||||
EXPECT_FALSE(o.is_modified());
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, META_SOURCE, _))
|
||||
.WillOnce(Return(api_error::success));
|
||||
EXPECT_EQ(std::size_t(1u), o.get_chunk_size());
|
||||
}
|
||||
|
||||
TEST(open_file, will_not_change_source_path_for_0_byte_file) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = 0u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
file_manager::open_file o(0u, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, 0u, source_path);
|
||||
|
||||
o.close();
|
||||
EXPECT_EQ(api_error::success, o.get_api_error());
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
EXPECT_TRUE(utils::file::is_file(fsi.source_path));
|
||||
}
|
||||
|
||||
TEST(open_file, will_change_source_path_if_file_size_is_greater_than_0) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
EXPECT_CALL(um, remove_resume)
|
||||
.WillOnce(
|
||||
[&fsi](const std::string &api_path, const std::string &source_path2) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
EXPECT_EQ(fsi.source_path, source_path2);
|
||||
});
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, META_SOURCE, _))
|
||||
.WillOnce([&fsi](const std::string &, const std::string &,
|
||||
const std::string &source_path2) -> api_error {
|
||||
EXPECT_STRNE(fsi.source_path.c_str(), source_path2.c_str());
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, test_chunk_size,
|
||||
source_path);
|
||||
|
||||
o.close();
|
||||
EXPECT_EQ(api_error::download_stopped, o.get_api_error());
|
||||
EXPECT_STRNE(source_path.c_str(), o.get_source_path().c_str());
|
||||
EXPECT_FALSE(utils::file::is_file(source_path));
|
||||
}
|
||||
|
||||
TEST(open_file,
|
||||
will_not_change_source_path_if_file_size_matches_existing_source) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
create_random_file(source_path, test_chunk_size)->close();
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, test_chunk_size,
|
||||
source_path);
|
||||
|
||||
o.close();
|
||||
EXPECT_EQ(api_error::success, o.get_api_error());
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
EXPECT_TRUE(utils::file::is_file(source_path));
|
||||
}
|
||||
|
||||
TEST(open_file, write_with_incomplete_download) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
auto nf = create_random_file(generate_test_file_name(".", "test_src"),
|
||||
test_chunk_size * 2u);
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 2u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, test_chunk_size * 2u,
|
||||
source_path);
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, _))
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
EXPECT_CALL(mp, read_file_bytes)
|
||||
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||
std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
if (stop_requested) {
|
||||
return api_error::download_stopped;
|
||||
}
|
||||
|
||||
if (offset == 0u) {
|
||||
std::size_t bytes_read{};
|
||||
data.resize(size);
|
||||
auto ret = nf->read_bytes(&data[0u], size, offset, bytes_read)
|
||||
? api_error::success
|
||||
: api_error::os_error;
|
||||
EXPECT_EQ(bytes_read, data.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (not stop_requested) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
return api_error::download_stopped;
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_upload).WillOnce([&fsi](const std::string &api_path) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, store_resume)
|
||||
.Times(2)
|
||||
.WillRepeatedly([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
|
||||
data_buffer data = {10, 9, 8};
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_EQ(api_error::success, o.write(0u, data, bytes_written));
|
||||
validate_write(o, 0u, data, bytes_written);
|
||||
|
||||
const auto test_state = [&]() {
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
|
||||
EXPECT_FALSE(o.can_close());
|
||||
|
||||
EXPECT_TRUE(o.is_modified());
|
||||
|
||||
EXPECT_TRUE(o.get_read_state(0u));
|
||||
EXPECT_FALSE(o.get_read_state(1u));
|
||||
};
|
||||
test_state();
|
||||
|
||||
o.close();
|
||||
nf->close();
|
||||
|
||||
test_state();
|
||||
|
||||
EXPECT_EQ(api_error::download_incomplete, o.get_api_error());
|
||||
|
||||
EXPECT_TRUE(utils::file::is_file(fsi.source_path));
|
||||
}
|
||||
|
||||
TEST(open_file, write_new_file) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = 0u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
EXPECT_CALL(um, store_resume).WillOnce([&fsi](const i_open_file &o) {
|
||||
EXPECT_EQ(fsi.api_path, o.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, o.get_source_path());
|
||||
});
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, 0u, source_path);
|
||||
data_buffer data = {10, 9, 8};
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, _))
|
||||
.WillOnce([&data](const std::string &,
|
||||
const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_SIZE).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
EXPECT_EQ(data.size(), utils::string::to_size_t(meta.at(META_SIZE)));
|
||||
return api_error::success;
|
||||
})
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_upload).WillOnce([&fsi](const std::string &api_path) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, queue_upload).WillOnce([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_EQ(api_error::success, o.write(0u, data, bytes_written));
|
||||
|
||||
const auto test_state = [&]() {
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
|
||||
EXPECT_FALSE(o.can_close());
|
||||
EXPECT_TRUE(o.is_modified());
|
||||
|
||||
EXPECT_TRUE(o.get_read_state(0u));
|
||||
EXPECT_EQ(std::size_t(1u), o.get_read_state().size());
|
||||
EXPECT_EQ(data.size(), o.get_file_size());
|
||||
};
|
||||
test_state();
|
||||
|
||||
o.close();
|
||||
|
||||
test_state();
|
||||
|
||||
EXPECT_EQ(api_error::success, o.get_api_error());
|
||||
|
||||
EXPECT_TRUE(utils::file::is_file(fsi.source_path));
|
||||
}
|
||||
|
||||
TEST(open_file, write_new_file_multiple_chunks) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = 0u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
EXPECT_CALL(um, store_resume).WillOnce([&fsi](const i_open_file &o) {
|
||||
EXPECT_EQ(fsi.api_path, o.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, o.get_source_path());
|
||||
});
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, 0u, source_path);
|
||||
data_buffer data = {10, 9, 8};
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, _))
|
||||
.WillOnce([&data](const std::string &,
|
||||
const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_SIZE).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
EXPECT_EQ(data.size(), utils::string::to_size_t(meta.at(META_SIZE)));
|
||||
return api_error::success;
|
||||
})
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
return api_error::success;
|
||||
})
|
||||
.WillOnce(
|
||||
[&data](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_SIZE).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
EXPECT_EQ(data.size() + test_chunk_size,
|
||||
utils::string::to_size_t(meta.at(META_SIZE)));
|
||||
return api_error::success;
|
||||
})
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_upload).WillOnce([&fsi](const std::string &api_path) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, queue_upload).WillOnce([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_EQ(api_error::success, o.write(0u, data, bytes_written));
|
||||
EXPECT_EQ(api_error::success, o.write(test_chunk_size, data, bytes_written));
|
||||
|
||||
const auto test_state = [&]() {
|
||||
EXPECT_STREQ(source_path.c_str(), o.get_source_path().c_str());
|
||||
|
||||
EXPECT_FALSE(o.can_close());
|
||||
EXPECT_TRUE(o.is_modified());
|
||||
|
||||
EXPECT_EQ(std::size_t(2u), o.get_read_state().size());
|
||||
for (std::size_t i = 0u; i < 2u; i++) {
|
||||
EXPECT_TRUE(o.get_read_state(i));
|
||||
}
|
||||
|
||||
EXPECT_EQ(data.size() + test_chunk_size, o.get_file_size());
|
||||
};
|
||||
test_state();
|
||||
|
||||
o.close();
|
||||
|
||||
test_state();
|
||||
|
||||
EXPECT_EQ(api_error::success, o.get_api_error());
|
||||
|
||||
EXPECT_TRUE(utils::file::is_file(fsi.source_path));
|
||||
}
|
||||
|
||||
TEST(open_file, resize_file_to_0_bytes) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
create_random_file(source_path, test_chunk_size * 4u)->close();
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, fsi.size, source_path);
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, _))
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_SIZE).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
EXPECT_EQ(std::size_t(0u),
|
||||
utils::string::to_size_t(meta.at(META_SIZE)));
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_upload).WillOnce([&fsi](const std ::string &api_path) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, queue_upload).WillOnce([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
EXPECT_CALL(um, store_resume).WillOnce([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
|
||||
EXPECT_EQ(api_error::success, o.resize(0u));
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), o.get_file_size());
|
||||
EXPECT_FALSE(o.can_close());
|
||||
EXPECT_TRUE(o.is_modified());
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), o.get_read_state().size());
|
||||
}
|
||||
|
||||
TEST(open_file, resize_file_by_full_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
create_random_file(source_path, test_chunk_size * 4u)->close();
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
EXPECT_CALL(um, store_resume).WillOnce([&fsi](const i_open_file &o) {
|
||||
EXPECT_EQ(fsi.api_path, o.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, o.get_source_path());
|
||||
});
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
test_closeable_open_file(o, false, api_error::success, fsi.size, source_path);
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, _))
|
||||
.WillOnce([](const std::string &, const api_meta_map &meta) -> api_error {
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_CHANGED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_MODIFIED).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_SIZE).empty()));
|
||||
EXPECT_NO_THROW(EXPECT_FALSE(meta.at(META_WRITTEN).empty()));
|
||||
EXPECT_EQ(std::size_t(test_chunk_size * 3u),
|
||||
utils::string::to_size_t(meta.at(META_SIZE)));
|
||||
return api_error::success;
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_upload).WillOnce([&fsi](const std::string &api_path) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, queue_upload).WillOnce([&fsi](const i_open_file &cur_file) {
|
||||
EXPECT_EQ(fsi.api_path, cur_file.get_api_path());
|
||||
EXPECT_EQ(fsi.source_path, cur_file.get_source_path());
|
||||
});
|
||||
|
||||
EXPECT_EQ(api_error::success, o.resize(test_chunk_size * 3u));
|
||||
|
||||
EXPECT_EQ(std::size_t(test_chunk_size * 3u), o.get_file_size());
|
||||
EXPECT_FALSE(o.can_close());
|
||||
EXPECT_TRUE(o.is_modified());
|
||||
EXPECT_EQ(std::size_t(3u), o.get_read_state().size());
|
||||
}
|
||||
|
||||
TEST(open_file, can_add_handle) {
|
||||
event_system::instance().start();
|
||||
console_consumer c;
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
event_consumer ec("filesystem_item_opened", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const filesystem_item_opened &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_directory().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
event_consumer ec2("filesystem_item_handle_opened", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const filesystem_item_handle_opened &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_directory().get<std::string>().c_str());
|
||||
EXPECT_STREQ("1", ee.get_handle().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, META_SOURCE, _))
|
||||
.WillOnce(Return(api_error::success));
|
||||
EXPECT_CALL(um, remove_resume)
|
||||
.WillOnce(
|
||||
[&fsi](const std::string &api_path, const std::string &source_path2) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
EXPECT_EQ(fsi.source_path, source_path2);
|
||||
});
|
||||
|
||||
event_capture capture(
|
||||
{"filesystem_item_opened", "filesystem_item_handle_opened"});
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
#ifdef _WIN32
|
||||
o.add(1u, {});
|
||||
EXPECT_EQ(nullptr, o.get_open_data(1u).directory_buffer);
|
||||
#else
|
||||
o.add(1u, O_RDWR | O_SYNC);
|
||||
EXPECT_EQ(O_RDWR | O_SYNC, o.get_open_data(1u));
|
||||
#endif
|
||||
|
||||
capture.wait_for_empty();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(open_file, can_remove_handle) {
|
||||
event_system::instance().start();
|
||||
console_consumer c;
|
||||
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
mock_upload_manager um;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
event_consumer ec("filesystem_item_closed", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const filesystem_item_closed &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_directory().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
event_consumer ec2("filesystem_item_handle_closed", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const filesystem_item_handle_closed &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_directory().get<std::string>().c_str());
|
||||
EXPECT_STREQ("1", ee.get_handle().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
EXPECT_CALL(um, remove_resume)
|
||||
.WillOnce(
|
||||
[&fsi](const std::string &api_path, const std::string &source_path2) {
|
||||
EXPECT_EQ(fsi.api_path, api_path);
|
||||
EXPECT_EQ(fsi.source_path, source_path2);
|
||||
});
|
||||
EXPECT_CALL(mp, set_item_meta(fsi.api_path, META_SOURCE, _))
|
||||
.WillOnce(Return(api_error::success));
|
||||
|
||||
event_capture capture({
|
||||
"filesystem_item_opened",
|
||||
"filesystem_item_handle_opened",
|
||||
"filesystem_item_handle_closed",
|
||||
"filesystem_item_closed",
|
||||
});
|
||||
|
||||
file_manager::open_file o(test_chunk_size, 0U, fsi, mp, um);
|
||||
#ifdef _WIN32
|
||||
o.add(1u, {});
|
||||
#else
|
||||
o.add(1u, O_RDWR | O_SYNC);
|
||||
#endif
|
||||
o.remove(1u);
|
||||
|
||||
capture.wait_for_empty();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(open_file,
|
||||
can_read_locally_after_write_with_file_size_greater_than_existing_size) {}
|
||||
|
||||
TEST(open_file, test_valid_download_chunks) {}
|
||||
|
||||
TEST(open_file, test_full_download_with_partial_chunk) {}
|
||||
|
||||
TEST(open_file, source_is_read_after_full_download) {}
|
||||
} // namespace repertory
|
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "mocks/mock_provider.hpp"
|
||||
#include "mocks/mock_upload_manager.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/unix/unix_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
static constexpr const std::size_t test_chunk_size = 1024u;
|
||||
|
||||
TEST(ring_buffer_open_file, can_forward_to_last_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(0u, 3u);
|
||||
rb.forward(4u);
|
||||
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_last_chunk());
|
||||
for (std::size_t chunk = 0u; chunk < 8u; chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file,
|
||||
can_forward_to_last_chunk_if_count_is_greater_than_remaining) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(0u, 3u);
|
||||
rb.forward(100u);
|
||||
|
||||
EXPECT_EQ(std::size_t(15u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(8u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(15u), rb.get_last_chunk());
|
||||
for (std::size_t chunk = 8u; chunk <= 15u; chunk++) {
|
||||
EXPECT_FALSE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_forward_after_last_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(0u, 3u);
|
||||
rb.forward(5u);
|
||||
|
||||
EXPECT_EQ(std::size_t(8u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(1u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(8u), rb.get_last_chunk());
|
||||
EXPECT_FALSE(rb.get_read_state(8u));
|
||||
for (std::size_t chunk = 1u; chunk < 8u; chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_forward_and_rollover_after_last_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(16u, 20u);
|
||||
rb.forward(8u);
|
||||
|
||||
EXPECT_EQ(std::size_t(28u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(21u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(28u), rb.get_last_chunk());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_reverse_to_first_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(0u, 3u);
|
||||
rb.reverse(3u);
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_last_chunk());
|
||||
for (std::size_t chunk = 0u; chunk < 8u; chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file,
|
||||
can_reverse_to_first_chunk_if_count_is_greater_than_remaining) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(0u, 3u);
|
||||
rb.reverse(13u);
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_last_chunk());
|
||||
for (std::size_t chunk = 0u; chunk < 8u; chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_reverse_before_first_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 16u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(1u, 3u);
|
||||
rb.reverse(3u);
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_last_chunk());
|
||||
EXPECT_FALSE(rb.get_read_state(0u));
|
||||
for (std::size_t chunk = 1u; chunk < 8u; chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_reverse_and_rollover_before_first_chunk) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(16u, 20u);
|
||||
rb.reverse(8u);
|
||||
|
||||
EXPECT_EQ(std::size_t(12u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(12u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(19u), rb.get_last_chunk());
|
||||
|
||||
EXPECT_FALSE(rb.get_read_state(12u));
|
||||
EXPECT_FALSE(rb.get_read_state(13u));
|
||||
EXPECT_FALSE(rb.get_read_state(14u));
|
||||
EXPECT_FALSE(rb.get_read_state(15u));
|
||||
for (std::size_t chunk = 16u; chunk <= rb.get_last_chunk(); chunk++) {
|
||||
EXPECT_TRUE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, can_reverse_full_ring) {
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
rb.set(8u, 15u);
|
||||
rb.reverse(16u);
|
||||
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_current_chunk());
|
||||
EXPECT_EQ(std::size_t(0u), rb.get_first_chunk());
|
||||
EXPECT_EQ(std::size_t(7u), rb.get_last_chunk());
|
||||
|
||||
for (std::size_t chunk = 0u; chunk <= rb.get_last_chunk(); chunk++) {
|
||||
EXPECT_FALSE(rb.get_read_state(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, read_full_file) {
|
||||
const auto download_source_path = generate_test_file_name(".", "test");
|
||||
auto nf = create_random_file(download_source_path, test_chunk_size * 32u);
|
||||
|
||||
const auto dest_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = generate_test_file_name(".", "test");
|
||||
|
||||
EXPECT_CALL(mp, read_file_bytes)
|
||||
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||
std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
std::size_t bytes_read{};
|
||||
data.resize(size);
|
||||
auto ret = nf->read_bytes(&data[0u], size, offset, bytes_read)
|
||||
? api_error::success
|
||||
: api_error::os_error;
|
||||
EXPECT_EQ(bytes_read, data.size());
|
||||
return ret;
|
||||
});
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
|
||||
native_file_ptr nf2;
|
||||
EXPECT_EQ(api_error::success, native_file::create_or_open(dest_path, nf2));
|
||||
|
||||
auto to_read = fsi.size;
|
||||
std::size_t chunk = 0u;
|
||||
while (to_read) {
|
||||
data_buffer data{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
rb.read(test_chunk_size, chunk * test_chunk_size, data));
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_TRUE(nf2->write_bytes(data.data(), data.size(),
|
||||
chunk * test_chunk_size, bytes_written));
|
||||
chunk++;
|
||||
to_read -= data.size();
|
||||
}
|
||||
nf2->close();
|
||||
nf->close();
|
||||
|
||||
EXPECT_STREQ(utils::file::generate_sha256(download_source_path).c_str(),
|
||||
utils::file::generate_sha256(dest_path).c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, read_full_file_in_reverse) {
|
||||
const auto download_source_path = generate_test_file_name(".", "test");
|
||||
auto nf = create_random_file(download_source_path, test_chunk_size * 32u);
|
||||
|
||||
const auto dest_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = generate_test_file_name(".", "test");
|
||||
|
||||
EXPECT_CALL(mp, read_file_bytes)
|
||||
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||
std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
std::size_t bytes_read{};
|
||||
data.resize(size);
|
||||
auto ret = nf->read_bytes(&data[0u], size, offset, bytes_read)
|
||||
? api_error::success
|
||||
: api_error::os_error;
|
||||
EXPECT_EQ(bytes_read, data.size());
|
||||
return ret;
|
||||
});
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
|
||||
native_file_ptr nf2;
|
||||
EXPECT_EQ(api_error::success, native_file::create_or_open(dest_path, nf2));
|
||||
|
||||
auto to_read = fsi.size;
|
||||
std::size_t chunk = rb.get_total_chunks() - 1u;
|
||||
while (to_read) {
|
||||
data_buffer data{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
rb.read(test_chunk_size, chunk * test_chunk_size, data));
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_TRUE(nf2->write_bytes(data.data(), data.size(),
|
||||
chunk * test_chunk_size, bytes_written));
|
||||
chunk--;
|
||||
to_read -= data.size();
|
||||
}
|
||||
nf2->close();
|
||||
nf->close();
|
||||
|
||||
EXPECT_STREQ(utils::file::generate_sha256(download_source_path).c_str(),
|
||||
utils::file::generate_sha256(dest_path).c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, read_full_file_in_partial_chunks) {
|
||||
const auto download_source_path = generate_test_file_name(".", "test");
|
||||
auto nf = create_random_file(download_source_path, test_chunk_size * 32u);
|
||||
|
||||
const auto dest_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = generate_test_file_name(".", "test");
|
||||
|
||||
EXPECT_CALL(mp, read_file_bytes)
|
||||
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||
std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
std::size_t bytes_read{};
|
||||
data.resize(size);
|
||||
auto ret = nf->read_bytes(&data[0u], size, offset, bytes_read)
|
||||
? api_error::success
|
||||
: api_error::os_error;
|
||||
EXPECT_EQ(bytes_read, data.size());
|
||||
return ret;
|
||||
});
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
|
||||
native_file_ptr nf2;
|
||||
EXPECT_EQ(api_error::success, native_file::create_or_open(dest_path, nf2));
|
||||
|
||||
auto total_read = std::uint64_t(0u);
|
||||
|
||||
while (total_read < fsi.size) {
|
||||
data_buffer data{};
|
||||
EXPECT_EQ(api_error::success, rb.read(3u, total_read, data));
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_TRUE(nf2->write_bytes(data.data(), data.size(), total_read,
|
||||
bytes_written));
|
||||
total_read += data.size();
|
||||
}
|
||||
nf2->close();
|
||||
nf->close();
|
||||
|
||||
EXPECT_STREQ(utils::file::generate_sha256(download_source_path).c_str(),
|
||||
utils::file::generate_sha256(dest_path).c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
|
||||
TEST(ring_buffer_open_file, read_full_file_in_partial_chunks_in_reverse) {
|
||||
const auto download_source_path = generate_test_file_name(".", "test");
|
||||
auto nf = create_random_file(download_source_path, test_chunk_size * 32u);
|
||||
|
||||
const auto dest_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.directory = false;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 32u;
|
||||
fsi.source_path = generate_test_file_name(".", "test");
|
||||
|
||||
EXPECT_CALL(mp, read_file_bytes)
|
||||
.WillRepeatedly([&nf](const std::string & /* api_path */,
|
||||
std::size_t size, std::uint64_t offset,
|
||||
data_buffer &data,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
std::size_t bytes_read{};
|
||||
data.resize(size);
|
||||
auto ret = nf->read_bytes(&data[0u], size, offset, bytes_read)
|
||||
? api_error::success
|
||||
: api_error::os_error;
|
||||
EXPECT_EQ(bytes_read, data.size());
|
||||
return ret;
|
||||
});
|
||||
{
|
||||
file_manager::ring_buffer_open_file rb("./ring_buffer_directory",
|
||||
test_chunk_size, 30U, fsi, mp, 8u);
|
||||
|
||||
native_file_ptr nf2;
|
||||
EXPECT_EQ(api_error::success, native_file::create_or_open(dest_path, nf2));
|
||||
|
||||
auto total_read = std::uint64_t(0u);
|
||||
const auto read_size = 3u;
|
||||
|
||||
while (total_read < fsi.size) {
|
||||
const auto offset = fsi.size - total_read - read_size;
|
||||
const auto remain = fsi.size - total_read;
|
||||
|
||||
data_buffer data{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
rb.read(static_cast<std::size_t>(
|
||||
std::min(remain, std::uint64_t(read_size))),
|
||||
(remain >= read_size) ? offset : 0u, data));
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_TRUE(nf2->write_bytes(data.data(), data.size(),
|
||||
(remain >= read_size) ? offset : 0u,
|
||||
bytes_written));
|
||||
total_read += data.size();
|
||||
}
|
||||
nf2->close();
|
||||
nf->close();
|
||||
|
||||
EXPECT_STREQ(utils::file::generate_sha256(download_source_path).c_str(),
|
||||
utils::file::generate_sha256(dest_path).c_str());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(
|
||||
utils::file::delete_directory_recursively("./ring_buffer_directory"));
|
||||
}
|
||||
} // namespace repertory
|
1870
repertory2/repertory2_test/src/file_manager_test.cpp
Normal file
1870
repertory2/repertory2_test/src/file_manager_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
184
repertory2/repertory2_test/src/file_manager_upload_test.cpp
Normal file
184
repertory2/repertory2_test/src/file_manager_upload_test.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "mocks/mock_provider.hpp"
|
||||
#include "mocks/mock_upload_manager.hpp"
|
||||
#include "utils/event_capture.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
static constexpr const std::size_t test_chunk_size = 1024u;
|
||||
|
||||
TEST(upload, can_upload_a_valid_file) {
|
||||
console_consumer c;
|
||||
|
||||
event_system::instance().start();
|
||||
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
event_consumer ec("file_upload_completed", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const file_upload_completed &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("success", ee.get_result().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_cancelled().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
EXPECT_CALL(mp, upload_file(fsi.api_path, fsi.source_path, _))
|
||||
.WillOnce([&fsi](const std::string &, const std::string &,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
return api_error::success;
|
||||
});
|
||||
file_manager::upload upload(fsi, mp);
|
||||
|
||||
event_capture e({"file_upload_completed"});
|
||||
e.wait_for_empty();
|
||||
|
||||
EXPECT_EQ(api_error::success, upload.get_api_error());
|
||||
EXPECT_FALSE(upload.is_cancelled());
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(upload, can_cancel_upload) {
|
||||
console_consumer c;
|
||||
|
||||
event_system::instance().start();
|
||||
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
// create_random_file(source_path, test_chunk_size * 4u)->close();
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
event_consumer ec("file_upload_completed", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const file_upload_completed &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("upload_stopped", ee.get_result().get<std::string>().c_str());
|
||||
EXPECT_STREQ("1", ee.get_cancelled().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
|
||||
EXPECT_CALL(mp, upload_file(fsi.api_path, fsi.source_path, _))
|
||||
.WillOnce([&cv, &fsi, &mtx](const std::string &, const std::string &,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
EXPECT_FALSE(stop_requested);
|
||||
|
||||
unique_mutex_lock l(mtx);
|
||||
cv.notify_one();
|
||||
l.unlock();
|
||||
|
||||
l.lock();
|
||||
cv.wait(l);
|
||||
l.unlock();
|
||||
|
||||
EXPECT_TRUE(stop_requested);
|
||||
|
||||
return api_error::upload_stopped;
|
||||
});
|
||||
|
||||
unique_mutex_lock l(mtx);
|
||||
file_manager::upload upload(fsi, mp);
|
||||
cv.wait(l);
|
||||
|
||||
upload.cancel();
|
||||
|
||||
cv.notify_one();
|
||||
l.unlock();
|
||||
|
||||
event_capture e({"file_upload_completed"});
|
||||
e.wait_for_empty();
|
||||
|
||||
EXPECT_EQ(api_error::upload_stopped, upload.get_api_error());
|
||||
EXPECT_TRUE(upload.is_cancelled());
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(upload, can_stop_upload) {
|
||||
console_consumer c;
|
||||
|
||||
event_system::instance().start();
|
||||
|
||||
const auto source_path = generate_test_file_name(".", "test");
|
||||
|
||||
mock_provider mp;
|
||||
|
||||
EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false));
|
||||
|
||||
filesystem_item fsi;
|
||||
fsi.api_path = "/test.txt";
|
||||
fsi.size = test_chunk_size * 4u;
|
||||
fsi.source_path = source_path;
|
||||
|
||||
event_consumer ec("file_upload_completed", [&fsi](const event &e) {
|
||||
const auto &ee = dynamic_cast<const file_upload_completed &>(e);
|
||||
EXPECT_STREQ(fsi.api_path.c_str(),
|
||||
ee.get_api_path().get<std::string>().c_str());
|
||||
EXPECT_STREQ(fsi.source_path.c_str(),
|
||||
ee.get_source().get<std::string>().c_str());
|
||||
EXPECT_STREQ("upload_stopped", ee.get_result().get<std::string>().c_str());
|
||||
EXPECT_STREQ("0", ee.get_cancelled().get<std::string>().c_str());
|
||||
});
|
||||
|
||||
EXPECT_CALL(mp, upload_file(fsi.api_path, fsi.source_path, _))
|
||||
.WillOnce([&fsi](const std::string &, const std::string &,
|
||||
stop_type &stop_requested) -> api_error {
|
||||
std::this_thread::sleep_for(3s);
|
||||
EXPECT_TRUE(stop_requested);
|
||||
return api_error::upload_stopped;
|
||||
});
|
||||
|
||||
event_capture e({"file_upload_completed"});
|
||||
|
||||
{ file_manager::upload upload(fsi, mp); }
|
||||
|
||||
e.wait_for_empty();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
} // namespace repertory
|
706
repertory2/repertory2_test/src/fuse_drive_test.cpp
Normal file
706
repertory2/repertory2_test/src/fuse_drive_test.cpp
Normal file
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
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 !_WIN32
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "drives/fuse/fuse_drive.hpp"
|
||||
#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/utils.hpp"
|
||||
|
||||
#ifndef ACCESSPERMS
|
||||
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
|
||||
#endif
|
||||
|
||||
static constexpr const auto SLEEP_SECONDS = 1.5s;
|
||||
|
||||
namespace repertory {
|
||||
static void execute_mount(const std::string &data_directory,
|
||||
const std::vector<std::string> &drive_args,
|
||||
std::thread &mount_thread) {
|
||||
auto cmd = "./repertory -dd \"" + data_directory + "\"" + " " +
|
||||
utils::string::join(drive_args, ' ');
|
||||
std::cout << cmd << std::endl;
|
||||
EXPECT_EQ(0, system(cmd.c_str()));
|
||||
mount_thread.join();
|
||||
}
|
||||
|
||||
static void execute_unmount(const std::string &mount_location) {
|
||||
// filesystem_item fsi{};
|
||||
// EXPECT_EQ(api_error::success, provider.get_filesystem_item("/", true,
|
||||
// fsi)); EXPECT_STREQ("/", fsi.api_path.c_str());
|
||||
// EXPECT_TRUE(fsi.api_parent.empty());
|
||||
// EXPECT_TRUE(fsi.directory);
|
||||
// EXPECT_EQ(std::uint64_t(0u), fsi.size);
|
||||
// EXPECT_TRUE(fsi.source_path.empty());
|
||||
//
|
||||
// api_meta_map meta{};
|
||||
// EXPECT_EQ(api_error::success, provider.get_item_meta("/", meta));
|
||||
// for (const auto &kv : meta) {
|
||||
// std::cout << kv.first << '=' << kv.second << std::endl;
|
||||
// }
|
||||
|
||||
auto unmounted = false;
|
||||
for (int i = 0; not unmounted && (i < 50); i++) {
|
||||
unmounted = (fuse_base::unmount(mount_location) == 0);
|
||||
if (not unmounted) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unmounted);
|
||||
}
|
||||
|
||||
static auto create_file_and_test(const std::string &mount_location,
|
||||
std::string name) -> std::string {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto file_path =
|
||||
utils::path::absolute(utils::path::combine(mount_location, {name}));
|
||||
|
||||
auto fd =
|
||||
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
EXPECT_TRUE(utils::file::is_file(file_path));
|
||||
EXPECT_FALSE(utils::file::is_directory(file_path));
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
EXPECT_EQ(0u, file_size);
|
||||
|
||||
EXPECT_EQ(0, close(fd));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static void rmdir_and_test(const std::string &directory_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
int ret = 0;
|
||||
for (auto i = 0; ((ret = rmdir(directory_path.c_str())) != 0) && (i < 20);
|
||||
i++) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, ret);
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
EXPECT_FALSE(utils::file::is_directory(directory_path));
|
||||
EXPECT_FALSE(utils::file::is_file(directory_path));
|
||||
}
|
||||
|
||||
static void unlink_file_and_test(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
int ret = 0;
|
||||
for (auto i = 0; ((ret = unlink(file_path.c_str())) != 0) && (i < 20); i++) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, ret);
|
||||
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
EXPECT_FALSE(utils::file::is_directory(file_path));
|
||||
EXPECT_FALSE(utils::file::is_file(file_path));
|
||||
}
|
||||
|
||||
static void test_chmod(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
struct stat64 unix_st {};
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
||||
ACCESSPERMS & unix_st.st_mode);
|
||||
}
|
||||
|
||||
static void test_chown(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
struct stat64 unix_st {};
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(0U, unix_st.st_gid);
|
||||
|
||||
EXPECT_EQ(0, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(0U, unix_st.st_gid);
|
||||
}
|
||||
|
||||
static void test_mkdir(const std::string & /* api_path */,
|
||||
const std::string &directory_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, mkdir(directory_path.c_str(),
|
||||
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP));
|
||||
|
||||
EXPECT_TRUE(utils::file::is_directory(directory_path));
|
||||
EXPECT_FALSE(utils::file::is_file(directory_path));
|
||||
|
||||
struct stat64 unix_st {};
|
||||
stat64(directory_path.c_str(), &unix_st);
|
||||
|
||||
EXPECT_EQ(getuid(), unix_st.st_uid);
|
||||
EXPECT_EQ(getgid(), unix_st.st_gid);
|
||||
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
|
||||
S_IXGRP),
|
||||
ACCESSPERMS & unix_st.st_mode);
|
||||
}
|
||||
|
||||
static void test_write_and_read(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto fd =
|
||||
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
|
||||
std::string data = "TestData";
|
||||
EXPECT_EQ(data.size(),
|
||||
static_cast<std::size_t>(write(fd, data.data(), data.size())));
|
||||
EXPECT_EQ(0, lseek(fd, 0, SEEK_SET));
|
||||
fsync(fd);
|
||||
|
||||
data_buffer read_data;
|
||||
read_data.resize(data.size());
|
||||
EXPECT_EQ(data.size(), static_cast<std::size_t>(
|
||||
read(fd, read_data.data(), read_data.size())));
|
||||
|
||||
EXPECT_EQ(0, memcmp(data.data(), read_data.data(), data.size()));
|
||||
|
||||
EXPECT_EQ(0, close(fd));
|
||||
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
EXPECT_EQ(data.size(), file_size);
|
||||
|
||||
// filesystem_item fsi{};
|
||||
// EXPECT_EQ(api_error::success,
|
||||
// provider.get_filesystem_item(api_path, false, fsi));
|
||||
// EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
|
||||
// EXPECT_EQ(data.size(), file_size);
|
||||
}
|
||||
|
||||
static void test_rename_file(const std::string &from_file_path,
|
||||
const std::string &to_file_path,
|
||||
bool is_rename_supported) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto fd = open(from_file_path.c_str(), O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
close(fd);
|
||||
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
if (is_rename_supported) {
|
||||
EXPECT_EQ(0, rename(from_file_path.c_str(), to_file_path.c_str()));
|
||||
EXPECT_FALSE(utils::file::is_file(from_file_path));
|
||||
EXPECT_TRUE(utils::file::is_file(to_file_path));
|
||||
} else {
|
||||
EXPECT_EQ(-1, rename(from_file_path.c_str(), to_file_path.c_str()));
|
||||
EXPECT_TRUE(utils::file::is_file(from_file_path));
|
||||
EXPECT_FALSE(utils::file::is_file(to_file_path));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_rename_directory(const std::string &from_dir_path,
|
||||
const std::string &to_dir_path,
|
||||
bool is_rename_supported) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, mkdir(from_dir_path.c_str(),
|
||||
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
EXPECT_TRUE(utils::file::is_directory(from_dir_path));
|
||||
if (is_rename_supported) {
|
||||
EXPECT_EQ(0, rename(from_dir_path.c_str(), to_dir_path.c_str()));
|
||||
EXPECT_FALSE(utils::file::is_directory(from_dir_path));
|
||||
EXPECT_TRUE(utils::file::is_directory(to_dir_path));
|
||||
} else {
|
||||
EXPECT_EQ(-1, rename(from_dir_path.c_str(), to_dir_path.c_str()));
|
||||
EXPECT_TRUE(utils::file::is_directory(from_dir_path));
|
||||
EXPECT_FALSE(utils::file::is_directory(to_dir_path));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_truncate(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, truncate(file_path.c_str(), 10u));
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
|
||||
EXPECT_EQ(std::uint64_t(10u), file_size);
|
||||
}
|
||||
|
||||
static void test_ftruncate(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto fd = open(file_path.c_str(), O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
|
||||
EXPECT_EQ(0, ftruncate(fd, 10u));
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
|
||||
EXPECT_EQ(std::uint64_t(10u), file_size);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
static void test_fallocate(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto file =
|
||||
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, file);
|
||||
EXPECT_EQ(0, fallocate(file, 0, 0, 16));
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
EXPECT_EQ(16U, file_size);
|
||||
|
||||
EXPECT_EQ(0, close(file));
|
||||
|
||||
file_size = 0U;
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
EXPECT_EQ(16U, file_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void test_file_getattr(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto fd =
|
||||
open(file_path.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
|
||||
EXPECT_EQ(0, close(fd));
|
||||
|
||||
struct stat64 unix_st {};
|
||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR | S_IRGRP),
|
||||
ACCESSPERMS & unix_st.st_mode);
|
||||
EXPECT_FALSE(S_ISDIR(unix_st.st_mode));
|
||||
EXPECT_TRUE(S_ISREG(unix_st.st_mode));
|
||||
}
|
||||
|
||||
static void test_directory_getattr(const std::string & /* api_path */,
|
||||
const std::string &directory_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
EXPECT_EQ(0, mkdir(directory_path.c_str(),
|
||||
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP));
|
||||
|
||||
struct stat64 unix_st {};
|
||||
EXPECT_EQ(0, stat64(directory_path.c_str(), &unix_st));
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
|
||||
S_IXGRP),
|
||||
ACCESSPERMS & unix_st.st_mode);
|
||||
EXPECT_TRUE(S_ISDIR(unix_st.st_mode));
|
||||
EXPECT_FALSE(S_ISREG(unix_st.st_mode));
|
||||
}
|
||||
|
||||
static void
|
||||
test_write_operations_fail_if_read_only(const std::string & /* api_path */,
|
||||
const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
auto fd =
|
||||
open(file_path.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
EXPECT_LE(1, fd);
|
||||
|
||||
std::string data = "TestData";
|
||||
EXPECT_EQ(-1, write(fd, data.data(), data.size()));
|
||||
|
||||
EXPECT_EQ(-1, ftruncate(fd, 9u));
|
||||
|
||||
#ifndef __APPLE__
|
||||
EXPECT_EQ(-1, fallocate(fd, 0, 0, 16));
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(0, close(fd));
|
||||
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
std::uint64_t file_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(file_path, file_size));
|
||||
EXPECT_EQ(std::size_t(0u), file_size);
|
||||
|
||||
// filesystem_item fsi{};
|
||||
// EXPECT_EQ(api_error::success,
|
||||
// provider.get_filesystem_item(api_path, false, fsi));
|
||||
// EXPECT_TRUE(utils::file::get_file_size(fsi.source_path, file_size));
|
||||
// EXPECT_EQ(std::size_t(0u), file_size);
|
||||
}
|
||||
|
||||
#if !__APPLE__ && HAS_SETXATTR
|
||||
static void test_xattr_invalid_parameters(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(-1, setxattr(nullptr, "user.test_attr", attr.data(), attr.size(),
|
||||
XATTR_CREATE));
|
||||
EXPECT_EQ(errno, EFAULT);
|
||||
EXPECT_EQ(-1, setxattr(file_path.c_str(), nullptr, attr.data(), attr.size(),
|
||||
XATTR_CREATE));
|
||||
EXPECT_EQ(errno, EFAULT);
|
||||
EXPECT_EQ(-1, setxattr(file_path.c_str(), "user.test_attr", nullptr,
|
||||
attr.size(), XATTR_CREATE));
|
||||
EXPECT_EQ(errno, EFAULT);
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", nullptr, 0,
|
||||
XATTR_CREATE));
|
||||
}
|
||||
|
||||
static void test_xattr_create_and_get(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(attr.size(),
|
||||
static_cast<std::size_t>(getxattr(
|
||||
file_path.c_str(), "user.test_attr", val.data(), val.size())));
|
||||
EXPECT_STREQ(attr.c_str(), val.c_str());
|
||||
}
|
||||
|
||||
static void test_xattr_listxattr(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr2", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(attr.size(),
|
||||
static_cast<std::size_t>(getxattr(
|
||||
file_path.c_str(), "user.test_attr", val.data(), val.size())));
|
||||
EXPECT_STREQ(attr.c_str(), val.c_str());
|
||||
|
||||
std::string data;
|
||||
auto size = listxattr(file_path.c_str(), data.data(), 0U);
|
||||
EXPECT_EQ(31, size);
|
||||
|
||||
data.resize(static_cast<std::size_t>(size));
|
||||
EXPECT_EQ(size, listxattr(file_path.c_str(), data.data(),
|
||||
static_cast<std::size_t>(size)));
|
||||
|
||||
auto *ptr = data.data();
|
||||
EXPECT_STREQ("user.test_attr", ptr);
|
||||
|
||||
ptr += strlen(ptr) + 1;
|
||||
EXPECT_STREQ("user.test_attr2", ptr);
|
||||
}
|
||||
|
||||
static void test_xattr_replace(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
|
||||
attr = "cow";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_REPLACE));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(attr.size(),
|
||||
static_cast<std::size_t>(getxattr(
|
||||
file_path.c_str(), "user.test_attr", val.data(), val.size())));
|
||||
EXPECT_STREQ(attr.c_str(), val.c_str());
|
||||
}
|
||||
|
||||
static void test_xattr_default_create(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), 0));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(attr.size(),
|
||||
static_cast<std::size_t>(getxattr(
|
||||
file_path.c_str(), "user.test_attr", val.data(), val.size())));
|
||||
EXPECT_STREQ(attr.c_str(), val.c_str());
|
||||
}
|
||||
|
||||
static void test_xattr_default_replace(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), 0));
|
||||
|
||||
attr = "cow";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), 0));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(attr.size(),
|
||||
static_cast<std::size_t>(getxattr(
|
||||
file_path.c_str(), "user.test_attr", val.data(), val.size())));
|
||||
EXPECT_STREQ(attr.c_str(), val.c_str());
|
||||
}
|
||||
|
||||
static void test_xattr_create_fails_if_exists(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), 0));
|
||||
EXPECT_EQ(-1, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
static void
|
||||
test_xattr_create_fails_if_not_exists(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(-1, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_REPLACE));
|
||||
EXPECT_EQ(ENODATA, errno);
|
||||
}
|
||||
|
||||
static void test_xattr_removexattr(const std::string &file_path) {
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
std::string attr = "moose";
|
||||
EXPECT_EQ(0, setxattr(file_path.c_str(), "user.test_attr", attr.data(),
|
||||
attr.size(), XATTR_CREATE));
|
||||
|
||||
EXPECT_EQ(0, removexattr(file_path.c_str(), "user.test_attr"));
|
||||
|
||||
std::string val;
|
||||
val.resize(attr.size());
|
||||
EXPECT_EQ(-1, getxattr(file_path.c_str(), "user.test_attr", val.data(),
|
||||
val.size()));
|
||||
EXPECT_EQ(ENODATA, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(fuse_drive, all_tests) {
|
||||
auto current_directory = std::filesystem::current_path();
|
||||
|
||||
for (std::size_t idx = 0U; idx < 2U; idx++) {
|
||||
std::filesystem::current_path(current_directory);
|
||||
|
||||
const auto test_directory =
|
||||
utils::path::absolute("./fuse_drive" + std::to_string(idx));
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively(test_directory));
|
||||
|
||||
const auto mount_location = utils::path::absolute(
|
||||
utils::path::combine(test_directory, {"mount", std::to_string(idx)}));
|
||||
|
||||
EXPECT_TRUE(utils::file::create_full_directory_path(mount_location));
|
||||
{
|
||||
std::unique_ptr<app_config> config_ptr{};
|
||||
std::unique_ptr<curl_comm> comm_ptr{};
|
||||
std::unique_ptr<i_provider> provider_ptr{};
|
||||
|
||||
const auto cfg_directory = utils::path::absolute(
|
||||
utils::path::combine(test_directory, {"cfg", std::to_string(idx)}));
|
||||
EXPECT_TRUE(utils::file::create_full_directory_path(cfg_directory));
|
||||
|
||||
std::vector<std::string> drive_args{};
|
||||
|
||||
switch (idx) {
|
||||
case 0U: {
|
||||
#ifdef REPERTORY_ENABLE_S3
|
||||
config_ptr =
|
||||
std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
||||
{
|
||||
app_config src_cfg(provider_type::s3,
|
||||
utils::path::combine(get_test_dir(), {"storj"}));
|
||||
config_ptr->set_enable_drive_events(true);
|
||||
config_ptr->set_event_level(event_level::verbose);
|
||||
config_ptr->set_s3_config(src_cfg.get_s3_config());
|
||||
}
|
||||
|
||||
comm_ptr = std::make_unique<curl_comm>(config_ptr->get_s3_config());
|
||||
provider_ptr = std::make_unique<s3_provider>(*config_ptr, *comm_ptr);
|
||||
drive_args = std::vector<std::string>({"-s3", "-na", "storj"});
|
||||
#else
|
||||
continue;
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case 1U: {
|
||||
config_ptr =
|
||||
std::make_unique<app_config>(provider_type::sia, cfg_directory);
|
||||
{
|
||||
app_config src_cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
config_ptr->set_enable_drive_events(true);
|
||||
config_ptr->set_event_level(event_level::debug);
|
||||
config_ptr->set_host_config(src_cfg.get_host_config());
|
||||
}
|
||||
|
||||
comm_ptr = std::make_unique<curl_comm>(config_ptr->get_host_config());
|
||||
provider_ptr = std::make_unique<sia_provider>(*config_ptr, *comm_ptr);
|
||||
} break;
|
||||
|
||||
default:
|
||||
std::cerr << "provider at index " << idx << " is not implemented"
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::thread th([&] {
|
||||
std::this_thread::sleep_for(5s);
|
||||
EXPECT_EQ(0, system(("mount|grep \"" + mount_location + "\"").c_str()));
|
||||
|
||||
auto file_path = create_file_and_test(mount_location, "chmod_test");
|
||||
test_chmod(utils::path::create_api_path("chmod_test"), file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location, "chown_test");
|
||||
test_chown(utils::path::create_api_path("chown_test"), file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = utils::path::combine(mount_location, {"mkdir_test"});
|
||||
test_mkdir(utils::path::create_api_path("mkdir_test"), file_path);
|
||||
rmdir_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location, "write_read_test");
|
||||
test_write_and_read(utils::path::create_api_path("write_read_test"),
|
||||
file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "from_rename_file_test");
|
||||
auto to_file_path = utils::path::absolute(
|
||||
utils::path::combine(mount_location, {"to_rename_file_test"}));
|
||||
test_rename_file(file_path, to_file_path,
|
||||
provider_ptr->is_rename_supported());
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(file_path));
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(to_file_path));
|
||||
|
||||
file_path = utils::path::absolute(
|
||||
utils::path::combine(mount_location, {"from_rename_dir_test"}));
|
||||
to_file_path = utils::path::absolute(
|
||||
utils::path::combine(mount_location, {"to_rename_dir_test"}));
|
||||
test_rename_directory(file_path, to_file_path,
|
||||
provider_ptr->is_rename_supported());
|
||||
EXPECT_TRUE(utils::file::retry_delete_directory(file_path.c_str()));
|
||||
EXPECT_TRUE(utils::file::retry_delete_directory(to_file_path.c_str()));
|
||||
|
||||
file_path = create_file_and_test(mount_location, "truncate_file_test");
|
||||
test_truncate(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location, "ftruncate_file_test");
|
||||
test_ftruncate(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
#ifndef __APPLE__
|
||||
file_path = create_file_and_test(mount_location, "fallocate_file_test");
|
||||
test_fallocate(utils::path::create_api_path("fallocate_file_test"),
|
||||
file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
#endif
|
||||
|
||||
file_path = create_file_and_test(mount_location, "write_fails_ro_test");
|
||||
test_write_operations_fail_if_read_only(
|
||||
utils::path::create_api_path("write_fails_ro_test"), file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location, "getattr.txt");
|
||||
test_file_getattr(utils::path::create_api_path("getattr.txt"),
|
||||
file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = utils::path::combine(mount_location, {"getattr_dir"});
|
||||
test_directory_getattr(utils::path::create_api_path("getattr_dir"),
|
||||
file_path);
|
||||
rmdir_and_test(file_path);
|
||||
|
||||
#if !__APPLE__ && HAS_SETXATTR
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_invalid_names_test");
|
||||
test_xattr_invalid_parameters(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_create_get_test");
|
||||
test_xattr_create_and_get(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_listxattr_test");
|
||||
test_xattr_listxattr(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location, "xattr_replace_test");
|
||||
test_xattr_replace(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_default_create_test");
|
||||
test_xattr_default_create(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_default_replace_test");
|
||||
test_xattr_default_replace(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location,
|
||||
"xattr_create_fails_exists_test");
|
||||
test_xattr_create_fails_if_exists(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path = create_file_and_test(mount_location,
|
||||
"xattr_create_fails_not_exists_test");
|
||||
test_xattr_create_fails_if_not_exists(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
|
||||
file_path =
|
||||
create_file_and_test(mount_location, "xattr_removexattr_test");
|
||||
test_xattr_removexattr(file_path);
|
||||
unlink_file_and_test(file_path);
|
||||
#endif
|
||||
|
||||
execute_unmount(mount_location);
|
||||
});
|
||||
|
||||
drive_args.push_back(mount_location);
|
||||
execute_mount(config_ptr->get_data_directory(), drive_args, th);
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::current_path(current_directory);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif
|
104
repertory2/repertory2_test/src/lock_data_test.cpp
Normal file
104
repertory2/repertory2_test/src/lock_data_test.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(lock_data, lock_and_unlock) {
|
||||
{
|
||||
lock_data l(provider_type::sia, "1");
|
||||
EXPECT_EQ(lock_result::success, l.grab_lock());
|
||||
|
||||
std::thread([]() {
|
||||
lock_data l2(provider_type::sia, "1");
|
||||
EXPECT_EQ(lock_result::locked, l2.grab_lock(10));
|
||||
}).join();
|
||||
}
|
||||
|
||||
std::thread([]() {
|
||||
lock_data l(provider_type::sia, "1");
|
||||
EXPECT_EQ(lock_result::success, l.grab_lock(10));
|
||||
}).join();
|
||||
|
||||
#ifdef _WIN32
|
||||
lock_data l2(provider_type::remote, "1");
|
||||
EXPECT_EQ(lock_result::success, l2.grab_lock());
|
||||
|
||||
lock_data l3(provider_type::remote, "2");
|
||||
EXPECT_EQ(lock_result::success, l3.grab_lock());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST(lock_data, set_and_unset_mount_state) {
|
||||
lock_data l(provider_type::sia, "1");
|
||||
EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
|
||||
|
||||
lock_data l2(provider_type::remote, "1");
|
||||
EXPECT_TRUE(l2.set_mount_state(true, "D:", 97));
|
||||
|
||||
lock_data l3(provider_type::remote, "2");
|
||||
EXPECT_TRUE(l3.set_mount_state(true, "E:", 96));
|
||||
|
||||
json mount_state;
|
||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||
|
||||
EXPECT_STREQ(R"({"Active":true,"Location":"C:","PID":99})",
|
||||
mount_state["Sia1"].dump().c_str());
|
||||
EXPECT_STREQ(R"({"Active":true,"Location":"D:","PID":97})",
|
||||
mount_state["Remote1"].dump().c_str());
|
||||
EXPECT_STREQ(R"({"Active":true,"Location":"E:","PID":96})",
|
||||
mount_state["Remote2"].dump().c_str());
|
||||
|
||||
EXPECT_TRUE(l.set_mount_state(false, "C:", 99));
|
||||
EXPECT_TRUE(l2.set_mount_state(false, "D:", 98));
|
||||
EXPECT_TRUE(l3.set_mount_state(false, "E:", 97));
|
||||
|
||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||
mount_state["Sia1"].dump().c_str());
|
||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||
mount_state["Remote1"].dump().c_str());
|
||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||
mount_state["Remote2"].dump().c_str());
|
||||
}
|
||||
#else
|
||||
TEST(lock_data, set_and_unset_mount_state) {
|
||||
lock_data l(provider_type::sia, "1");
|
||||
EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
|
||||
|
||||
json mount_state;
|
||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||
|
||||
EXPECT_STREQ(R"({"Active":true,"Location":"/mnt/1","PID":99})",
|
||||
mount_state["Sia1"].dump().c_str());
|
||||
|
||||
EXPECT_TRUE(l.set_mount_state(false, "/mnt/1", 99));
|
||||
|
||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||
|
||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||
mount_state["Sia1"].dump().c_str());
|
||||
}
|
||||
#endif
|
||||
} // namespace repertory
|
41
repertory2/repertory2_test/src/packet_test.cpp
Normal file
41
repertory2/repertory2_test/src/packet_test.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "comm/packet/packet.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(packet, encrypt_and_decrypt) {
|
||||
packet test_packet;
|
||||
test_packet.encode("test");
|
||||
test_packet.encrypt("moose");
|
||||
|
||||
std::uint32_t size{};
|
||||
EXPECT_EQ(0, test_packet.decode(size));
|
||||
EXPECT_EQ(0, test_packet.decrypt("moose"));
|
||||
|
||||
std::string data;
|
||||
EXPECT_EQ(0, test_packet.decode(data));
|
||||
|
||||
EXPECT_STREQ("test", data.c_str());
|
||||
}
|
||||
} // namespace repertory
|
133
repertory2/repertory2_test/src/path_utils_test.cpp
Normal file
133
repertory2/repertory2_test/src/path_utils_test.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "utils/path_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(path_utils, combine) {
|
||||
auto s = utils::path::combine(R"(\test\path)", {});
|
||||
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\test\path)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/test/path", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::combine(R"(\test)", {R"(\path)"});
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\test\path)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/test/path", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::combine(R"(\test)", {R"(\path)", R"(\again\)"});
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\test\path\again)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/test/path/again", s.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(path_utils, create_api_path) {
|
||||
auto s = utils::path::create_api_path("");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path(R"(\)");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path("/");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path(".");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path(R"(\\)");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path("//");
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path("/cow///moose/////dog/chicken");
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path("\\cow\\\\\\moose\\\\\\\\dog\\chicken/");
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
|
||||
s = utils::path::create_api_path("/cow\\\\/moose\\\\/\\dog\\chicken\\");
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
}
|
||||
|
||||
TEST(path_utils, finalize) {
|
||||
auto s = utils::path::finalize("");
|
||||
EXPECT_STREQ("", s.c_str());
|
||||
|
||||
s = utils::path::finalize(R"(\)");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize("/");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize(R"(\\)");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize("//");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize("/cow///moose/////dog/chicken");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\cow\moose\dog\chicken)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize("\\cow\\\\\\moose\\\\\\\\dog\\chicken/");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\cow\moose\dog\chicken)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
#endif
|
||||
|
||||
s = utils::path::finalize("/cow\\\\/moose\\\\/\\dog\\chicken\\");
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(R"(\cow\moose\dog\chicken)", s.c_str());
|
||||
#else
|
||||
EXPECT_STREQ("/cow/moose/dog/chicken", s.c_str());
|
||||
#endif
|
||||
}
|
||||
} // namespace repertory
|
748
repertory2/repertory2_test/src/providers_test.cpp
Normal file
748
repertory2/repertory2_test/src/providers_test.cpp
Normal file
@@ -0,0 +1,748 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/encrypt/encrypt_provider.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
#include "providers/s3/s3_provider.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
using gid_t = std::uint32_t;
|
||||
using uid_t = std::uint32_t;
|
||||
static constexpr auto getgid() -> gid_t { return 0U; }
|
||||
static constexpr auto getuid() -> uid_t { return 0U; }
|
||||
#endif
|
||||
|
||||
const auto check_forced_dirs = [](const repertory::directory_item_list &list) {
|
||||
static auto forced_dirs = std::array<std::string, 2>{".", ".."};
|
||||
for (std::size_t i = 0U; i < forced_dirs.size(); ++i) {
|
||||
const auto &item = list.at(i);
|
||||
EXPECT_TRUE(item.directory);
|
||||
EXPECT_STREQ(forced_dirs.at(i).c_str(), item.api_path.c_str());
|
||||
EXPECT_STREQ("", item.api_parent.c_str());
|
||||
EXPECT_EQ(std::size_t(0U), item.size);
|
||||
}
|
||||
};
|
||||
|
||||
const auto create_directory = [](repertory::i_provider &provider,
|
||||
const std::string &api_path) {
|
||||
auto date = repertory::utils::get_file_time_now();
|
||||
auto meta = repertory::create_meta_attributes(
|
||||
date, 1U, date + 1U, date + 2U, true, getgid(), "", 0700, date + 3U, 2U,
|
||||
3U, 0U, api_path + "_src", getuid(), date + 4U);
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
provider.create_directory(api_path, meta));
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
provider.is_directory(api_path, exists));
|
||||
EXPECT_TRUE(exists);
|
||||
|
||||
repertory::api_meta_map meta2{};
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
provider.get_item_meta(api_path, meta2));
|
||||
|
||||
EXPECT_EQ(date, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_ACCESSED]));
|
||||
EXPECT_EQ(1U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_ATTRIBUTES]));
|
||||
EXPECT_EQ(date + 1U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_CHANGED]));
|
||||
EXPECT_EQ(date + 2U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_CREATION]));
|
||||
EXPECT_TRUE(
|
||||
repertory::utils::string::to_bool(meta2.at(repertory::META_DIRECTORY)));
|
||||
EXPECT_EQ(getgid(), static_cast<gid_t>(repertory::utils::string::to_uint32(
|
||||
meta2[repertory::META_GID])));
|
||||
EXPECT_EQ(std::uint32_t(0700),
|
||||
repertory::utils::string::to_uint32(meta2[repertory::META_MODE]));
|
||||
EXPECT_EQ(date + 3U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_MODIFIED]));
|
||||
EXPECT_EQ(2U,
|
||||
repertory::utils::string::to_uint64(meta2[repertory::META_BACKUP]));
|
||||
EXPECT_EQ(
|
||||
3U, repertory::utils::string::to_uint64(meta2[repertory::META_OSXFLAGS]));
|
||||
EXPECT_FALSE(
|
||||
repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
|
||||
EXPECT_EQ(std::uint64_t(0U),
|
||||
repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
|
||||
EXPECT_STREQ((api_path + "_src").c_str(),
|
||||
meta2[repertory::META_SOURCE].c_str());
|
||||
EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
|
||||
meta2[repertory::META_UID])));
|
||||
EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_WRITTEN]));
|
||||
};
|
||||
|
||||
const auto create_file = [](repertory::i_provider &provider,
|
||||
const std::string &api_path) {
|
||||
auto source_path = repertory::generate_test_file_name(".", "test");
|
||||
|
||||
auto date = repertory::utils::get_file_time_now();
|
||||
auto meta = repertory::create_meta_attributes(
|
||||
date, 1U, date + 1U, date + 2U, false, getgid(), "", 0700, date + 3U, 2U,
|
||||
3U, 0U, source_path, getuid(), date + 4U);
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
provider.create_file(api_path, meta));
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(repertory::api_error::success, provider.is_file(api_path, exists));
|
||||
EXPECT_TRUE(exists);
|
||||
|
||||
EXPECT_TRUE(repertory::utils::file::delete_file(source_path));
|
||||
|
||||
repertory::api_meta_map meta2{};
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
provider.get_item_meta(api_path, meta2));
|
||||
|
||||
EXPECT_EQ(date, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_ACCESSED]));
|
||||
EXPECT_EQ(1U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_ATTRIBUTES]));
|
||||
EXPECT_EQ(date + 1U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_CHANGED]));
|
||||
EXPECT_EQ(date + 2U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_CREATION]));
|
||||
EXPECT_FALSE(
|
||||
repertory::utils::string::to_bool(meta2.at(repertory::META_DIRECTORY)));
|
||||
EXPECT_EQ(getgid(), static_cast<gid_t>(repertory::utils::string::to_uint32(
|
||||
meta2[repertory::META_GID])));
|
||||
EXPECT_EQ(std::uint32_t(0700),
|
||||
repertory::utils::string::to_uint32(meta2[repertory::META_MODE]));
|
||||
EXPECT_EQ(date + 3U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_MODIFIED]));
|
||||
EXPECT_EQ(2U,
|
||||
repertory::utils::string::to_uint64(meta2[repertory::META_BACKUP]));
|
||||
EXPECT_EQ(
|
||||
3U, repertory::utils::string::to_uint64(meta2[repertory::META_OSXFLAGS]));
|
||||
EXPECT_FALSE(
|
||||
repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
|
||||
EXPECT_EQ(std::uint64_t(0U),
|
||||
repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
|
||||
EXPECT_STREQ(source_path.c_str(), meta2[repertory::META_SOURCE].c_str());
|
||||
EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
|
||||
meta2[repertory::META_UID])));
|
||||
EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
|
||||
meta2[repertory::META_WRITTEN]));
|
||||
};
|
||||
|
||||
const auto decrypt_parts = [](const repertory::app_config &cfg,
|
||||
std::string &path) {
|
||||
if (path != "/" && path != "." && path != "..") {
|
||||
auto parts = repertory::utils::string::split(path, '/', false);
|
||||
for (auto &part : parts) {
|
||||
if (part.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
repertory::utils::encryption::decrypt_file_name(
|
||||
cfg.get_encrypt_config().encryption_token, part));
|
||||
}
|
||||
path = repertory::utils::string::join(parts, '/');
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
static void can_create_and_remove_directory(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::not_implemented,
|
||||
provider.create_directory("/moose", meta));
|
||||
|
||||
EXPECT_EQ(api_error::not_implemented, provider.remove_directory("/moose"));
|
||||
return;
|
||||
}
|
||||
|
||||
create_directory(provider, "/pt01");
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/pt01"));
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(api_error::success, provider.is_directory("/pt01", exists));
|
||||
EXPECT_FALSE(exists);
|
||||
}
|
||||
|
||||
static void create_directory_fails_if_already_exists(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_directory(provider, "/pt01");
|
||||
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::directory_exists,
|
||||
provider.create_directory("/pt01", meta));
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/pt01"));
|
||||
}
|
||||
|
||||
static void
|
||||
create_directory_fails_if_file_already_exists(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_file(provider, "/pt01");
|
||||
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::item_exists, provider.create_directory("/pt01", meta));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/pt01"));
|
||||
}
|
||||
|
||||
static void create_directory_clone_source_meta(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
EXPECT_EQ(api_error::not_implemented,
|
||||
provider.create_directory_clone_source_meta("/moose", "/moose"));
|
||||
return;
|
||||
}
|
||||
create_directory(provider, "/clone");
|
||||
|
||||
api_meta_map meta_orig{};
|
||||
EXPECT_EQ(api_error::success, provider.get_item_meta("/clone", meta_orig));
|
||||
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.create_directory_clone_source_meta("/clone", "/clone2"));
|
||||
|
||||
api_meta_map meta_clone{};
|
||||
EXPECT_EQ(api_error::success, provider.get_item_meta("/clone2", meta_clone));
|
||||
|
||||
EXPECT_EQ(meta_orig.size(), meta_clone.size());
|
||||
for (const auto &item : meta_orig) {
|
||||
if (item.first == META_KEY) {
|
||||
if (item.second.empty() && meta_clone[item.first].empty()) {
|
||||
continue;
|
||||
}
|
||||
EXPECT_STRNE(item.second.c_str(), meta_clone[item.first].c_str());
|
||||
continue;
|
||||
}
|
||||
EXPECT_STREQ(item.second.c_str(), meta_clone[item.first].c_str());
|
||||
}
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/clone"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/clone2"));
|
||||
}
|
||||
|
||||
static void create_directory_clone_source_meta_fails_if_already_exists(
|
||||
i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
create_directory(provider, "/clone");
|
||||
create_directory(provider, "/clone2");
|
||||
|
||||
EXPECT_EQ(api_error::directory_exists,
|
||||
provider.create_directory_clone_source_meta("/clone", "/clone2"));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/clone"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/clone2"));
|
||||
}
|
||||
|
||||
static void create_directory_clone_source_meta_fails_if_directory_not_found(
|
||||
i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_EQ(api_error::directory_not_found,
|
||||
provider.create_directory_clone_source_meta("/clone", "/clone2"));
|
||||
}
|
||||
|
||||
static void create_directory_clone_source_meta_fails_if_file_already_exists(
|
||||
i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_directory(provider, "/clone");
|
||||
create_file(provider, "/clone2");
|
||||
|
||||
EXPECT_EQ(api_error::item_exists,
|
||||
provider.create_directory_clone_source_meta("/clone", "/clone2"));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/clone"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/clone2"));
|
||||
}
|
||||
|
||||
static void can_create_and_remove_file(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::not_implemented,
|
||||
provider.create_file("/moose.txt", meta));
|
||||
return;
|
||||
}
|
||||
|
||||
create_file(provider, "/pt01.txt");
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(api_error::success, provider.is_file("/pt01.txt", exists));
|
||||
EXPECT_TRUE(exists);
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.is_file("/pt01.txt", exists));
|
||||
EXPECT_FALSE(exists);
|
||||
}
|
||||
|
||||
static void create_file_fails_if_already_exists(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_file(provider, "/pt01.txt");
|
||||
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::item_exists, provider.create_file("/pt01.txt", meta));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||
}
|
||||
|
||||
static void
|
||||
create_file_fails_if_directory_already_exists(i_provider &provider) {
|
||||
if (provider.is_direct_only()) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_directory(provider, "/pt01");
|
||||
|
||||
api_meta_map meta{};
|
||||
EXPECT_EQ(api_error::directory_exists, provider.create_file("/pt01", meta));
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/pt01"));
|
||||
}
|
||||
|
||||
static void get_api_path_from_source(const app_config &cfg,
|
||||
i_provider &provider) {
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
std::string file_name{api_path.substr(1U)};
|
||||
decrypt_parts(cfg, file_name);
|
||||
EXPECT_STREQ("test.txt", file_name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
create_file(provider, "/pt01.txt");
|
||||
|
||||
filesystem_item fsi{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_filesystem_item("/pt01.txt", false, fsi));
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(fsi.source_path, api_path));
|
||||
|
||||
EXPECT_STREQ("/pt01.txt", api_path.c_str());
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||
}
|
||||
|
||||
static void
|
||||
get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
|
||||
i_provider &provider) {
|
||||
std::string source_path{};
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
source_path = utils::path::combine(cfg.get_encrypt_config().path,
|
||||
{"test_not_found.txt"});
|
||||
} else {
|
||||
source_path = utils::path::combine("./", {"test_not_found.txt"});
|
||||
}
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::item_not_found,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
EXPECT_TRUE(api_path.empty());
|
||||
}
|
||||
|
||||
static void get_directory_item_count(const app_config &cfg,
|
||||
i_provider &provider) {
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
|
||||
EXPECT_EQ(std::size_t(0U), provider.get_directory_item_count("/not_found"));
|
||||
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
EXPECT_EQ(std::size_t(1U), provider.get_directory_item_count(api_path));
|
||||
}
|
||||
}
|
||||
|
||||
static void get_directory_items(const app_config &cfg, i_provider &provider) {
|
||||
directory_item_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
||||
check_forced_dirs(list);
|
||||
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
EXPECT_EQ(std::size_t(4U), list.size());
|
||||
|
||||
directory_item_list list_decrypted{list.begin() + 2U, list.end()};
|
||||
for (auto &dir_item : list_decrypted) {
|
||||
decrypt_parts(cfg, dir_item.api_parent);
|
||||
decrypt_parts(cfg, dir_item.api_path);
|
||||
}
|
||||
|
||||
auto dir = std::find_if(list_decrypted.begin(), list_decrypted.end(),
|
||||
[](const directory_item &dir_item) -> bool {
|
||||
return dir_item.directory;
|
||||
});
|
||||
EXPECT_LT(dir, list_decrypted.end());
|
||||
EXPECT_STREQ("/sub10", dir->api_path.c_str());
|
||||
EXPECT_STREQ("/", dir->api_parent.c_str());
|
||||
EXPECT_EQ(std::size_t(0U), dir->size);
|
||||
|
||||
auto file = std::find_if(list_decrypted.begin(), list_decrypted.end(),
|
||||
[](const directory_item &dir_item) -> bool {
|
||||
return not dir_item.directory;
|
||||
});
|
||||
EXPECT_LT(file, list_decrypted.end());
|
||||
EXPECT_STREQ("/test.txt", file->api_path.c_str());
|
||||
EXPECT_STREQ("/", file->api_parent.c_str());
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(std::size_t(47U), file->size);
|
||||
#else
|
||||
EXPECT_EQ(std::size_t(46U), file->size);
|
||||
#endif
|
||||
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
list.clear();
|
||||
EXPECT_EQ(api_error::success, provider.get_directory_items(api_path, list));
|
||||
check_forced_dirs(list);
|
||||
EXPECT_EQ(std::size_t(3U), list.size());
|
||||
|
||||
directory_item_list list_decrypted2{list.begin() + 2U, list.end()};
|
||||
for (auto &dir_item : list_decrypted2) {
|
||||
decrypt_parts(cfg, dir_item.api_parent);
|
||||
decrypt_parts(cfg, dir_item.api_path);
|
||||
}
|
||||
|
||||
auto file2 = std::find_if(list_decrypted2.begin(), list_decrypted2.end(),
|
||||
[](const directory_item &dir_item) -> bool {
|
||||
return not dir_item.directory;
|
||||
});
|
||||
EXPECT_LT(file2, list_decrypted2.end());
|
||||
EXPECT_STREQ("/sub10/moose.txt", file2->api_path.c_str());
|
||||
EXPECT_STREQ("/sub10", file2->api_parent.c_str());
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(std::size_t(46U), file2->size);
|
||||
#else
|
||||
EXPECT_EQ(std::size_t(45U), file2->size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_directory_items_fails_if_directory_not_found(i_provider &provider) {
|
||||
directory_item_list list{};
|
||||
EXPECT_EQ(api_error::directory_not_found,
|
||||
provider.get_directory_items("/not_found", list));
|
||||
EXPECT_TRUE(list.empty());
|
||||
}
|
||||
|
||||
static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
|
||||
i_provider &provider) {
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
directory_item_list list{};
|
||||
EXPECT_EQ(api_error::item_exists,
|
||||
provider.get_directory_items(api_path, list));
|
||||
EXPECT_TRUE(list.empty());
|
||||
}
|
||||
}
|
||||
|
||||
static void get_file(const app_config &cfg, i_provider &provider) {
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file(api_path, file));
|
||||
decrypt_parts(cfg, file.api_path);
|
||||
decrypt_parts(cfg, file.api_parent);
|
||||
|
||||
EXPECT_STREQ("/test.txt", file.api_path.c_str());
|
||||
EXPECT_STREQ("/", file.api_parent.c_str());
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(std::size_t(47U), file.file_size);
|
||||
#else
|
||||
EXPECT_EQ(std::size_t(46U), file.file_size);
|
||||
#endif
|
||||
EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void get_file_fails_if_file_not_found(i_provider &provider) {
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::item_not_found, provider.get_file("/not_found", file));
|
||||
}
|
||||
|
||||
static void get_file_fails_if_item_is_directory(const app_config &cfg,
|
||||
i_provider &provider) {
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
const auto source_path =
|
||||
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
||||
|
||||
std::string api_path{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_api_path_from_source(source_path, api_path));
|
||||
|
||||
api_file file{};
|
||||
EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
|
||||
}
|
||||
}
|
||||
|
||||
static void get_file_list(const app_config &cfg, i_provider &provider) {
|
||||
api_file_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file_list(list));
|
||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||
EXPECT_EQ(std::size_t(2U), list.size());
|
||||
|
||||
std::vector<std::string> expected_parents{
|
||||
{"/"},
|
||||
{"/sub10"},
|
||||
};
|
||||
std::vector<std::string> expected_paths{
|
||||
{"/test.txt"},
|
||||
{"/sub10/moose.txt"},
|
||||
};
|
||||
|
||||
for (auto &file : list) {
|
||||
decrypt_parts(cfg, file.api_parent);
|
||||
decrypt_parts(cfg, file.api_path);
|
||||
utils::remove_element_from(expected_parents, file.api_parent);
|
||||
utils::remove_element_from(expected_paths, file.api_path);
|
||||
}
|
||||
EXPECT_TRUE(expected_parents.empty());
|
||||
EXPECT_TRUE(expected_paths.empty());
|
||||
}
|
||||
}
|
||||
|
||||
static void run_tests(const app_config &cfg, i_provider &provider) {
|
||||
get_file_list(cfg, provider);
|
||||
ASSERT_FALSE(::testing::Test::HasFailure());
|
||||
|
||||
can_create_and_remove_directory(provider);
|
||||
can_create_and_remove_file(provider);
|
||||
|
||||
create_directory_fails_if_already_exists(provider);
|
||||
create_directory_fails_if_file_already_exists(provider);
|
||||
|
||||
create_directory_clone_source_meta(provider);
|
||||
create_directory_clone_source_meta_fails_if_already_exists(provider);
|
||||
create_directory_clone_source_meta_fails_if_directory_not_found(provider);
|
||||
create_directory_clone_source_meta_fails_if_file_already_exists(provider);
|
||||
|
||||
create_file_fails_if_already_exists(provider);
|
||||
create_file_fails_if_directory_already_exists(provider);
|
||||
|
||||
get_api_path_from_source(cfg, provider);
|
||||
get_api_path_from_source_fails_if_file_not_found(cfg, provider);
|
||||
|
||||
// TODO: continue here
|
||||
get_directory_items(cfg, provider);
|
||||
get_directory_items_fails_if_directory_not_found(provider);
|
||||
get_directory_items_fails_if_item_is_file(cfg, provider);
|
||||
|
||||
get_directory_item_count(cfg, provider);
|
||||
|
||||
get_file(cfg, provider);
|
||||
get_file_fails_if_file_not_found(provider);
|
||||
get_file_fails_if_item_is_directory(cfg, provider);
|
||||
|
||||
/* get_file_list(provider);
|
||||
get_file_size(provider);
|
||||
get_filesystem_item(provider);
|
||||
get_filesystem_item_and_file(provider);
|
||||
get_filesystem_item_from_source_path(provider);
|
||||
get_item_meta(provider);
|
||||
get_item_meta2(provider);
|
||||
get_pinned_files(provider);
|
||||
get_total_drive_space(provider);
|
||||
get_total_item_count(provider);
|
||||
get_used_drive_space(provider);
|
||||
is_directory(provider);
|
||||
is_file(provider);
|
||||
is_file_writeable(provider);
|
||||
read_file_bytes(provider);
|
||||
remove_directory(provider);
|
||||
remove_file(provider);
|
||||
remove_item_meta(provider);
|
||||
rename_file(provider);
|
||||
set_item_meta(provider);
|
||||
set_item_meta2(provider);
|
||||
upload_file(provider); */
|
||||
}
|
||||
|
||||
TEST(providers, encrypt_provider) {
|
||||
const auto config_path = utils::path::absolute("./providers_test_encrypt");
|
||||
ASSERT_TRUE(utils::file::delete_directory_recursively(config_path));
|
||||
|
||||
console_consumer consumer{};
|
||||
event_system::instance().start();
|
||||
{
|
||||
app_config cfg(provider_type::encrypt, config_path);
|
||||
|
||||
const auto encrypt_path = utils::path::combine(
|
||||
std::filesystem::path(utils::path::absolute(__FILE__))
|
||||
.parent_path()
|
||||
.string(),
|
||||
{"encrypt"});
|
||||
|
||||
EXPECT_STREQ(
|
||||
encrypt_path.c_str(),
|
||||
cfg.set_value_by_name("EncryptConfig.Path", encrypt_path).c_str());
|
||||
EXPECT_STREQ(
|
||||
"test_token",
|
||||
cfg.set_value_by_name("EncryptConfig.EncryptionToken", "test_token")
|
||||
.c_str());
|
||||
|
||||
encrypt_provider provider{cfg};
|
||||
file_manager mgr(cfg, provider);
|
||||
mgr.start();
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&provider](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
&mgr));
|
||||
EXPECT_EQ(provider_type::encrypt, provider.get_provider_type());
|
||||
EXPECT_TRUE(provider.is_direct_only());
|
||||
EXPECT_TRUE(provider.is_online());
|
||||
EXPECT_FALSE(provider.is_rename_supported());
|
||||
|
||||
run_tests(cfg, provider);
|
||||
|
||||
provider.stop();
|
||||
mgr.stop();
|
||||
}
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
#if defined(REPERTORY_ENABLE_S3) && defined(REPERTORY_ENABLE_S3_TESTING)
|
||||
TEST(providers, s3_provider) {
|
||||
const auto config_path = utils::path::absolute("./providers_test_s3");
|
||||
ASSERT_TRUE(utils::file::delete_directory_recursively(config_path));
|
||||
|
||||
console_consumer consumer{};
|
||||
event_system::instance().start();
|
||||
{
|
||||
app_config cfg(provider_type::s3, config_path);
|
||||
{
|
||||
app_config src_cfg(provider_type::s3,
|
||||
utils::path::combine(get_test_dir(), {"storj"}));
|
||||
cfg.set_s3_config(src_cfg.get_s3_config());
|
||||
}
|
||||
|
||||
curl_comm comm{cfg.get_s3_config()};
|
||||
s3_provider provider{cfg, comm};
|
||||
file_manager mgr(cfg, provider);
|
||||
mgr.start();
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&provider](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
&mgr));
|
||||
EXPECT_EQ(provider_type::s3, provider.get_provider_type());
|
||||
EXPECT_FALSE(provider.is_direct_only());
|
||||
EXPECT_TRUE(provider.is_online());
|
||||
EXPECT_FALSE(provider.is_rename_supported());
|
||||
|
||||
run_tests(cfg, provider);
|
||||
|
||||
provider.stop();
|
||||
mgr.stop();
|
||||
}
|
||||
event_system::instance().stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(providers, sia_provider) {
|
||||
const auto config_path = utils::path::absolute("./providers_test_sia");
|
||||
ASSERT_TRUE(utils::file::delete_directory_recursively(config_path));
|
||||
|
||||
console_consumer consumer{};
|
||||
event_system::instance().start();
|
||||
{
|
||||
app_config cfg(provider_type::sia, config_path);
|
||||
{
|
||||
app_config src_cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
cfg.set_host_config(src_cfg.get_host_config());
|
||||
}
|
||||
|
||||
curl_comm comm{cfg.get_host_config()};
|
||||
sia_provider provider{cfg, comm};
|
||||
file_manager mgr(cfg, provider);
|
||||
mgr.start();
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&provider](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
&mgr));
|
||||
EXPECT_EQ(provider_type::sia, provider.get_provider_type());
|
||||
EXPECT_FALSE(provider.is_direct_only());
|
||||
EXPECT_TRUE(provider.is_online());
|
||||
EXPECT_TRUE(provider.is_rename_supported());
|
||||
|
||||
run_tests(cfg, provider);
|
||||
|
||||
provider.stop();
|
||||
mgr.stop();
|
||||
}
|
||||
event_system::instance().stop();
|
||||
}
|
||||
} // namespace repertory
|
1001
repertory2/repertory2_test/src/remote_fuse_test.cpp
Normal file
1001
repertory2/repertory2_test/src/remote_fuse_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
533
repertory2/repertory2_test/src/remote_winfsp_test.cpp
Normal file
533
repertory2/repertory2_test/src/remote_winfsp_test.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "drives/winfsp/i_winfsp_drive.hpp"
|
||||
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#ifdef _WIN32
|
||||
#include "drives/winfsp/remotewinfsp/remote_server.hpp"
|
||||
#include "mocks/mock_winfsp_drive.hpp"
|
||||
#else
|
||||
#include "drives/fuse/remotefuse/remote_server.hpp"
|
||||
#include "mocks/mock_fuse_drive.hpp"
|
||||
#endif
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
using namespace repertory;
|
||||
using namespace repertory::remote_winfsp;
|
||||
|
||||
namespace winfsp_test {
|
||||
static std::string mount_location_;
|
||||
|
||||
static void can_delete_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/candelete.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
native_file::native_file_ptr nf;
|
||||
EXPECT_EQ(api_error::success, native_file::create_or_open(test_file, nf));
|
||||
EXPECT_TRUE(nf);
|
||||
if (nf) {
|
||||
EXPECT_EQ(STATUS_INVALID_HANDLE,
|
||||
client.winfsp_can_delete(
|
||||
reinterpret_cast<PVOID>(nf->get_handle()), &api_path[0]));
|
||||
|
||||
nf->close();
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename t>
|
||||
static void create_and_close_test(remote_client &client, t &server) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/create.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
const auto ret = client.winfsp_create(
|
||||
&api_path[0], 0, GENERIC_READ | GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL, 0,
|
||||
&file_desc, &fi, normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(1u, client.get_open_file_count(utils::string::to_utf8(api_path)));
|
||||
EXPECT_EQ(1u, server.get_open_file_count(test_file));
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
EXPECT_EQ(0u, client.get_open_file_count(utils::string::to_utf8(api_path)));
|
||||
EXPECT_EQ(0u, server.get_open_file_count(test_file));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void cleanup_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/cleanup.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
BOOLEAN was_closed = 0u;
|
||||
EXPECT_EQ(STATUS_SUCCESS,
|
||||
client.winfsp_cleanup(file_desc, &api_path[0], 0, was_closed));
|
||||
EXPECT_FALSE(was_closed);
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void flush_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/flush.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_flush(file_desc, &fi));
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void get_file_info_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/getfileinfo.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_get_file_info(file_desc, &fi));
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void get_security_by_name_test(remote_client &client) {
|
||||
const auto test_file =
|
||||
utils::path::absolute("./win_remote/getsecuritybyname.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
UINT32 attributes = 0u;
|
||||
std::uint64_t security_descriptor_size = 1024;
|
||||
std::wstring str_descriptor;
|
||||
ret = client.winfsp_get_security_by_name(
|
||||
&api_path[0], &attributes, &security_descriptor_size, str_descriptor);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(static_cast<UINT32>(FILE_ATTRIBUTE_NORMAL), attributes);
|
||||
EXPECT_FALSE(str_descriptor.empty());
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void get_volume_info_test(remote_client &client) {
|
||||
UINT64 total_size = 0u;
|
||||
UINT64 free_size = 0u;
|
||||
std::string volume_label;
|
||||
EXPECT_EQ(STATUS_SUCCESS,
|
||||
client.winfsp_get_volume_info(total_size, free_size, volume_label));
|
||||
EXPECT_EQ(100u, free_size);
|
||||
EXPECT_EQ(200u, total_size);
|
||||
EXPECT_STREQ(volume_label.c_str(), "TestVolumeLabel");
|
||||
}
|
||||
|
||||
static void mounted_test(remote_client &client) {
|
||||
const auto location = utils::string::from_utf8(mount_location_);
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_mounted(location));
|
||||
}
|
||||
|
||||
static void open_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/open.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
PVOID file_desc2 = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
{
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(
|
||||
&api_path[0], 0, GENERIC_READ | GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL, 0,
|
||||
&file_desc, &fi, normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
}
|
||||
{
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
const auto ret =
|
||||
client.winfsp_open(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
&file_desc2, &fi, normalized_name);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
}
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc2));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void overwrite_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/overwrite.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
const UINT32 attributes = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE;
|
||||
const BOOLEAN replace_attributes = 0u;
|
||||
const UINT64 allocation_size = 0u;
|
||||
ret = client.winfsp_overwrite(file_desc, attributes, replace_attributes,
|
||||
allocation_size, &fi);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(0u, fi.FileSize);
|
||||
EXPECT_EQ(attributes, fi.FileAttributes);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void create_and_read_directory_test(remote_client &client) {
|
||||
const auto test_directory =
|
||||
utils::path::absolute("./win_remote/readdirectory");
|
||||
EXPECT_TRUE(utils::file::delete_directory(test_directory));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_directory).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(
|
||||
&api_path[0], FILE_DIRECTORY_FILE, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_DIRECTORY, 0, &file_desc, &fi, normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
EXPECT_TRUE(utils::file::is_directory(test_directory));
|
||||
|
||||
json list;
|
||||
ret = client.winfsp_read_directory(file_desc, nullptr, nullptr, list);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(2u, list.size());
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::delete_directory(test_directory));
|
||||
}
|
||||
|
||||
static void open_and_read_directory_test(remote_client &client) {
|
||||
const auto test_directory =
|
||||
utils::path::absolute("./win_remote/openreaddirectory");
|
||||
EXPECT_TRUE(utils::file::delete_directory(test_directory));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_directory).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(
|
||||
&api_path[0], FILE_DIRECTORY_FILE, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_DIRECTORY, 0, &file_desc, &fi, normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::is_directory(test_directory));
|
||||
|
||||
file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
ret = client.winfsp_open(&api_path[0], FILE_DIRECTORY_FILE,
|
||||
GENERIC_READ | GENERIC_WRITE, &file_desc, &fi,
|
||||
normalized_name);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
json item_list;
|
||||
ret = client.winfsp_read_directory(file_desc, nullptr, nullptr, item_list);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(2u, item_list.size());
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::delete_directory(test_directory));
|
||||
}
|
||||
|
||||
static void read_and_write_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/readwrite.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
data_buffer buffer;
|
||||
buffer.emplace_back('T');
|
||||
buffer.emplace_back('e');
|
||||
buffer.emplace_back('s');
|
||||
buffer.emplace_back('t');
|
||||
UINT32 bytes_transferred = 0u;
|
||||
ret = client.winfsp_write(file_desc, &buffer[0], 0,
|
||||
static_cast<UINT32>(buffer.size()), 0, 0,
|
||||
&bytes_transferred, &fi);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(buffer.size(), bytes_transferred);
|
||||
|
||||
data_buffer buffer2(buffer.size());
|
||||
UINT32 bytes_transferred2 = 0u;
|
||||
ret = client.winfsp_read(file_desc, &buffer2[0], 0,
|
||||
static_cast<UINT32>(buffer2.size()),
|
||||
&bytes_transferred2);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_EQ(bytes_transferred, bytes_transferred2);
|
||||
EXPECT_EQ(0, memcmp(&buffer[0], &buffer2[0], buffer.size()));
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void rename_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/rename.txt");
|
||||
const auto test_file2 = utils::path::absolute("./win_remote/rename2.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file2));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
auto api_path2 =
|
||||
utils::string::from_utf8(test_file2).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
ret = client.winfsp_rename(file_desc, &api_path[0], &api_path2[0], 0);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
EXPECT_TRUE(utils::file::is_file(test_file2));
|
||||
EXPECT_FALSE(utils::file::is_file(test_file));
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file2));
|
||||
}
|
||||
|
||||
static void set_basic_info_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/setbasicinfo.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
const auto attributes = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE;
|
||||
#ifdef _WIN32
|
||||
SYSTEMTIME st{};
|
||||
::GetSystemTime(&st);
|
||||
|
||||
LARGE_INTEGER ft{};
|
||||
::SystemTimeToFileTime(&st, reinterpret_cast<FILETIME *>(&ft));
|
||||
|
||||
const auto creation_time = ft.QuadPart;
|
||||
const auto last_access_time = ft.QuadPart + 1;
|
||||
const auto last_write_time = ft.QuadPart + 2;
|
||||
const auto change_time = last_write_time;
|
||||
#else
|
||||
const auto creation_time =
|
||||
utils::unix_time_to_windows_time(utils::get_time_now());
|
||||
const auto last_access_time = creation_time + 1;
|
||||
const auto last_write_time = creation_time + 2;
|
||||
const auto change_time = last_write_time;
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS,
|
||||
client.winfsp_set_basic_info(file_desc, attributes, creation_time,
|
||||
last_access_time, last_write_time,
|
||||
change_time, &fi));
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(attributes), fi.FileAttributes);
|
||||
EXPECT_EQ(creation_time, fi.CreationTime);
|
||||
EXPECT_EQ(last_access_time, fi.LastAccessTime);
|
||||
EXPECT_EQ(last_write_time, fi.LastWriteTime);
|
||||
EXPECT_EQ(change_time, fi.ChangeTime);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void set_file_size_test(remote_client &client) {
|
||||
const auto test_file = utils::path::absolute("./win_remote/setfilesize.txt");
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
auto api_path =
|
||||
utils::string::from_utf8(test_file).substr(mount_location_.size());
|
||||
|
||||
PVOID file_desc = reinterpret_cast<PVOID>(REPERTORY_INVALID_HANDLE);
|
||||
remote::file_info fi{};
|
||||
std::string normalized_name;
|
||||
BOOLEAN exists = 0u;
|
||||
auto ret = client.winfsp_create(&api_path[0], 0, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_ATTRIBUTE_NORMAL, 0, &file_desc, &fi,
|
||||
normalized_name, exists);
|
||||
EXPECT_EQ(STATUS_SUCCESS, ret);
|
||||
|
||||
const UINT64 new_file_size = 34u;
|
||||
const BOOLEAN set_allocation_size = 0u;
|
||||
EXPECT_EQ(STATUS_SUCCESS,
|
||||
client.winfsp_set_file_size(file_desc, new_file_size,
|
||||
set_allocation_size, &fi));
|
||||
|
||||
std::uint64_t file_size = 0u;
|
||||
EXPECT_TRUE(utils::file::get_file_size(test_file, file_size));
|
||||
EXPECT_EQ(34u, file_size);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(test_file));
|
||||
}
|
||||
|
||||
static void unmounted_test(remote_client &client) {
|
||||
const auto location = utils::string::from_utf8(mount_location_);
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_unmounted(location));
|
||||
}
|
||||
|
||||
TEST(remote_winfsp, all_tests) {
|
||||
std::uint16_t port = 0;
|
||||
const auto found_port = utils::get_next_available_port(20020u, port);
|
||||
EXPECT_TRUE(found_port);
|
||||
if (found_port) {
|
||||
console_consumer c;
|
||||
|
||||
app_config config(provider_type::remote, "./win_remote");
|
||||
config.set_remote_host_name_or_ip("localhost");
|
||||
config.set_remote_port(port);
|
||||
config.set_remote_token("testtoken");
|
||||
config.set_enable_drive_events(true);
|
||||
config.set_event_level(event_level::verbose);
|
||||
|
||||
event_system::instance().start();
|
||||
#ifdef _WIN32
|
||||
mount_location_ = std::string(__FILE__).substr(0, 2);
|
||||
mock_winfsp_drive drive(mount_location_);
|
||||
remote_server server(config, drive, mount_location_);
|
||||
#else
|
||||
mount_location_ = utils::path::absolute(".");
|
||||
mock_fuse_drive drive(mount_location_);
|
||||
remote_fuse::remote_server server(config, drive, mount_location_);
|
||||
#endif
|
||||
std::this_thread::sleep_for(2s);
|
||||
|
||||
std::thread([&]() {
|
||||
remote_client client(config);
|
||||
|
||||
can_delete_test(client);
|
||||
cleanup_test(client);
|
||||
create_and_close_test(client, server);
|
||||
create_and_read_directory_test(client);
|
||||
flush_test(client);
|
||||
get_file_info_test(client);
|
||||
get_security_by_name_test(client);
|
||||
get_volume_info_test(client);
|
||||
mounted_test(client);
|
||||
open_and_read_directory_test(client);
|
||||
open_test(client);
|
||||
overwrite_test(client);
|
||||
read_and_write_test(client);
|
||||
rename_test(client);
|
||||
set_basic_info_test(client);
|
||||
set_file_size_test(client);
|
||||
unmounted_test(client);
|
||||
}).join();
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
EXPECT_TRUE(utils::file::delete_directory_recursively("./win_remote"));
|
||||
}
|
||||
} // namespace winfsp_test
|
326
repertory2/repertory2_test/src/sia_provider_test.cpp
Normal file
326
repertory2/repertory2_test/src/sia_provider_test.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "app_config.hpp"
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "events/consumers/console_consumer.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "file_manager/file_manager.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
#include "types/startup_exception.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
/* TEST(sia_provider, can_construct_sia_provider) {
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider provider(cfg, comm);
|
||||
EXPECT_EQ(provider_type::sia, provider.get_provider_type());
|
||||
EXPECT_FALSE(provider.is_direct_only());
|
||||
EXPECT_FALSE(provider.is_rename_supported());
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_create_and_remove_directory) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
api_meta_map meta{};
|
||||
meta[META_ACCESSED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CHANGED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CREATION] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_MODIFIED] = std::to_string(utils::get_file_time_now());
|
||||
EXPECT_EQ(api_error::success, provider.create_directory("/moose2", meta));
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(api_error::success, provider.is_directory("/moose2", exists));
|
||||
EXPECT_TRUE(exists);
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.is_file("/moose2", exists));
|
||||
EXPECT_FALSE(exists);
|
||||
|
||||
EXPECT_FALSE(provider.is_file_writeable("/moose2"));
|
||||
EXPECT_EQ(api_error::directory_exists, provider.remove_file("/moose2"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/moose2"));
|
||||
|
||||
api_meta_map m{};
|
||||
EXPECT_EQ(api_error::item_not_found, provider.get_item_meta("/moose2", m));
|
||||
EXPECT_TRUE(m.empty());
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_create_and_remove_file) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
api_meta_map meta{};
|
||||
meta[META_ACCESSED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CHANGED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CREATION] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_MODIFIED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_SIZE] = "0";
|
||||
EXPECT_EQ(api_error::success, provider.create_file("/moose.txt", meta));
|
||||
|
||||
bool exists{};
|
||||
EXPECT_EQ(api_error::success, provider.is_file("/moose.txt", exists));
|
||||
EXPECT_TRUE(exists);
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.is_directory("/moose.txt", exists));
|
||||
EXPECT_FALSE(exists);
|
||||
|
||||
EXPECT_TRUE(provider.is_file_writeable("/moose.txt"));
|
||||
EXPECT_EQ(api_error::item_not_found, provider.remove_directory("/moose.txt"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/moose.txt"));
|
||||
|
||||
api_meta_map m{};
|
||||
EXPECT_EQ(api_error::item_not_found, provider.get_item_meta("/moose.txt", m));
|
||||
EXPECT_TRUE(m.empty());
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_get_file_list) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
api_file_list list{};
|
||||
EXPECT_EQ(api_error::success, provider.get_file_list(list));
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_get_and_set_item_meta) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
api_meta_map meta{};
|
||||
meta[META_ACCESSED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CHANGED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CREATION] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_MODIFIED] = std::to_string(utils::get_file_time_now());
|
||||
EXPECT_EQ(api_error::success, provider.create_directory("/moose2", meta));
|
||||
EXPECT_EQ(api_error::success, provider.create_file("/moose2.txt", meta));
|
||||
|
||||
{
|
||||
api_meta_map m{
|
||||
{"test_one", "one"},
|
||||
{"test_two", "two"},
|
||||
};
|
||||
EXPECT_EQ(api_error::success, provider.set_item_meta("/moose2", m));
|
||||
|
||||
api_meta_map m2{};
|
||||
EXPECT_EQ(api_error::success, provider.get_item_meta("/moose2", m2));
|
||||
EXPECT_EQ(meta.size() + m.size(), m2.size());
|
||||
|
||||
EXPECT_STREQ("one", m2["test_one"].c_str());
|
||||
EXPECT_STREQ("two", m2["test_two"].c_str());
|
||||
}
|
||||
|
||||
{
|
||||
api_meta_map m{
|
||||
{"test_one", "one1"},
|
||||
{"test_two", "two2"},
|
||||
};
|
||||
EXPECT_EQ(api_error::success, provider.set_item_meta("/moose2.txt", m));
|
||||
|
||||
api_meta_map m2{};
|
||||
EXPECT_EQ(api_error::success, provider.get_item_meta("/moose2.txt", m2));
|
||||
EXPECT_EQ(meta.size() + m.size(), m2.size());
|
||||
|
||||
EXPECT_STREQ("one1", m2["test_one"].c_str());
|
||||
EXPECT_STREQ("two2", m2["test_two"].c_str());
|
||||
}
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/moose2"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/moose2.txt"));
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_get_and_set_individual_item_meta) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
api_meta_map meta{};
|
||||
meta[META_ACCESSED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CHANGED] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_CREATION] = std::to_string(utils::get_file_time_now());
|
||||
meta[META_MODIFIED] = std::to_string(utils::get_file_time_now());
|
||||
EXPECT_EQ(api_error::success, provider.create_directory("/moose2", meta));
|
||||
EXPECT_EQ(api_error::success, provider.create_file("/moose2.txt", meta));
|
||||
|
||||
{
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.set_item_meta("/moose2", "test_meta", "cow2"));
|
||||
std::string value{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_item_meta("/moose2", "test_meta", value));
|
||||
EXPECT_STREQ("cow2", value.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.set_item_meta("/moose2.txt", "test_meta", "cow"));
|
||||
std::string value{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.get_item_meta("/moose2.txt", "test_meta", value));
|
||||
EXPECT_STREQ("cow", value.c_str());
|
||||
}
|
||||
|
||||
EXPECT_EQ(api_error::success, provider.remove_directory("/moose2"));
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/moose2.txt"));
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_read_file_bytes) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
data_buffer data{};
|
||||
stop_type stop_requested = false;
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.read_file_bytes("/renterd_linux_amd64.zip", 10U, 0U, data,
|
||||
stop_requested));
|
||||
EXPECT_EQ(10U, data.size());
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
}
|
||||
|
||||
TEST(sia_provider, can_upload_file) {
|
||||
console_consumer cc{};
|
||||
event_system::instance().start();
|
||||
|
||||
app_config cfg(provider_type::sia,
|
||||
utils::path::combine(get_test_dir(), {"sia"}));
|
||||
curl_comm comm(cfg.get_host_config());
|
||||
sia_provider sia(cfg, comm);
|
||||
i_provider &provider = sia;
|
||||
|
||||
EXPECT_TRUE(provider.start(
|
||||
[&](bool directory, api_file &file) -> api_error {
|
||||
return provider_meta_handler(provider, directory, file);
|
||||
},
|
||||
nullptr));
|
||||
|
||||
stop_type stop_requested = false;
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.upload_file("/sia_provider_test.cpp", __FILE__, "",
|
||||
stop_requested));
|
||||
api_meta_map meta = {{"test", "test"}};
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider.set_item_meta("/sia_provider_test.cpp", meta));
|
||||
EXPECT_EQ(api_error::success, provider.remove_file("/sia_provider_test.cpp"));
|
||||
|
||||
provider.stop();
|
||||
|
||||
event_system::instance().stop();
|
||||
} */
|
||||
} // namespace repertory
|
48
repertory2/repertory2_test/src/string_utils_test.cpp
Normal file
48
repertory2/repertory2_test/src/string_utils_test.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(string_utils, is_numeric) {
|
||||
EXPECT_TRUE(utils::string::is_numeric("100"));
|
||||
EXPECT_TRUE(utils::string::is_numeric("+100"));
|
||||
EXPECT_TRUE(utils::string::is_numeric("-100"));
|
||||
|
||||
EXPECT_TRUE(utils::string::is_numeric("100.00"));
|
||||
EXPECT_TRUE(utils::string::is_numeric("+100.00"));
|
||||
EXPECT_TRUE(utils::string::is_numeric("-100.00"));
|
||||
|
||||
EXPECT_FALSE(utils::string::is_numeric("1.00.00"));
|
||||
EXPECT_FALSE(utils::string::is_numeric("+1.00.00"));
|
||||
EXPECT_FALSE(utils::string::is_numeric("-1.00.00"));
|
||||
|
||||
EXPECT_FALSE(utils::string::is_numeric("a1"));
|
||||
EXPECT_FALSE(utils::string::is_numeric("1a"));
|
||||
|
||||
EXPECT_FALSE(utils::string::is_numeric("+"));
|
||||
EXPECT_FALSE(utils::string::is_numeric("-"));
|
||||
|
||||
EXPECT_FALSE(utils::string::is_numeric(""));
|
||||
}
|
||||
} // namespace repertory
|
76
repertory2/repertory2_test/src/test_common.cpp
Normal file
76
repertory2/repertory2_test/src/test_common.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
std::vector<std::string> generated_files;
|
||||
|
||||
void delete_generated_files() {
|
||||
for (const auto &file : generated_files) {
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(file));
|
||||
}
|
||||
}
|
||||
|
||||
auto create_random_file(std::string path, std::size_t size) -> native_file_ptr {
|
||||
native_file_ptr file;
|
||||
if (native_file::create_or_open(path, file) == api_error::success) {
|
||||
generated_files.emplace_back(utils::path::absolute(path));
|
||||
|
||||
EXPECT_TRUE(file->truncate(0U));
|
||||
|
||||
data_buffer buf(size);
|
||||
randombytes_buf(buf.data(), buf.size());
|
||||
|
||||
std::size_t bytes_written{};
|
||||
EXPECT_TRUE(file->write_bytes(buf.data(), buf.size(), 0U, bytes_written));
|
||||
file->flush();
|
||||
|
||||
std::uint64_t current_size{};
|
||||
EXPECT_TRUE(utils::file::get_file_size(path, current_size));
|
||||
EXPECT_EQ(size, current_size);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
auto generate_test_file_name(const std::string &directory,
|
||||
const std::string &file_name_no_extension)
|
||||
-> std::string {
|
||||
static std::atomic<std::uint32_t> idx{0U};
|
||||
auto path = utils::path::absolute(utils::path::combine(
|
||||
directory, {file_name_no_extension + std::to_string(idx++) + ".dat"}));
|
||||
generated_files.emplace_back(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
auto get_test_dir() -> std::string {
|
||||
auto dir = utils::get_environment_variable("REPERTORY_TEST_DIR");
|
||||
if (not dir.empty()) {
|
||||
return utils::path::absolute(dir);
|
||||
}
|
||||
return utils::path::absolute(utils::path::combine("..", {".."}));
|
||||
}
|
||||
} // namespace repertory
|
77
repertory2/repertory2_test/src/utils_test.cpp
Normal file
77
repertory2/repertory2_test/src/utils_test.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path_utils.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
#ifdef _WIN32
|
||||
TEST(utils, convert_api_date) {
|
||||
LARGE_INTEGER li{};
|
||||
li.QuadPart = utils::convert_api_date("2009-10-12T17:50:30.111Z");
|
||||
|
||||
SYSTEMTIME st{};
|
||||
FileTimeToSystemTime(reinterpret_cast<FILETIME *>(&li), &st);
|
||||
|
||||
SYSTEMTIME lt{};
|
||||
SystemTimeToTzSpecificLocalTime(nullptr, &st, <);
|
||||
|
||||
EXPECT_EQ(2009, lt.wYear);
|
||||
EXPECT_EQ(10, lt.wMonth);
|
||||
EXPECT_EQ(12, lt.wDay);
|
||||
|
||||
EXPECT_EQ(17, lt.wHour);
|
||||
EXPECT_EQ(50, lt.wMinute);
|
||||
EXPECT_EQ(20, lt.wSecond);
|
||||
EXPECT_EQ(111, lt.wMilliseconds);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(utils, create_uuid_string) {
|
||||
const auto uuid1 = utils::create_uuid_string();
|
||||
const auto uuid2 = utils::create_uuid_string();
|
||||
ASSERT_EQ(36u, uuid1.size());
|
||||
ASSERT_EQ(36u, uuid2.size());
|
||||
ASSERT_STRNE(&uuid1[0], &uuid2[0]);
|
||||
}
|
||||
|
||||
TEST(utils, generate_sha256) {
|
||||
const auto res = utils::file::generate_sha256(__FILE__);
|
||||
std::cout << res << std::endl;
|
||||
}
|
||||
|
||||
TEST(utils, string_to_bool) {
|
||||
EXPECT_TRUE(utils::string::to_bool("1"));
|
||||
EXPECT_TRUE(utils::string::to_bool("-1"));
|
||||
EXPECT_TRUE(utils::string::to_bool("0.1"));
|
||||
EXPECT_TRUE(utils::string::to_bool("-0.1"));
|
||||
EXPECT_TRUE(utils::string::to_bool("00000.1000000"));
|
||||
EXPECT_TRUE(utils::string::to_bool("true"));
|
||||
|
||||
EXPECT_FALSE(utils::string::to_bool("false"));
|
||||
EXPECT_FALSE(utils::string::to_bool("0"));
|
||||
EXPECT_FALSE(utils::string::to_bool("00000.00000"));
|
||||
}
|
||||
} // namespace repertory
|
57
repertory2/repertory2_test/src/version_test.cpp
Normal file
57
repertory2/repertory2_test/src/version_test.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(version, equal) {
|
||||
EXPECT_EQ(0, utils::compare_version_strings("1.0", "1.0"));
|
||||
EXPECT_EQ(0, utils::compare_version_strings("1.0.0", "1.0"));
|
||||
EXPECT_EQ(0, utils::compare_version_strings("1.0.0.0", "1.0"));
|
||||
EXPECT_EQ(0, utils::compare_version_strings("1.0.0.0", "1.0.0"));
|
||||
}
|
||||
|
||||
TEST(version, greater) {
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1", "1.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1", "1.0.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1", "1.0.0.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1.0", "1.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1.0", "1.0.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1.0", "1.0.0.0"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0", "0.9.9"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1", "0.9.9"));
|
||||
EXPECT_EQ(1, utils::compare_version_strings("1.0.1.0", "0.9.9"));
|
||||
}
|
||||
|
||||
TEST(version, less) {
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("0.9.9", "1.0"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("0.9.9", "1.0.1"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("0.9.9", "1.0.1.0"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0", "1.0.1"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0", "1.0.1.0"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0.0", "1.0.1"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0.0", "1.0.1.0"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0.0.0", "1.0.1"));
|
||||
EXPECT_EQ(-1, utils::compare_version_strings("1.0.0.0", "1.0.1.0"));
|
||||
}
|
||||
} // namespace repertory
|
385
repertory2/repertory2_test/src/winfsp_test.cpp
Normal file
385
repertory2/repertory2_test/src/winfsp_test.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
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 _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, normal, false, std::string, test_name, TN, E_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::is_directory(mount_point);
|
||||
for (auto i = 0; mounted && (i < 50); i++) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
mounted = utils::file::is_directory(mount_point);
|
||||
}
|
||||
EXPECT_FALSE(utils::file::is_directory(mount_point));
|
||||
}
|
||||
|
||||
static void root_creation_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
WIN32_FILE_ATTRIBUTE_DATA ad{};
|
||||
EXPECT_TRUE(
|
||||
::GetFileAttributesEx(&mount_point[0], 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::is_file(file));
|
||||
|
||||
std::uint64_t file_size;
|
||||
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
|
||||
EXPECT_EQ(0, file_size);
|
||||
|
||||
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::retry_delete_file(file));
|
||||
EXPECT_FALSE(utils::file::is_file(file));
|
||||
}
|
||||
|
||||
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::is_file(file));
|
||||
|
||||
std::uint64_t file_size;
|
||||
EXPECT_TRUE(utils::file::get_file_size(file, file_size));
|
||||
EXPECT_EQ(10, file_size);
|
||||
}
|
||||
|
||||
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::is_file(file2));
|
||||
EXPECT_FALSE(utils::file::is_file(file));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef REPERTORY_ENABLE_S3
|
||||
if (PROVIDER_INDEX == 1U) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
Reference in New Issue
Block a user