From 24418ba03dadce5f40023e67dfd421a54859da15 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Sat, 22 Feb 2025 09:48:00 -0600 Subject: [PATCH] v2.0.4-rc (#37) # Changelog ## v2.0.4-rc ### BREAKING CHANGES * `renterd` v2.0.0+ is now required. Prior versions will fail to mount. ### Issues * \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default * \#36 [bug] Max cache size bytes is set to '0' by default ### Changes from v2.0.3-rc * Added Sia API version check prior to mounting * Added back `-cv` (check version) CLI option * Continue documentation updates * Fixed setting `ApiAuth` via `set_value_by_name` * Fixed setting `HostConfig.ApiUser` via `set_value_by_name` * Fixed setting `HostConfig.Path` via `set_value_by_name` * Fixed setting `HostConfig.Protocol` via `set_value_by_name` * Improved ring buffer read-ahead * Integrated `renterd` version 2.0.0 * Prefer using local cache file when opening files * Refactored `app_config` unit tests * Refactored polling to be more accurate on scheduling tasks Reviewed-on: https://git.fifthgrid.com/BlockStorage/repertory/pulls/37 --- .cspell/words.txt | 1 + CHANGELOG.md | 27 + CMakeLists.txt | 5 + README.md | 2 +- cmake/versions.cmake | 12 +- config.sh | 2 +- docker/aarch64/alpine | 3 +- docker/x86_64/alpine | 3 +- docker/x86_64/mingw64 | 2 +- repertory/librepertory/include/app_config.hpp | 40 +- repertory/librepertory/include/common.hpp | 59 +- .../winfsp/remotewinfsp/remote_client.hpp | 1 + .../events/types/provider_invalid_version.hpp | 78 ++ .../providers/encrypt/encrypt_provider.hpp | 7 + .../include/providers/i_provider.hpp | 4 + .../include/providers/s3/s3_provider.hpp | 7 + .../include/providers/sia/sia_provider.hpp | 4 + .../librepertory/include/types/repertory.hpp | 52 +- repertory/librepertory/src/app_config.cpp | 79 +- .../fuse/remotefuse/remote_fuse_drive.cpp | 89 +- .../winfsp/remotewinfsp/remote_client.cpp | 28 +- .../src/file_manager/file_manager.cpp | 7 + .../src/file_manager/ring_buffer_base.cpp | 106 +-- repertory/librepertory/src/initialize.cpp | 12 +- .../src/providers/base_provider.cpp | 54 +- .../providers/encrypt/encrypt_provider.cpp | 24 +- .../src/providers/s3/s3_provider.cpp | 79 +- .../src/providers/sia/sia_provider.cpp | 137 +++- repertory/librepertory/src/utils/polling.cpp | 71 +- .../repertory/include/cli/check_version.hpp | 66 +- .../include/fixtures/fuse_fixture.hpp | 18 +- .../include/mocks/mock_provider.hpp | 4 + .../repertory_test/src/app_config_test.cpp | 763 ++++++++++++++++++ repertory/repertory_test/src/atomic_test.cpp | 8 +- repertory/repertory_test/src/config_test.cpp | 696 ---------------- .../repertory_test/src/curl_comm_test.cpp | 8 +- .../src/json_serialize_test.cpp | 76 +- .../repertory_test/src/lock_data_test.cpp | 6 +- repertory/repertory_test/src/packet_test.cpp | 2 +- .../repertory_test/src/providers_test.cpp | 203 ++++- repertory/repertory_test/src/upload_test.cpp | 6 +- repertory/repertory_test/src/utils_test.cpp | 4 +- scripts/env.sh | 4 + support/include/utils/error.hpp | 130 ++- support/src/utils/error.cpp | 56 +- support/src/utils/error_handler.cpp | 241 ++++++ support/src/utils/file.cpp | 12 +- support/test/src/utils/error_test.cpp | 43 + 48 files changed, 2141 insertions(+), 1200 deletions(-) create mode 100644 repertory/librepertory/include/events/types/provider_invalid_version.hpp create mode 100644 repertory/repertory_test/src/app_config_test.cpp delete mode 100644 repertory/repertory_test/src/config_test.cpp create mode 100644 support/src/utils/error_handler.cpp diff --git a/.cspell/words.txt b/.cspell/words.txt index fefbc103..105d1a80 100644 --- a/.cspell/words.txt +++ b/.cspell/words.txt @@ -192,6 +192,7 @@ secp256k1 secur32 sfml_project shlwapi +skynet source_subdir spdlog spdlog_project diff --git a/CHANGELOG.md b/CHANGELOG.md index d48fc15b..331271ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,34 @@ # Changelog +## v2.0.4-rc + +### BREAKING CHANGES + +* `renterd` v2.0.0+ is now required. Prior versions will fail to mount. + +### Issues + +* \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default +* \#36 [bug] Max cache size bytes is set to '0' by default + +### Changes from v2.0.3-rc + +* Added Sia API version check prior to mounting +* Added back `-cv` (check version) CLI option +* Continue documentation updates +* Fixed setting `ApiAuth` via `set_value_by_name` +* Fixed setting `HostConfig.ApiUser` via `set_value_by_name` +* Fixed setting `HostConfig.Path` via `set_value_by_name` +* Fixed setting `HostConfig.Protocol` via `set_value_by_name` +* Improved ring buffer read-ahead +* Integrated `renterd` version 2.0.0 +* Prefer using local cache file when opening files +* Refactored `app_config` unit tests +* Refactored polling to be more accurate on scheduling tasks + ## v2.0.3-rc + ### Issues * \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories diff --git a/CMakeLists.txt b/CMakeLists.txt index ec98d7be..1a03a842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,10 @@ if(PROJECT_IS_MINGW) endif() endif() +if (PROJECT_ENABLE_V2_ERRORS) + add_definitions(-DPROJECT_ENABLE_V2_ERRORS) +endif() + include(cmake/settings.cmake) include(cmake/flags.cmake) @@ -143,6 +147,7 @@ endif() -DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT} -DPROJECT_DESC=${PROJECT_DESC} -DPROJECT_DIST_DIR=${PROJECT_DIST_DIR} + -DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS} -DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES} -DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST} -DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB} diff --git a/README.md b/README.md index e4f83697..b78006c3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ on Windows. ## Minimum Requirements -* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v0.4.0+ for Sia support +* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.0+ for Sia support * Only 64-bit operating systems are supported * By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support * Windows requires the following dependencies to be installed: diff --git a/cmake/versions.cmake b/cmake/versions.cmake index 4eddf7f5..2a121d97 100644 --- a/cmake/versions.cmake +++ b/cmake/versions.cmake @@ -1,15 +1,15 @@ set(BINUTILS_VERSION 2.43) -set(BOOST_MAJOR_VERSION 1) -set(BOOST_MINOR_VERSION 87) -set(BOOST_PATCH_VERSION 0) set(BOOST2_MAJOR_VERSION 1) set(BOOST2_MINOR_VERSION 76) set(BOOST2_PATCH_VERSION 0) +set(BOOST_MAJOR_VERSION 1) +set(BOOST_MINOR_VERSION 87) +set(BOOST_PATCH_VERSION 0) set(CPP_HTTPLIB_VERSION 0.18.1) -set(CURL_VERSION 8.11.0) set(CURL2_VERSION 8_11_0) -set(EXPAT_VERSION 2.6.4) +set(CURL_VERSION 8.11.0) set(EXPAT2_VERSION 2_6_4) +set(EXPAT_VERSION 2.6.4) set(GCC_VERSION 14.2.0) set(GTEST_VERSION 1.15.2) set(ICU_VERSION 76-1) @@ -22,7 +22,7 @@ set(PKG_CONFIG_VERSION 0.29.2) set(PUGIXML_VERSION 1.14) set(ROCKSDB_VERSION 9.7.4) set(SPDLOG_VERSION 1.15.0) -set(SQLITE_VERSION 3460100) set(SQLITE2_VERSION 3.46.1) +set(SQLITE_VERSION 3460100) set(STDUUID_VERSION 1.2.3) set(ZLIB_VERSION 1.3.1) diff --git a/config.sh b/config.sh index cb708ffa..9b2999ec 100755 --- a/config.sh +++ b/config.sh @@ -10,7 +10,7 @@ PROJECT_DESC="Mount utility for Sia and S3" PROJECT_MAJOR_VERSION=2 PROJECT_MINOR_VERSION=0 -PROJECT_REVISION_VERSION=3 +PROJECT_REVISION_VERSION=4 PROJECT_RELEASE_NUM=0 PROJECT_RELEASE_ITER=rc diff --git a/docker/aarch64/alpine b/docker/aarch64/alpine index eac8260c..6b580f00 100644 --- a/docker/aarch64/alpine +++ b/docker/aarch64/alpine @@ -1,4 +1,5 @@ -FROM arm64v8/alpine:3.21.0 +#comment +FROM arm64v8/alpine:3.21.3 MAINTAINER Scott E. Graves CMD bash diff --git a/docker/x86_64/alpine b/docker/x86_64/alpine index 8b3687b7..3346e7be 100644 --- a/docker/x86_64/alpine +++ b/docker/x86_64/alpine @@ -1,4 +1,5 @@ -FROM alpine:3.21.0 +#comment +FROM alpine:3.21.3 MAINTAINER Scott E. Graves CMD bash diff --git a/docker/x86_64/mingw64 b/docker/x86_64/mingw64 index 0077c720..b790cc0b 100644 --- a/docker/x86_64/mingw64 +++ b/docker/x86_64/mingw64 @@ -1,5 +1,5 @@ #comment -FROM alpine:3.21.0 +FROM alpine:3.21.3 RUN apk update RUN apk upgrade diff --git a/repertory/librepertory/include/app_config.hpp b/repertory/librepertory/include/app_config.hpp index e24bc44f..572a135e 100644 --- a/repertory/librepertory/include/app_config.hpp +++ b/repertory/librepertory/include/app_config.hpp @@ -31,26 +31,26 @@ private: static stop_type stop_requested; public: - [[nodiscard]] static auto - default_agent_name(const provider_type &prov) -> std::string; + [[nodiscard]] static auto default_agent_name(const provider_type &prov) + -> std::string; - [[nodiscard]] static auto - default_api_port(const provider_type &prov) -> std::uint16_t; + [[nodiscard]] static auto default_api_port(const provider_type &prov) + -> std::uint16_t; - [[nodiscard]] static auto - default_data_directory(const provider_type &prov) -> std::string; + [[nodiscard]] static auto default_data_directory(const provider_type &prov) + -> std::string; - [[nodiscard]] static auto - default_remote_api_port(const provider_type &prov) -> std::uint16_t; + [[nodiscard]] static auto default_remote_api_port(const provider_type &prov) + -> std::uint16_t; - [[nodiscard]] static auto - default_rpc_port(const provider_type &prov) -> std::uint16_t; + [[nodiscard]] static auto default_rpc_port(const provider_type &prov) + -> std::uint16_t; - [[nodiscard]] static auto - get_provider_display_name(const provider_type &prov) -> std::string; + [[nodiscard]] static auto get_provider_display_name(const provider_type &prov) + -> std::string; - [[nodiscard]] static auto - get_provider_name(const provider_type &prov) -> std::string; + [[nodiscard]] static auto get_provider_name(const provider_type &prov) + -> std::string; public: [[nodiscard]] static auto get_stop_requested() -> bool; @@ -91,7 +91,6 @@ private: std::atomic max_upload_count_; std::atomic med_freq_interval_secs_; std::atomic online_check_retry_secs_; - std::atomic orphaned_file_retention_days_; std::atomic preferred_download_type_; std::atomic retry_read_count_; std::atomic ring_buffer_file_size_; @@ -172,8 +171,6 @@ public: [[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t; - [[nodiscard]] auto get_orphaned_file_retention_days() const -> std::uint16_t; - [[nodiscard]] auto get_preferred_download_type() const -> download_type; [[nodiscard]] auto get_provider_type() const -> provider_type; @@ -192,8 +189,11 @@ public: [[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t; - [[nodiscard]] auto - get_value_by_name(const std::string &name) const -> std::string; + [[nodiscard]] auto get_value_by_name(const std::string &name) const + -> std::string; + + [[nodiscard]] auto get_raw_value_by_name(const std::string &name) const + -> std::string; [[nodiscard]] auto get_version() const -> std::uint64_t; @@ -239,8 +239,6 @@ public: void set_online_check_retry_secs(std::uint16_t value); - void set_orphaned_file_retention_days(std::uint16_t value); - void set_preferred_download_type(const download_type &value); void set_remote_config(remote::remote_config value); diff --git a/repertory/librepertory/include/common.hpp b/repertory/librepertory/include/common.hpp index c8948b8f..2c5d6e40 100644 --- a/repertory/librepertory/include/common.hpp +++ b/repertory/librepertory/include/common.hpp @@ -57,7 +57,7 @@ using json = nlohmann::json; inline constexpr const std::string_view REPERTORY = "repertory"; inline constexpr const std::wstring_view REPERTORY_W = L"repertory"; -inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 0ULL; +inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 1ULL; inline constexpr const std::string_view REPERTORY_DATA_NAME = "repertory2"; inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION = "2.0.0"; @@ -221,44 +221,25 @@ using WCHAR = wchar_t; #define MAX_PATH 260 -#define STATUS_SUCCESS \ - std::uint32_t { 0U } -#define STATUS_ACCESS_DENIED \ - std::uint32_t { 0xC0000022L } -#define STATUS_DEVICE_BUSY \ - std::uint32_t { 0x80000011L } -#define STATUS_DEVICE_INSUFFICIENT_RESOURCES \ - std::uint32_t { 0xC0000468L } -#define STATUS_DIRECTORY_NOT_EMPTY \ - std::uint32_t { 0xC0000101L } -#define STATUS_FILE_IS_A_DIRECTORY \ - std::uint32_t { 0xC00000BAL } -#define STATUS_FILE_TOO_LARGE \ - std::uint32_t { 0xC0000904L } -#define STATUS_INSUFFICIENT_RESOURCES \ - std::uint32_t { 0xC000009AL } -#define STATUS_INTERNAL_ERROR \ - std::uint32_t { 0xC00000E5L } -#define STATUS_INVALID_ADDRESS \ - std::uint32_t { 0xC0000141L } -#define STATUS_INVALID_HANDLE \ - std::uint32_t { 0xC0000006L } -#define STATUS_INVALID_IMAGE_FORMAT \ - std::uint32_t { 0xC000007BL } -#define STATUS_INVALID_PARAMETER \ - std::uint32_t { 0xC000000DL } -#define STATUS_NO_MEMORY \ - std::uint32_t { 0xC0000017L } -#define STATUS_NOT_IMPLEMENTED \ - std::uint32_t { 0xC0000002L } -#define STATUS_OBJECT_NAME_EXISTS \ - std::uint32_t { 0x40000000L } -#define STATUS_OBJECT_NAME_NOT_FOUND \ - std::uint32_t { 0xC0000034L } -#define STATUS_OBJECT_PATH_INVALID \ - std::uint32_t { 0xC0000039L } -#define STATUS_UNEXPECTED_IO_ERROR \ - std::uint32_t { 0xC00000E9L } +#define STATUS_SUCCESS std::uint32_t{0U} +#define STATUS_ACCESS_DENIED std::uint32_t{0xC0000022L} +#define STATUS_DEVICE_BUSY std::uint32_t{0x80000011L} +#define STATUS_DEVICE_INSUFFICIENT_RESOURCES std::uint32_t{0xC0000468L} +#define STATUS_DIRECTORY_NOT_EMPTY std::uint32_t{0xC0000101L} +#define STATUS_FILE_IS_A_DIRECTORY std::uint32_t{0xC00000BAL} +#define STATUS_FILE_TOO_LARGE std::uint32_t{0xC0000904L} +#define STATUS_INSUFFICIENT_RESOURCES std::uint32_t{0xC000009AL} +#define STATUS_INTERNAL_ERROR std::uint32_t{0xC00000E5L} +#define STATUS_INVALID_ADDRESS std::uint32_t{0xC0000141L} +#define STATUS_INVALID_HANDLE std::uint32_t{0xC0000006L} +#define STATUS_INVALID_IMAGE_FORMAT std::uint32_t{0xC000007BL} +#define STATUS_INVALID_PARAMETER std::uint32_t{0xC000000DL} +#define STATUS_NO_MEMORY std::uint32_t{0xC0000017L} +#define STATUS_NOT_IMPLEMENTED std::uint32_t{0xC0000002L} +#define STATUS_OBJECT_NAME_EXISTS std::uint32_t{0x40000000L} +#define STATUS_OBJECT_NAME_NOT_FOUND std::uint32_t{0xC0000034L} +#define STATUS_OBJECT_PATH_INVALID std::uint32_t{0xC0000039L} +#define STATUS_UNEXPECTED_IO_ERROR std::uint32_t{0xC00000E9L} #define CONVERT_STATUS_NOT_IMPLEMENTED(e) \ ((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e) diff --git a/repertory/librepertory/include/drives/winfsp/remotewinfsp/remote_client.hpp b/repertory/librepertory/include/drives/winfsp/remotewinfsp/remote_client.hpp index 2c141606..a8a8f7b6 100644 --- a/repertory/librepertory/include/drives/winfsp/remotewinfsp/remote_client.hpp +++ b/repertory/librepertory/include/drives/winfsp/remotewinfsp/remote_client.hpp @@ -26,6 +26,7 @@ #include "comm/packet/packet_client.hpp" #include "drives/remote/remote_open_file_table.hpp" #include "drives/winfsp/remotewinfsp/i_remote_instance.hpp" +#include "types/remote.hpp" namespace repertory { class app_config; diff --git a/repertory/librepertory/include/events/types/provider_invalid_version.hpp b/repertory/librepertory/include/events/types/provider_invalid_version.hpp new file mode 100644 index 00000000..4b535868 --- /dev/null +++ b/repertory/librepertory/include/events/types/provider_invalid_version.hpp @@ -0,0 +1,78 @@ +/* + Copyright <2018-2025> + + 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_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_ +#define REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_ + +#include "events/i_event.hpp" +#include "types/repertory.hpp" + +namespace repertory { +struct provider_invalid_version final : public i_event { + provider_invalid_version() = default; + provider_invalid_version(std::string_view function_name_, + std::string required_version_, + std::string returned_version_) + : function_name(std::string(function_name_)), + required_version(std::move(required_version_)), + returned_version(std::move(returned_version_)) {} + + static constexpr const event_level level{event_level::error}; + static constexpr const std::string_view name{"provider_invalid_version"}; + + std::string function_name; + std::string required_version; + std::string returned_version; + + [[nodiscard]] auto get_event_level() const -> event_level override { + return level; + } + + [[nodiscard]] auto get_name() const -> std::string_view override { + return name; + } + + [[nodiscard]] auto get_single_line() const -> std::string override { + return fmt::format("{}|func|{}|required|{}|returned|{}", name, + function_name, required_version, returned_version); + } +}; +} // namespace repertory + +NLOHMANN_JSON_NAMESPACE_BEGIN +template <> struct adl_serializer { + static void to_json(json &data, + const repertory::provider_invalid_version &value) { + data["function_name"] = value.function_name; + data["required_version"] = value.required_version; + data["returned_version"] = value.returned_version; + } + + static void from_json(const json &data, + repertory::provider_invalid_version &value) { + data.at("function_name").get_to(value.function_name); + data.at("required_version").get_to(value.required_version); + data.at("returned_version").get_to(value.returned_version); + } +}; +NLOHMANN_JSON_NAMESPACE_END + +#endif // REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_ diff --git a/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp b/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp index db4b4a3e..984f8500 100644 --- a/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp +++ b/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp @@ -85,6 +85,13 @@ private: void remove_deleted_files(stop_type &stop_requested); public: + [[nodiscard]] auto check_version(std::string &required_version, + std::string &returned_version) const + -> bool override { + required_version = returned_version = ""; + return true; + } + [[nodiscard]] auto create_directory(const std::string &api_path, api_meta_map &meta) -> api_error override; diff --git a/repertory/librepertory/include/providers/i_provider.hpp b/repertory/librepertory/include/providers/i_provider.hpp index 7e4836da..d1b5f616 100644 --- a/repertory/librepertory/include/providers/i_provider.hpp +++ b/repertory/librepertory/include/providers/i_provider.hpp @@ -31,6 +31,10 @@ class i_provider { INTERFACE_SETUP(i_provider); public: + [[nodiscard]] virtual auto check_version(std::string &required_version, + std::string &returned_version) const + -> bool = 0; + [[nodiscard]] virtual auto create_directory(const std::string &api_path, api_meta_map &meta) -> api_error = 0; diff --git a/repertory/librepertory/include/providers/s3/s3_provider.hpp b/repertory/librepertory/include/providers/s3/s3_provider.hpp index 20804914..4d9f1f04 100644 --- a/repertory/librepertory/include/providers/s3/s3_provider.hpp +++ b/repertory/librepertory/include/providers/s3/s3_provider.hpp @@ -113,6 +113,13 @@ protected: -> api_error override; public: + [[nodiscard]] auto check_version(std::string &required_version, + std::string &returned_version) const + -> bool override { + required_version = returned_version = ""; + return true; + } + [[nodiscard]] static auto convert_api_date(std::string_view date) -> std::uint64_t; diff --git a/repertory/librepertory/include/providers/sia/sia_provider.hpp b/repertory/librepertory/include/providers/sia/sia_provider.hpp index d4a07990..cdde708e 100644 --- a/repertory/librepertory/include/providers/sia/sia_provider.hpp +++ b/repertory/librepertory/include/providers/sia/sia_provider.hpp @@ -80,6 +80,10 @@ protected: -> api_error override; public: + [[nodiscard]] auto check_version(std::string &required_version, + std::string &returned_version) const + -> bool override; + [[nodiscard]] auto get_directory_item_count(const std::string &api_path) const -> std::uint64_t override; diff --git a/repertory/librepertory/include/types/repertory.hpp b/repertory/librepertory/include/types/repertory.hpp index 7a9d99e7..fce1cbc2 100644 --- a/repertory/librepertory/include/types/repertory.hpp +++ b/repertory/librepertory/include/types/repertory.hpp @@ -24,30 +24,27 @@ namespace repertory { constexpr const auto default_api_auth_size{48U}; -constexpr const auto default_download_timeout_ces{30U}; +constexpr const auto default_download_timeout_secs{30U}; constexpr const auto default_eviction_delay_mins{1U}; -constexpr const auto default_high_freq_interval_secs{30U}; -constexpr const auto default_low_freq_interval_secs{0U * 60U}; +constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}}; +constexpr const auto default_low_freq_interval_secs{std::uint16_t(60U * 60U)}; constexpr const auto default_max_cache_size_bytes{ - std::uint64_t(20UL * 1024UL * 1024UL * 1024UL), + std::uint64_t(20ULL * 1024ULL * 1024ULL * 1024ULL), }; constexpr const auto default_max_upload_count{5U}; -constexpr const auto default_med_freq_interval_secs{2U * 60U}; +constexpr const auto default_med_freq_interval_secs{std::uint16_t{2U * 60U}}; constexpr const auto default_online_check_retry_secs{60U}; -constexpr const auto default_orphaned_file_retention_days{15U}; constexpr const auto default_retry_read_count{6U}; constexpr const auto default_ring_buffer_file_size{512U}; constexpr const auto default_task_wait_ms{100U}; constexpr const auto default_timeout_ms{60000U}; -constexpr const auto max_orphaned_file_retention_days{std::uint16_t(31U)}; constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)}; constexpr const auto max_s3_object_name_length{1024U}; constexpr const auto min_cache_size_bytes{ - std::uint64_t(100UL * 1024UL * 1024UL), + std::uint64_t(100ULL * 1024ULL * 1024ULL), }; constexpr const auto min_download_timeout_secs{std::uint8_t(5U)}; constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)}; -constexpr const auto min_orphaned_file_retention_days{std::uint16_t(1U)}; constexpr const auto min_retry_read_count{std::uint16_t(2U)}; constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)}; constexpr const auto min_task_wait_ms{std::uint16_t(50U)}; @@ -333,7 +330,6 @@ struct directory_item final { bool directory{false}; std::uint64_t size{}; api_meta_map meta; - bool resolved{false}; }; struct encrypt_config final { @@ -493,8 +489,6 @@ inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{ inline constexpr const auto JSON_META{"Meta"}; inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{ "OnlineCheckRetrySeconds"}; -inline constexpr const auto JSON_ORPHANED_FILE_RETENTION_DAYS{ - "OrphanedFileRetentionDays"}; inline constexpr const auto JSON_PATH{"Path"}; inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{ "PreferredDownloadType"}; @@ -619,6 +613,16 @@ template struct adl_serializer> { } }; +template <> struct adl_serializer> { + static void to_json(json &data, const std::atomic &value) { + data = value.load(); + } + + static void from_json(const json &data, std::atomic &value) { + value.store(data.get()); + } +}; + template struct adl_serializer> { static void to_json(json &data, const std::atomic &value) { @@ -642,6 +646,18 @@ template <> struct adl_serializer> { } }; +template <> struct adl_serializer> { + static void to_json(json &data, + const std::atomic &value) { + data = repertory::event_level_to_string(value.load()); + } + + static void from_json(const json &data, + std::atomic &value) { + value.store(repertory::event_level_from_string(data.get())); + } +}; + template <> struct adl_serializer> { static void to_json(json &data, const std::atomic &value) { @@ -674,15 +690,13 @@ template <> struct adl_serializer { } }; -template <> struct adl_serializer> { - static void to_json(json &data, - const std::atomic &value) { - data = repertory::event_level_to_string(value.load()); +template <> struct adl_serializer { + static void to_json(json &data, const repertory::event_level &value) { + data = repertory::event_level_to_string(value); } - static void from_json(const json &data, - std::atomic &value) { - value.store(repertory::event_level_from_string(data.get())); + static void from_json(const json &data, repertory::event_level &value) { + value = repertory::event_level_from_string(data.get()); } }; NLOHMANN_JSON_NAMESPACE_END diff --git a/repertory/librepertory/src/app_config.cpp b/repertory/librepertory/src/app_config.cpp index 8ee5208c..4d770108 100644 --- a/repertory/librepertory/src/app_config.cpp +++ b/repertory/librepertory/src/app_config.cpp @@ -70,7 +70,7 @@ app_config::app_config(const provider_type &prov, api_port_(default_rpc_port(prov)), api_user_(std::string{REPERTORY}), config_changed_(false), - download_timeout_secs_(default_download_timeout_ces), + download_timeout_secs_(default_download_timeout_secs), enable_download_timeout_(true), enable_drive_events_(false), #if defined(_WIN32) @@ -85,7 +85,6 @@ app_config::app_config(const provider_type &prov, max_upload_count_(default_max_upload_count), med_freq_interval_secs_(default_med_freq_interval_secs), online_check_retry_secs_(default_online_check_retry_secs), - orphaned_file_retention_days_(default_orphaned_file_retention_days), preferred_download_type_(download_type::default_), retry_read_count_(default_retry_read_count), ring_buffer_file_size_(default_ring_buffer_file_size), @@ -166,8 +165,14 @@ app_config::app_config(const provider_type &prov, [this]() { return get_host_config().api_password; }}, {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT), [this]() { return std::to_string(get_host_config().api_port); }}, + {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER), + [this]() { return get_host_config().api_user; }}, {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP), [this]() { return get_host_config().host_name_or_ip; }}, + {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH), + [this]() { return get_host_config().path; }}, + {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL), + [this]() { return get_host_config().protocol; }}, {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS), [this]() { return std::to_string(get_host_config().timeout_ms); }}, {JSON_LOW_FREQ_INTERVAL_SECS, @@ -180,8 +185,6 @@ app_config::app_config(const provider_type &prov, [this]() { return std::to_string(get_med_frequency_interval_secs()); }}, {JSON_ONLINE_CHECK_RETRY_SECS, [this]() { return std::to_string(get_online_check_retry_secs()); }}, - {JSON_ORPHANED_FILE_RETENTION_DAYS, - [this]() { return std::to_string(get_orphaned_file_retention_days()); }}, {JSON_PREFERRED_DOWNLOAD_TYPE, [this]() { return download_type_to_string(get_preferred_download_type()); @@ -250,7 +253,7 @@ app_config::app_config(const provider_type &prov, value_set_lookup_ = { { - JSON_API_PATH, + JSON_API_AUTH, [this](const std::string &value) { set_api_auth(value); return get_api_auth(); @@ -349,7 +352,7 @@ app_config::app_config(const provider_type &prov, { JSON_HIGH_FREQ_INTERVAL_SECS, [this](const std::string &value) { - set_high_frequency_interval_secs(utils::string::to_uint8(value)); + set_high_frequency_interval_secs(utils::string::to_uint16(value)); return std::to_string(get_high_frequency_interval_secs()); }, }, @@ -380,6 +383,15 @@ app_config::app_config(const provider_type &prov, return std::to_string(get_host_config().api_port); }, }, + { + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER), + [this](const std::string &value) { + auto cfg = get_host_config(); + cfg.api_user = value; + set_host_config(cfg); + return get_host_config().api_user; + }, + }, { fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP), [this](const std::string &value) { @@ -389,6 +401,24 @@ app_config::app_config(const provider_type &prov, return get_host_config().host_name_or_ip; }, }, + { + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH), + [this](const std::string &value) { + auto cfg = get_host_config(); + cfg.path = value; + set_host_config(cfg); + return get_host_config().path; + }, + }, + { + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL), + [this](const std::string &value) { + auto cfg = get_host_config(); + cfg.protocol = value; + set_host_config(cfg); + return get_host_config().protocol; + }, + }, { fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS), [this](const std::string &value) { @@ -401,14 +431,14 @@ app_config::app_config(const provider_type &prov, { JSON_LOW_FREQ_INTERVAL_SECS, [this](const std::string &value) { - set_low_frequency_interval_secs(utils::string::to_uint8(value)); + set_low_frequency_interval_secs(utils::string::to_uint16(value)); return std::to_string(get_low_frequency_interval_secs()); }, }, { JSON_MED_FREQ_INTERVAL_SECS, [this](const std::string &value) { - set_med_frequency_interval_secs(utils::string::to_uint8(value)); + set_med_frequency_interval_secs(utils::string::to_uint16(value)); return std::to_string(get_med_frequency_interval_secs()); }, }, @@ -433,13 +463,6 @@ app_config::app_config(const provider_type &prov, return std::to_string(get_online_check_retry_secs()); }, }, - { - JSON_ORPHANED_FILE_RETENTION_DAYS, - [this](const std::string &value) { - set_orphaned_file_retention_days(utils::string::to_uint16(value)); - return std::to_string(get_orphaned_file_retention_days()); - }, - }, { JSON_PREFERRED_DOWNLOAD_TYPE, [this](const std::string &value) { @@ -812,7 +835,6 @@ auto app_config::get_json() const -> json { {JSON_MAX_UPLOAD_COUNT, max_upload_count_}, {JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_secs_}, {JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_}, - {JSON_ORPHANED_FILE_RETENTION_DAYS, orphaned_file_retention_days_}, {JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_}, {JSON_REMOTE_CONFIG, remote_config_}, {JSON_REMOTE_MOUNT, remote_mount_}, @@ -834,7 +856,6 @@ auto app_config::get_json() const -> json { ret.erase(JSON_MAX_CACHE_SIZE_BYTES); ret.erase(JSON_MAX_UPLOAD_COUNT); ret.erase(JSON_ONLINE_CHECK_RETRY_SECS); - ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS); ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE); ret.erase(JSON_REMOTE_CONFIG); ret.erase(JSON_RETRY_READ_COUNT); @@ -856,7 +877,6 @@ auto app_config::get_json() const -> json { ret.erase(JSON_MAX_UPLOAD_COUNT); ret.erase(JSON_MED_FREQ_INTERVAL_SECS); ret.erase(JSON_ONLINE_CHECK_RETRY_SECS); - ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS); ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE); ret.erase(JSON_REMOTE_MOUNT); ret.erase(JSON_RETRY_READ_COUNT); @@ -912,12 +932,6 @@ auto app_config::get_online_check_retry_secs() const -> std::uint16_t { return std::max(min_online_check_retry_secs, online_check_retry_secs_.load()); } -auto app_config::get_orphaned_file_retention_days() const -> std::uint16_t { - return std::min(max_orphaned_file_retention_days, - std::max(min_orphaned_file_retention_days, - orphaned_file_retention_days_.load())); -} - auto app_config::get_preferred_download_type() const -> download_type { return preferred_download_type_; } @@ -1053,8 +1067,6 @@ auto app_config::load() -> bool { med_freq_interval_secs_, found); get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_, found); - get_value(json_document, JSON_ORPHANED_FILE_RETENTION_DAYS, - orphaned_file_retention_days_, found); get_value(json_document, JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_, found); get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found); @@ -1069,10 +1081,17 @@ auto app_config::load() -> bool { std::uint64_t version{}; get_value(json_document, JSON_VERSION, version, found); - // Handle configuration defaults for new config versions if (version != REPERTORY_CONFIG_VERSION) { version_ = REPERTORY_CONFIG_VERSION; - // TODO upgrade future version + if (version_ == 1U) { + if (low_freq_interval_secs_ == 0UL) { + set_value(low_freq_interval_secs_, default_low_freq_interval_secs); + } + + if (max_cache_size_bytes_ == 0UL) { + set_value(max_cache_size_bytes_, default_max_cache_size_bytes); + } + } found = false; } @@ -1199,10 +1218,6 @@ void app_config::set_online_check_retry_secs(std::uint16_t value) { set_value(online_check_retry_secs_, value); } -void app_config::set_orphaned_file_retention_days(std::uint16_t value) { - set_value(orphaned_file_retention_days_, value); -} - void app_config::set_preferred_download_type(const download_type &value) { set_value(preferred_download_type_, value); } diff --git a/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp b/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp index 982d9c57..18c792b2 100644 --- a/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp +++ b/repertory/librepertory/src/drives/fuse/remotefuse/remote_fuse_drive.cpp @@ -43,8 +43,8 @@ #include "utils/utils.hpp" namespace repertory::remote_fuse { -auto remote_fuse_drive::access_impl(std::string api_path, - int mask) -> api_error { +auto remote_fuse_drive::access_impl(std::string api_path, int mask) + -> api_error { return utils::to_api_error( remote_instance_->fuse_access(api_path.c_str(), mask)); } @@ -62,8 +62,8 @@ auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::chmod_impl(std::string api_path, - mode_t mode) -> api_error { +auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode) + -> api_error { #endif return utils::to_api_error(remote_instance_->fuse_chmod( api_path.c_str(), static_cast(mode))); @@ -74,8 +74,8 @@ auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, - gid_t gid) -> api_error { +auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid) + -> api_error { #endif return utils::to_api_error( remote_instance_->fuse_chown(api_path.c_str(), uid, gid)); @@ -94,7 +94,7 @@ void remote_fuse_drive::destroy_impl(void *ptr) { REPERTORY_USES_FUNCTION_NAME(); event_system::instance().raise(function_name, - get_mount_location()); + get_mount_location()); if (server_) { server_->stop(); @@ -116,14 +116,15 @@ void remote_fuse_drive::destroy_impl(void *ptr) { } event_system::instance().raise(function_name, - get_mount_location()); + get_mount_location()); fuse_base::destroy_impl(ptr); } -auto remote_fuse_drive::fgetattr_impl( - std::string api_path, struct stat *unix_st, - struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::fgetattr_impl(std::string api_path, + struct stat *unix_st, + struct fuse_file_info *f_info) + -> api_error { remote::stat r_stat{}; auto directory = false; @@ -184,8 +185,8 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::getattr_impl(std::string api_path, - struct stat *unix_st) -> api_error { +auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st) + -> api_error { #endif bool directory = false; remote::stat r_stat{}; @@ -263,14 +264,14 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * { server_ = std::make_shared(config_); server_->start(); event_system::instance().raise(function_name, - get_mount_location()); + get_mount_location()); } return ret; } -auto remote_fuse_drive::mkdir_impl(std::string api_path, - mode_t mode) -> api_error { +auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode) + -> api_error { return utils::to_api_error(remote_instance_->fuse_mkdir( api_path.c_str(), static_cast(mode))); } @@ -295,8 +296,9 @@ auto remote_fuse_drive::open_impl(std::string api_path, f_info->fh)); } -auto remote_fuse_drive::opendir_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::opendir_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { if ((f_info->flags & O_APPEND) == O_APPEND || (f_info->flags & O_EXCL) == O_EXCL) { return api_error::directory_exists; @@ -309,12 +311,14 @@ auto remote_fuse_drive::opendir_impl( void remote_fuse_drive::populate_stat(const remote::stat &r_stat, bool directory, struct stat &unix_st) { std::memset(&unix_st, 0, sizeof(struct stat)); - unix_st.st_blksize = r_stat.st_blksize; - unix_st.st_blocks = static_cast(r_stat.st_blocks); + unix_st.st_blksize = + static_cast(r_stat.st_blksize); + unix_st.st_blocks = + static_cast(r_stat.st_blocks); unix_st.st_gid = r_stat.st_gid; unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode; unix_st.st_nlink = r_stat.st_nlink; - unix_st.st_size = static_cast(r_stat.st_size); + unix_st.st_size = static_cast(r_stat.st_size); unix_st.st_uid = r_stat.st_uid; #if defined(__APPLE__) @@ -373,14 +377,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer, } #if FUSE_USE_VERSION >= 30 -auto remote_fuse_drive::readdir_impl( - std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir, - off_t offset, struct fuse_file_info *f_info, - fuse_readdir_flags /*flags*/) -> api_error { +auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf, + fuse_fill_dir_t fuse_fill_dir, + off_t offset, + struct fuse_file_info *f_info, + fuse_readdir_flags /*flags*/) + -> api_error { #else -auto remote_fuse_drive::readdir_impl( - std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir, - off_t offset, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf, + fuse_fill_dir_t fuse_fill_dir, + off_t offset, + struct fuse_file_info *f_info) + -> api_error { #endif std::string item_path; int res = 0; @@ -408,14 +416,16 @@ auto remote_fuse_drive::readdir_impl( return utils::to_api_error(res); } -auto remote_fuse_drive::release_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::release_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { return utils::to_api_error( remote_instance_->fuse_release(api_path.c_str(), f_info->fh)); } -auto remote_fuse_drive::releasedir_impl( - std::string api_path, struct fuse_file_info *f_info) -> api_error { +auto remote_fuse_drive::releasedir_impl(std::string api_path, + struct fuse_file_info *f_info) + -> api_error { return utils::to_api_error( remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh)); } @@ -512,8 +522,8 @@ api_error remote_fuse_drive::statfs_x_impl(std::string api_path, return utils::to_api_error(res); } #else // __APPLE__ -auto remote_fuse_drive::statfs_impl(std::string api_path, - struct statvfs *stbuf) -> api_error { +auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf) + -> api_error { auto res = statvfs(config_.get_data_directory().c_str(), stbuf); if (res == 0) { remote::statfs r_stat{}; @@ -540,8 +550,8 @@ auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size, struct fuse_file_info * /*f_info*/) -> api_error { #else -auto remote_fuse_drive::truncate_impl(std::string api_path, - off_t size) -> api_error { +auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size) + -> api_error { #endif return utils::to_api_error(remote_instance_->fuse_truncate( api_path.c_str(), static_cast(size))); @@ -552,9 +562,10 @@ auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error { } #if FUSE_USE_VERSION >= 30 -auto remote_fuse_drive::utimens_impl( - std::string api_path, const struct timespec tv[2], - struct fuse_file_info * /*f_info*/) -> api_error { +auto remote_fuse_drive::utimens_impl(std::string api_path, + const struct timespec tv[2], + struct fuse_file_info * /*f_info*/) + -> api_error { #else auto remote_fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2]) -> api_error { diff --git a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp index 0b9737a3..71ec10f4 100644 --- a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp +++ b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_client.cpp @@ -22,13 +22,11 @@ #include "drives/winfsp/remotewinfsp/remote_client.hpp" #include "app_config.hpp" -#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp" #include "events/event_system.hpp" #include "events/types/drive_mounted.hpp" #include "events/types/drive_unmount_pending.hpp" #include "events/types/drive_unmounted.hpp" -#include "types/repertory.hpp" -#include "utils/path.hpp" +#include "utils/string.hpp" #include "version.hpp" namespace repertory::remote_winfsp { @@ -44,11 +42,7 @@ auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name) request.encode(file_name); std::uint32_t service_flags{}; - auto ret{ - packet_client_.send(function_name, request, service_flags), - }; - - return ret; + return packet_client_.send(function_name, request, service_flags); } auto remote_client::json_create_directory_snapshot(const std::string &path, @@ -103,11 +97,7 @@ auto remote_client::json_release_directory_snapshot( request.encode(handle); std::uint32_t service_flags{}; - auto ret{ - packet_client_.send(function_name, request, service_flags), - }; - - return ret; + return packet_client_.send(function_name, request, service_flags); } auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name, @@ -273,8 +263,8 @@ auto remote_client::winfsp_get_security_by_name(PWSTR file_name, packet request; request.encode(file_name); - request.encode(static_cast( - descriptor_size == nullptr ? 0 : *descriptor_size)); + request.encode(descriptor_size == nullptr ? std::uint64_t(0U) + : *descriptor_size); request.encode(static_cast(attributes != nullptr)); packet response; @@ -417,7 +407,7 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset, ret = response.decode(buffer, *bytes_transferred); #if defined(_WIN32) if ((ret == STATUS_SUCCESS) && - (not*bytes_transferred || (*bytes_transferred != length))) { + ((*bytes_transferred == 0U) || (*bytes_transferred != length))) { ::SetLastError(ERROR_HANDLE_EOF); } #endif @@ -461,11 +451,7 @@ auto remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name, request.encode(replace_if_exists); std::uint32_t service_flags{}; - auto ret{ - packet_client_.send(function_name, request, service_flags), - }; - - return ret; + return packet_client_.send(function_name, request, service_flags); } auto remote_client::winfsp_set_basic_info( diff --git a/repertory/librepertory/src/file_manager/file_manager.cpp b/repertory/librepertory/src/file_manager/file_manager.cpp index 8d8d512c..9c347dec 100644 --- a/repertory/librepertory/src/file_manager/file_manager.cpp +++ b/repertory/librepertory/src/file_manager/file_manager.cpp @@ -466,6 +466,13 @@ auto file_manager::open(const std::string &api_path, bool directory, return download_type::default_; } + if (utils::file::file{fsi.source_path}.exists()) { + auto size = utils::file::file{fsi.source_path}.size(); + if (size.has_value() && *size == fsi.size) { + return download_type::default_; + } + } + if (type == download_type::direct) { return type; } diff --git a/repertory/librepertory/src/file_manager/ring_buffer_base.cpp b/repertory/librepertory/src/file_manager/ring_buffer_base.cpp index e818ae76..34e1daf3 100644 --- a/repertory/librepertory/src/file_manager/ring_buffer_base.cpp +++ b/repertory/librepertory/src/file_manager/ring_buffer_base.cpp @@ -98,19 +98,23 @@ auto ring_buffer_base::close() -> bool { return res; } -auto ring_buffer_base::download_chunk(std::size_t chunk, - bool skip_active) -> api_error { +auto ring_buffer_base::download_chunk(std::size_t chunk, bool skip_active) + -> api_error { REPERTORY_USES_FUNCTION_NAME(); unique_mutex_lock chunk_lock(chunk_mtx_); - const auto unlock_and_notify = [this, &chunk_lock]() { + if (not skip_active) { + ring_pos_ = chunk; + } + + const auto notify_and_unlock = [this, &chunk_lock]() { chunk_notify_.notify_all(); chunk_lock.unlock(); }; const auto unlock_and_return = - [&unlock_and_notify](api_error res) -> api_error { - unlock_and_notify(); + [¬ify_and_unlock](api_error res) -> api_error { + notify_and_unlock(); return res; }; @@ -124,7 +128,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk, } auto active_download = get_active_downloads().at(chunk); - unlock_and_notify(); + notify_and_unlock(); return active_download->wait(); } @@ -142,7 +146,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk, chunk == (total_chunks_ - 1U) ? get_last_chunk_size() : get_chunk_size(), }; - unlock_and_notify(); + notify_and_unlock(); auto result{ get_provider().read_file_bytes(get_api_path(), data_size, data_offset, @@ -167,7 +171,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk, } get_active_downloads().erase(chunk); - unlock_and_notify(); + notify_and_unlock(); active_download->notify(result); return result; @@ -226,7 +230,6 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset, } else if (chunk < ring_pos_) { reverse(ring_pos_ - chunk); } - res = download_chunk(chunk, false); if (res != api_error::success) { if (res == api_error::invalid_ring_buffer_position) { @@ -264,38 +267,46 @@ void ring_buffer_base::reader_thread() { REPERTORY_USES_FUNCTION_NAME(); unique_mutex_lock chunk_lock(chunk_mtx_); - auto next_chunk{ring_pos_}; - chunk_notify_.notify_all(); - chunk_lock.unlock(); + const auto notify_and_unlock = [this, &chunk_lock]() { + chunk_notify_.notify_all(); + chunk_lock.unlock(); + }; + + auto last_pos = ring_pos_; + auto next_chunk = ring_pos_; + notify_and_unlock(); while (not get_stop_requested()) { chunk_lock.lock(); - next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U; - const auto check_and_wait = [this, &chunk_lock, &next_chunk]() { + if (last_pos == ring_pos_) { + ++next_chunk; + } else { + next_chunk = ring_pos_ + 1U; + last_pos = ring_pos_; + } + + if (next_chunk > ring_end_) { + next_chunk = ring_begin_; + } + + if (read_state_[next_chunk % read_state_.size()]) { if (get_stop_requested()) { - chunk_notify_.notify_all(); - chunk_lock.unlock(); + notify_and_unlock(); return; } if (get_read_state().all()) { chunk_notify_.wait(chunk_lock); + last_pos = ring_pos_; next_chunk = ring_pos_; } - chunk_notify_.notify_all(); - chunk_lock.unlock(); - }; - - if (read_state_[next_chunk % read_state_.size()]) { - check_and_wait(); + notify_and_unlock(); continue; } - chunk_notify_.notify_all(); - chunk_lock.unlock(); - + notify_and_unlock(); download_chunk(next_chunk, true); } @@ -351,30 +362,31 @@ void ring_buffer_base::update_position(std::size_t count, bool is_forward) { if (is_forward ? (ring_pos_ + count) <= ring_end_ : (ring_pos_ - count) >= ring_begin_) { ring_pos_ += is_forward ? count : -count; - } else { - auto delta = is_forward ? count - (ring_end_ - ring_pos_) - : count - (ring_pos_ - ring_begin_); - - if (delta >= read_state_.size()) { - read_state_.set(0U, read_state_.size(), false); - ring_pos_ += is_forward ? count : -count; - ring_begin_ += is_forward ? delta : -delta; - } else { - for (std::size_t idx = 0U; idx < delta; ++idx) { - if (is_forward) { - read_state_[(ring_begin_ + idx) % read_state_.size()] = false; - } else { - read_state_[(ring_end_ - idx) % read_state_.size()] = false; - } - } - ring_begin_ += is_forward ? delta : -delta; - ring_pos_ += is_forward ? count : -count; - } - - ring_end_ = - std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U); + chunk_notify_.notify_all(); + return; } + auto delta = is_forward ? count - (ring_end_ - ring_pos_) + : count - (ring_pos_ - ring_begin_); + if (delta >= read_state_.size()) { + read_state_.set(0U, read_state_.size(), false); + ring_pos_ += is_forward ? count : -count; + ring_begin_ += is_forward ? delta : -delta; + } else { + for (std::size_t idx = 0U; idx < delta; ++idx) { + if (is_forward) { + read_state_[(ring_begin_ + idx) % read_state_.size()] = false; + } else { + read_state_[(ring_end_ - idx) % read_state_.size()] = false; + } + } + ring_begin_ += is_forward ? delta : -delta; + ring_pos_ += is_forward ? count : -count; + } + + ring_end_ = + std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U); + chunk_notify_.notify_all(); } } // namespace repertory diff --git a/repertory/librepertory/src/initialize.cpp b/repertory/librepertory/src/initialize.cpp index ba021868..37179b06 100644 --- a/repertory/librepertory/src/initialize.cpp +++ b/repertory/librepertory/src/initialize.cpp @@ -50,10 +50,6 @@ namespace repertory { auto project_initialize() -> bool { - spdlog::drop_all(); - spdlog::flush_every(std::chrono::seconds(10)); - spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v"); - #if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW) { static constexpr const auto guard_size{4096U}; @@ -68,6 +64,10 @@ auto project_initialize() -> bool { } #endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW) + spdlog::drop_all(); + spdlog::flush_every(std::chrono::seconds(10)); + spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v"); + #if defined(PROJECT_ENABLE_LIBSODIUM) { if (sodium_init() == -1) { @@ -77,7 +77,9 @@ auto project_initialize() -> bool { #endif // defined(PROJECT_ENABLE_LIBSODIUM) #if defined(PROJECT_ENABLE_OPENSSL) - { SSL_library_init(); } + { + SSL_library_init(); + } #endif // defined(PROJECT_ENABLE_OPENSSL) #if defined(PROJECT_ENABLE_CURL) diff --git a/repertory/librepertory/src/providers/base_provider.cpp b/repertory/librepertory/src/providers/base_provider.cpp index 4ca50567..432f045d 100644 --- a/repertory/librepertory/src/providers/base_provider.cpp +++ b/repertory/librepertory/src/providers/base_provider.cpp @@ -34,6 +34,7 @@ #include "events/types/orphaned_file_processing_failed.hpp" #include "events/types/orphaned_source_file_detected.hpp" #include "events/types/orphaned_source_file_removed.hpp" +#include "events/types/provider_invalid_version.hpp" #include "events/types/provider_offline.hpp" #include "events/types/provider_upload_begin.hpp" #include "events/types/provider_upload_end.hpp" @@ -69,8 +70,8 @@ void base_provider::add_all_items(stop_type &stop_requested) { } auto base_provider::create_api_file(std::string path, std::string key, - std::uint64_t size, - std::uint64_t file_time) -> api_file { + std::uint64_t size, std::uint64_t file_time) + -> api_file { api_file file{}; file.api_path = utils::path::create_api_path(path); file.api_parent = utils::path::get_parent_api_path(file.api_path); @@ -102,8 +103,8 @@ auto base_provider::create_api_file(std::string path, std::uint64_t size, } auto base_provider::create_directory_clone_source_meta( - const std::string &source_api_path, - const std::string &api_path) -> api_error { + const std::string &source_api_path, const std::string &api_path) + -> api_error { REPERTORY_USES_FUNCTION_NAME(); bool exists{}; @@ -201,8 +202,8 @@ auto base_provider::create_directory(const std::string &api_path, return api_error::error; } -auto base_provider::create_file(const std::string &api_path, - api_meta_map &meta) -> api_error { +auto base_provider::create_file(const std::string &api_path, api_meta_map &meta) + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -259,8 +260,9 @@ auto base_provider::create_file(const std::string &api_path, return api_error::error; } -auto base_provider::get_api_path_from_source( - const std::string &source_path, std::string &api_path) const -> api_error { +auto base_provider::get_api_path_from_source(const std::string &source_path, + std::string &api_path) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); if (source_path.empty()) { @@ -273,8 +275,9 @@ auto base_provider::get_api_path_from_source( return db3_->get_api_path(source_path, api_path); } -auto base_provider::get_directory_items( - const std::string &api_path, directory_item_list &list) const -> api_error { +auto base_provider::get_directory_items(const std::string &api_path, + directory_item_list &list) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -283,8 +286,15 @@ auto base_provider::get_directory_items( if (res != api_error::success) { return res; } + if (not exists) { - return api_error::directory_not_found; + res = is_file(api_path, exists); + if (res != api_error::success) { + utils::error::raise_api_path_error( + function_name, api_path, res, "failed to determine if file exists"); + } + + return exists ? api_error::item_exists : api_error::directory_not_found; } res = get_directory_items_impl(api_path, list); @@ -342,9 +352,10 @@ auto base_provider::get_file_size(const std::string &api_path, return api_error::success; } -auto base_provider::get_filesystem_item( - const std::string &api_path, bool directory, - filesystem_item &fsi) const -> api_error { +auto base_provider::get_filesystem_item(const std::string &api_path, + bool directory, + filesystem_item &fsi) const + -> api_error { bool exists{}; auto res = is_directory(api_path, exists); if (res != api_error::success) { @@ -377,9 +388,10 @@ auto base_provider::get_filesystem_item( return api_error::success; } -auto base_provider::get_filesystem_item_and_file( - const std::string &api_path, api_file &file, - filesystem_item &fsi) const -> api_error { +auto base_provider::get_filesystem_item_and_file(const std::string &api_path, + api_file &file, + filesystem_item &fsi) const + -> api_error { auto res = get_file(api_path, file); if (res != api_error::success) { return res; @@ -829,6 +841,14 @@ auto base_provider::start(api_item_added_callback api_item_added, return false; } + std::string returned_version; + std::string required_version; + if (not check_version(required_version, returned_version)) { + event_system::instance().raise( + function_name, required_version, returned_version); + return false; + } + cache_size_mgr::instance().initialize(&config_); polling::instance().set_callback({ diff --git a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp index a33b9c3e..3dbf5fe7 100644 --- a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp +++ b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp @@ -40,6 +40,7 @@ #include "utils/file_utils.hpp" #include "utils/path.hpp" #include "utils/polling.hpp" +#include namespace repertory { encrypt_provider::encrypt_provider(app_config &config) @@ -262,7 +263,6 @@ auto encrypt_provider::get_directory_items(const std::string &api_path, dir_item.api_parent = file.api_parent; dir_item.api_path = file.api_path; dir_item.directory = dir_entry->is_directory_item(); - dir_item.resolved = true; dir_item.size = file.file_size; create_item_meta(dir_item.meta, dir_item.directory, file); @@ -342,13 +342,23 @@ auto encrypt_provider::get_file_list(api_file_list &list, const auto &cfg{get_encrypt_config()}; try { - for (const auto &dir_entry : utils::file::directory{cfg.path}.get_items()) { - std::string api_path{}; - if (process_directory_entry(*dir_entry.get(), cfg, api_path)) { - list.emplace_back(create_api_file( - api_path, dir_entry->is_directory_item(), dir_entry->get_path())); + using func = std::function; + const func process_directory = [&](std::string path) { + for (const auto &dir_entry : utils::file::directory{path}.get_items()) { + std::string api_path{}; + if (dir_entry->is_directory_item()) { + process_directory_entry(*dir_entry.get(), cfg, api_path); + process_directory(dir_entry->get_path()); + continue; + } + + if (process_directory_entry(*dir_entry.get(), cfg, api_path)) { + list.emplace_back(create_api_file( + api_path, dir_entry->is_directory_item(), dir_entry->get_path())); + } } - } + }; + process_directory(cfg.path); return api_error::success; } catch (const std::exception &ex) { diff --git a/repertory/librepertory/src/providers/s3/s3_provider.cpp b/repertory/librepertory/src/providers/s3/s3_provider.cpp index 2b23fa90..6307b8fb 100644 --- a/repertory/librepertory/src/providers/s3/s3_provider.cpp +++ b/repertory/librepertory/src/providers/s3/s3_provider.cpp @@ -43,9 +43,9 @@ #include "utils/time.hpp" namespace { -[[nodiscard]] auto -set_request_path(auto &request, - const std::string &object_name) -> repertory::api_error { +[[nodiscard]] auto set_request_path(auto &request, + const std::string &object_name) + -> repertory::api_error { request.path = object_name; if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) { return repertory::api_error::name_too_long; @@ -59,8 +59,9 @@ namespace repertory { s3_provider::s3_provider(app_config &config, i_http_comm &comm) : base_provider(config, comm) {} -auto s3_provider::add_if_not_found( - api_file &file, const std::string &object_name) const -> api_error { +auto s3_provider::add_if_not_found(api_file &file, + const std::string &object_name) const + -> api_error { api_meta_map meta{}; auto res{get_item_meta(file.api_path, meta)}; if (res == api_error::item_not_found) { @@ -88,7 +89,7 @@ auto s3_provider::convert_api_date(std::string_view date) -> std::uint64_t { 1000000UL, }; - struct tm tm1 {}; + struct tm tm1{}; #if defined(_WIN32) utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &tm1); return nanos + utils::time::windows_time_t_to_unix_time(_mkgmtime(&tm1)); @@ -157,8 +158,9 @@ auto s3_provider::create_directory_impl(const std::string &api_path, utils::path::create_api_path(is_encrypted ? meta[META_KEY] : api_path)); } -auto s3_provider::create_directory_paths( - const std::string &api_path, const std::string &key) const -> api_error { +auto s3_provider::create_directory_paths(const std::string &api_path, + const std::string &key) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); if (api_path == "/") { @@ -321,8 +323,9 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const return 0U; } -auto s3_provider::get_directory_items_impl( - const std::string &api_path, directory_item_list &list) const -> api_error { +auto s3_provider::get_directory_items_impl(const std::string &api_path, + directory_item_list &list) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); const auto &cfg{get_s3_config()}; @@ -480,8 +483,8 @@ auto s3_provider::get_directory_items_impl( return api_error::success; } -auto s3_provider::get_file(const std::string &api_path, - api_file &file) const -> api_error { +auto s3_provider::get_file(const std::string &api_path, api_file &file) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -492,7 +495,19 @@ auto s3_provider::get_file(const std::string &api_path, get_object_info(false, api_path, is_encrypted, object_name, result), }; if (res != api_error::success) { - return res; + if (res != api_error::item_not_found) { + return res; + } + + bool exists{}; + res = is_directory(api_path, exists); + if (res != api_error::success) { + utils::error::raise_api_path_error( + function_name, api_path, res, + "failed to determine if directory exists"); + } + + return exists ? api_error::directory_exists : api_error::item_not_found; } file.api_path = api_path; @@ -521,8 +536,8 @@ auto s3_provider::get_file(const std::string &api_path, return api_error::error; } -auto s3_provider::get_file_list(api_file_list &list, - std::string &marker) const -> api_error { +auto s3_provider::get_file_list(api_file_list &list, std::string &marker) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -612,8 +627,9 @@ auto s3_provider::get_file_list(api_file_list &list, return api_error::error; } -auto s3_provider::get_last_modified( - bool directory, const std::string &api_path) const -> std::uint64_t { +auto s3_provider::get_last_modified(bool directory, + const std::string &api_path) const + -> std::uint64_t { bool is_encrypted{}; std::string object_name; head_object_result result{}; @@ -623,9 +639,10 @@ auto s3_provider::get_last_modified( : utils::time::get_time_now(); } -auto s3_provider::get_object_info( - bool directory, const std::string &api_path, bool &is_encrypted, - std::string &object_name, head_object_result &result) const -> api_error { +auto s3_provider::get_object_info(bool directory, const std::string &api_path, + bool &is_encrypted, std::string &object_name, + head_object_result &result) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -685,10 +702,12 @@ auto s3_provider::get_object_info( return api_error::error; } -auto s3_provider::get_object_list( - std::string &response_data, long &response_code, - std::optional delimiter, std::optional prefix, - std::optional token) const -> bool { +auto s3_provider::get_object_list(std::string &response_data, + long &response_code, + std::optional delimiter, + std::optional prefix, + std::optional token) const + -> bool { curl::requests::http_get get{}; get.allow_timeout = true; get.aws_service = "aws:amz:" + get_s3_config().region + ":s3"; @@ -716,8 +735,8 @@ auto s3_provider::get_total_drive_space() const -> std::uint64_t { return std::numeric_limits::max() / std::int64_t(2); } -auto s3_provider::is_directory(const std::string &api_path, - bool &exists) const -> api_error { +auto s3_provider::is_directory(const std::string &api_path, bool &exists) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -745,8 +764,8 @@ auto s3_provider::is_directory(const std::string &api_path, return api_error::error; } -auto s3_provider::is_file(const std::string &api_path, - bool &exists) const -> api_error { +auto s3_provider::is_file(const std::string &api_path, bool &exists) const + -> api_error { REPERTORY_USES_FUNCTION_NAME(); try { @@ -1004,8 +1023,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */, return api_error::not_implemented; } -auto s3_provider::set_meta_key(const std::string &api_path, - api_meta_map &meta) -> api_error { +auto s3_provider::set_meta_key(const std::string &api_path, api_meta_map &meta) + -> api_error { REPERTORY_USES_FUNCTION_NAME(); const auto &cfg{get_s3_config()}; diff --git a/repertory/librepertory/src/providers/sia/sia_provider.cpp b/repertory/librepertory/src/providers/sia/sia_provider.cpp index ceced3b7..1c0a425d 100644 --- a/repertory/librepertory/src/providers/sia/sia_provider.cpp +++ b/repertory/librepertory/src/providers/sia/sia_provider.cpp @@ -32,8 +32,8 @@ #include "providers/base_provider.hpp" #include "providers/s3/s3_provider.hpp" #include "types/repertory.hpp" +#include "utils/common.hpp" #include "utils/error_utils.hpp" -#include "utils/file_utils.hpp" #include "utils/path.hpp" #include "utils/polling.hpp" #include "utils/string.hpp" @@ -63,6 +63,54 @@ namespace repertory { sia_provider::sia_provider(app_config &config, i_http_comm &comm) : base_provider(config, comm) {} +auto sia_provider::check_version(std::string &required_version, + std::string &returned_version) const -> bool { + REPERTORY_USES_FUNCTION_NAME(); + + required_version = "2.0.0"; + + try { + curl::requests::http_get get{}; + get.allow_timeout = true; + get.path = "/api/bus/state"; + + nlohmann::json state_data; + std::string error_data; + get.response_handler = [&error_data, &state_data](auto &&data, + long response_code) { + if (response_code == http_error_codes::ok) { + state_data = nlohmann::json::parse(data.begin(), data.end()); + return; + } + + error_data = std::string(data.begin(), data.end()); + }; + + long response_code{}; + stop_type stop_requested{}; + if (not get_comm().make_request(get, response_code, stop_requested)) { + utils::error::raise_error(function_name, response_code, + "failed to check state"); + return false; + } + + if (response_code != http_error_codes::ok) { + utils::error::raise_error( + function_name, response_code, + fmt::format("failed to check state|response|{}", error_data)); + return false; + } + + returned_version = state_data.at("version").get().substr(1U); + return utils::compare_version_strings(returned_version, required_version) >= + 0; + } catch (const std::exception &e) { + utils::error::raise_error(function_name, e, "failed to check version"); + } + + return false; +} + auto sia_provider::create_directory_impl(const std::string &api_path, api_meta_map & /* meta */) -> api_error { @@ -70,7 +118,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path, curl::requests::http_put_file put_file{}; put_file.allow_timeout = true; - put_file.path = "/api/worker/objects" + api_path + "/"; + put_file.path = "/api/worker/object" + api_path + "/"; put_file.query["bucket"] = get_bucket(get_sia_config()); std::string error_data; @@ -112,10 +160,10 @@ auto sia_provider::get_directory_item_count(const std::string &api_path) const } std::uint64_t item_count{}; - if (object_list.contains("entries")) { - for (const auto &entry : object_list.at("entries")) { + if (object_list.contains("objects")) { + for (const auto &entry : object_list.at("objects")) { try { - auto name{entry.at("name").get()}; + auto name{entry.at("key").get()}; auto entry_api_path{utils::path::create_api_path(name)}; if (utils::string::ends_with(name, "/") && (entry_api_path == api_path)) { @@ -149,10 +197,10 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path, return api_error::comm_error; } - if (object_list.contains("entries")) { - for (const auto &entry : object_list.at("entries")) { + if (object_list.contains("objects")) { + for (const auto &entry : object_list.at("objects")) { try { - auto name{entry.at("name").get()}; + auto name{entry.at("key").get()}; auto entry_api_path{utils::path::create_api_path(name)}; auto directory{utils::string::ends_with(name, "/")}; @@ -185,7 +233,6 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path, dir_item.api_path = file.api_path; dir_item.directory = directory; dir_item.meta = meta; - dir_item.resolved = true; dir_item.size = file.file_size; list.emplace_back(std::move(dir_item)); } catch (const std::exception &e) { @@ -207,22 +254,28 @@ auto sia_provider::get_file(const std::string &api_path, api_file &file) const json file_data{}; auto res{get_object_info(api_path, file_data)}; if (res != api_error::success) { - return res; + if (res != api_error::item_not_found) { + return res; + } + + bool exists{}; + res = is_directory(api_path, exists); + if (res != api_error::success) { + utils::error::raise_api_path_error( + function_name, api_path, res, + "failed to determine if directory exists"); + } + + return exists ? api_error::directory_exists : api_error::item_not_found; } - auto slabs{file_data["object"]["Slabs"]}; auto size{ - std::accumulate( - slabs.begin(), slabs.end(), std::uint64_t(0U), - [](auto &&total_size, const json &slab) -> std::uint64_t { - return total_size + slab["Length"].get(); - }), + file_data.at("size").get(), }; api_meta_map meta{}; if (get_item_meta(api_path, meta) == api_error::item_not_found) { - file = create_api_file(api_path, "", size, - get_last_modified(file_data["object"])); + file = create_api_file(api_path, "", size, get_last_modified(file_data)); get_api_item_added()(false, file); } else { file = create_api_file(api_path, size, meta); @@ -250,9 +303,9 @@ auto sia_provider::get_file_list(api_file_list &list, return api_error::comm_error; } - if (object_list.contains("entries")) { - for (const auto &entry : object_list.at("entries")) { - auto name{entry.at("name").get()}; + if (object_list.contains("objects")) { + for (const auto &entry : object_list.at("objects")) { + auto name{entry.at("key").get()}; auto entry_api_path{utils::path::create_api_path(name)}; if (utils::string::ends_with(name, "/")) { @@ -313,8 +366,9 @@ auto sia_provider::get_object_info(const std::string &api_path, try { curl::requests::http_get get{}; get.allow_timeout = true; - get.path = "/api/bus/objects" + api_path; + get.path = "/api/bus/object" + api_path; get.query["bucket"] = get_bucket(get_sia_config()); + get.query["onlymetadata"] = "true"; std::string error_data; get.response_handler = [&error_data, &object_info](auto &&data, @@ -362,6 +416,7 @@ auto sia_provider::get_object_list(const std::string &api_path, get.allow_timeout = true; get.path = "/api/bus/objects" + api_path + "/"; get.query["bucket"] = get_bucket(get_sia_config()); + get.query["delimiter"] = "/"; std::string error_data; get.response_handler = [&error_data, &object_list](auto &&data, @@ -405,7 +460,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t { try { curl::requests::http_get get{}; get.allow_timeout = true; - get.path = "/api/autopilot/config"; + get.path = "/api/bus/autopilot"; get.query["bucket"] = get_bucket(get_sia_config()); json config_data; @@ -455,17 +510,18 @@ auto sia_provider::is_directory(const std::string &api_path, bool &exists) const exists = false; - json object_list{}; - if (not get_object_list(utils::path::get_parent_api_path(api_path), - object_list)) { - return api_error::comm_error; + json file_data{}; + auto res{get_object_info(api_path + '/', file_data)}; + if (res == api_error::item_not_found) { + return api_error::success; } - exists = object_list.contains("entries") && - std::ranges::find_if(object_list.at("entries"), - [&api_path](auto &&entry) -> bool { - return entry.at("name") == (api_path + "/"); - }) != object_list.at("entries").end(); + if (res != api_error::success) { + return res; + } + + exists = + utils::string::ends_with(file_data.at("key").get(), "/"); return api_error::success; } catch (const std::exception &e) { utils::error::raise_api_path_error( @@ -481,6 +537,7 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const try { exists = false; + if (api_path == "/") { return api_error::success; } @@ -495,7 +552,8 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const return res; } - exists = not file_data.contains("entries"); + exists = not utils::string::ends_with( + file_data.at("key").get(), "/"); return api_error::success; } catch (const std::exception &e) { utils::error::raise_api_path_error(function_name, api_path, e, @@ -559,8 +617,9 @@ auto sia_provider::read_file_bytes(const std::string &api_path, try { curl::requests::http_get get{}; - get.path = "/api/worker/objects" + api_path; + get.path = "/api/worker/object" + api_path; get.query["bucket"] = get_bucket(get_sia_config()); + get.headers["accept"] = "application/octet-stream"; get.range = {{ offset, offset + size - 1U, @@ -577,6 +636,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path, ++idx) { long response_code{}; const auto notify_retry = [&]() { + fmt::println("{}", std::string(buffer.begin(), buffer.end())); if (response_code == 0) { utils::error::raise_api_path_error( function_name, api_path, api_error::comm_error, @@ -622,7 +682,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path) curl::requests::http_delete del{}; del.allow_timeout = true; - del.path = "/api/bus/objects" + api_path + "/"; + del.path = "/api/bus/object" + api_path + "/"; del.query["bucket"] = get_bucket(get_sia_config()); std::string error_data; @@ -658,7 +718,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error { curl::requests::http_delete del{}; del.allow_timeout = true; - del.path = "/api/bus/objects" + api_path; + del.path = "/api/bus/object" + api_path; del.query["bucket"] = get_bucket(get_sia_config()); std::string error_data; @@ -697,12 +757,12 @@ auto sia_provider::rename_file(const std::string &from_api_path, try { curl::requests::http_post post{}; post.json = nlohmann::json({ + {"bucket", get_bucket(get_sia_config())}, {"from", from_api_path}, {"to", to_api_path}, {"mode", "single"}, }); post.path = "/api/bus/objects/rename"; - post.query["bucket"] = get_bucket(get_sia_config()); std::string error_data; post.response_handler = [&error_data](auto &&data, long response_code) { @@ -770,8 +830,9 @@ auto sia_provider::upload_file_impl(const std::string &api_path, REPERTORY_USES_FUNCTION_NAME(); curl::requests::http_put_file put_file{}; - put_file.path = "/api/worker/objects" + api_path; + put_file.path = "/api/worker/object" + api_path; put_file.query["bucket"] = get_bucket(get_sia_config()); + put_file.headers["content-type"] = "application/octet-stream"; put_file.source_path = source_path; std::string error_data; diff --git a/repertory/librepertory/src/utils/polling.cpp b/repertory/librepertory/src/utils/polling.cpp index 127f109e..572a9bf5 100644 --- a/repertory/librepertory/src/utils/polling.cpp +++ b/repertory/librepertory/src/utils/polling.cpp @@ -38,47 +38,58 @@ void polling::frequency_thread( std::function get_frequency_seconds, frequency freq) { REPERTORY_USES_FUNCTION_NAME(); + auto last_run = std::chrono::system_clock::time_point::min(); while (not get_stop_requested()) { - unique_mutex_lock lock(mutex_); - auto futures = std::accumulate( - items_.begin(), items_.end(), std::deque{}, - [this, &freq](auto &&list, auto &&item) -> auto { - if (item.second.freq != freq) { + auto elapsed = std::chrono::duration_cast( + std::chrono::system_clock::now() - last_run); + auto max_elapsed = std::chrono::seconds(get_frequency_seconds()); + + if (last_run == std::chrono::system_clock::time_point::min() || + elapsed >= max_elapsed) { + unique_mutex_lock lock(mutex_); + auto futures = std::accumulate( + items_.begin(), items_.end(), std::deque{}, + [this, &freq](auto &&list, auto &&item) -> auto { + if (item.second.freq != freq) { + return list; + } + + auto future = tasks::instance().schedule({ + [this, &freq, item](auto &&task_stopped) { + if (config_->get_event_level() == event_level::trace || + freq != frequency::second) { + event_system::instance().raise( + function_name, item.first); + } + item.second.action(task_stopped); + if (config_->get_event_level() == event_level::trace || + freq != frequency::second) { + event_system::instance().raise( + function_name, item.first); + } + }, + }); + + list.emplace_back(future); return list; - } - - auto future = tasks::instance().schedule({ - [this, &freq, item](auto &&task_stopped) { - if (config_->get_event_level() == event_level::trace || - freq != frequency::second) { - event_system::instance().raise( - function_name, item.first); - } - item.second.action(task_stopped); - if (config_->get_event_level() == event_level::trace || - freq != frequency::second) { - event_system::instance().raise( - function_name, item.first); - } - }, }); + lock.unlock(); - list.emplace_back(future); - return list; - }); - lock.unlock(); + while (not futures.empty()) { + futures.front()->wait(); + futures.pop_front(); + } - while (not futures.empty()) { - futures.front()->wait(); - futures.pop_front(); + last_run = std::chrono::system_clock::now(); + elapsed = std::chrono::seconds(0U); } + unique_mutex_lock lock(mutex_); if (get_stop_requested()) { return; } - lock.lock(); - notify_.wait_for(lock, std::chrono::seconds(get_frequency_seconds())); + notify_.wait_for(lock, max_elapsed - elapsed); } } diff --git a/repertory/repertory/include/cli/check_version.hpp b/repertory/repertory/include/cli/check_version.hpp index cc2d0ab4..8e15850f 100644 --- a/repertory/repertory/include/cli/check_version.hpp +++ b/repertory/repertory/include/cli/check_version.hpp @@ -23,50 +23,38 @@ #define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_ #include "app_config.hpp" +#include "comm/curl/curl_comm.hpp" +#include "providers/sia/sia_provider.hpp" #include "types/repertory.hpp" namespace repertory::cli::actions { -[[nodiscard]] inline auto -check_version(std::vector /* args */, - const std::string & /* data_directory */, - const provider_type & /* pt */, const std::string & /*unique_id*/, - std::string /*user*/, std::string /*password*/) -> exit_code { - auto ret = exit_code::success; +[[nodiscard]] inline auto check_version(std::vector /* args */, + const std::string &data_directory, + const provider_type &prov, + const std::string & /*unique_id*/, + std::string /*user*/, + std::string /*password*/) -> exit_code { + if (prov != provider_type::sia) { + fmt::println("Success:\n\tNo specific version is required for {} providers", + app_config::get_provider_display_name(prov)); + return exit_code::success; + } - // TODO need to updated way to check version - // if (not((pt == provider_type::remote) || (pt == provider_type::s3))) { - // app_config config(pt, data_directory); - // curl_comm comm(config); - // json data, err; - // - // if (comm.get("/daemon/version", data, err) == api_error::success) { - // const auto res = utils::compare_version_strings( - // data["version"].get(), - // app_config::get_provider_minimum_version(pt)); - // if (res < 0) { - // ret = exit_code::incompatible_version; - // std::cerr << "Failed!" << std::endl; - // std::cerr << " Actual: " << data["version"].get() - // << std::endl; - // std::cerr << " Minimum: " - // << app_config::get_provider_minimum_version(pt) << - // std::endl; - // } else { - // std::cout << "Success!" << std::endl; - // std::cout << " Actual: " << data["version"].get() - // << std::endl; - // std::cout << " Minimum: " - // << app_config::get_provider_minimum_version(pt) << - // std::endl; - // } - // } else { - // std::cerr << "Failed!" << std::endl; - // std::cerr << err.dump(2) << std::endl; - // ret = exit_code::communication_error; - // } - // } + app_config config(prov, data_directory); + curl_comm comm(config.get_host_config()); + sia_provider provider(config, comm); - return ret; + std::string required_version; + std::string returned_version; + if (provider.check_version(required_version, returned_version)) { + fmt::println("Success:\n\tRequired: {}\n\tActual: {}", required_version, + returned_version); + return exit_code::success; + } + + fmt::println("Failed:\n\tRequired: {}\n\tActual: {}", required_version, + returned_version); + return exit_code::incompatible_version; } } // namespace repertory::cli::actions diff --git a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp index a8298269..bd495be6 100644 --- a/repertory/repertory_test/include/fixtures/fuse_fixture.hpp +++ b/repertory/repertory_test/include/fixtures/fuse_fixture.hpp @@ -268,8 +268,8 @@ public: return file_path; } - static auto create_file_and_test(std::string &file_name, - mode_t perms) -> std::string { + static auto create_file_and_test(std::string &file_name, mode_t perms) + -> std::string { file_name += std::to_string(++provider_idx); auto file_path = utils::path::combine(mount_location, {file_name}); @@ -287,7 +287,7 @@ public: EXPECT_TRUE(utils::file::file(file_path).exists()); EXPECT_FALSE(utils::file::directory(file_path).exists()); - struct stat64 unix_st {}; + struct stat64 unix_st{}; EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st)); EXPECT_EQ(getgid(), unix_st.st_gid); EXPECT_EQ(getuid(), unix_st.st_uid); @@ -299,8 +299,8 @@ public: return create_file_and_test(file_name, ACCESSPERMS); } - static auto create_directory_and_test(std::string &dir_name, - mode_t perms) -> std::string { + static auto create_directory_and_test(std::string &dir_name, mode_t perms) + -> std::string { dir_name += std::to_string(++provider_idx); auto dir_path = utils::path::combine(mount_location, {dir_name}); @@ -309,7 +309,7 @@ public: EXPECT_TRUE(utils::file::directory(dir_path).exists()); EXPECT_FALSE(utils::file::file(dir_path).exists()); - struct stat64 unix_st {}; + struct stat64 unix_st{}; EXPECT_EQ(0, stat64(dir_path.c_str(), &unix_st)); EXPECT_EQ(getgid(), unix_st.st_gid); EXPECT_EQ(getuid(), unix_st.st_uid); @@ -410,9 +410,9 @@ std::string fuse_test::mount_location; template std::string fuse_test::mount_location2; -using fuse_provider_types = ::testing::Types; -// using fuse_provider_types = -// ::testing::Types; +// using fuse_provider_types = ::testing::Types; +using fuse_provider_types = + ::testing::Types; } // namespace repertory #endif // !defined(_WIN32) diff --git a/repertory/repertory_test/include/mocks/mock_provider.hpp b/repertory/repertory_test/include/mocks/mock_provider.hpp index ca8e28ba..98b2a05a 100644 --- a/repertory/repertory_test/include/mocks/mock_provider.hpp +++ b/repertory/repertory_test/include/mocks/mock_provider.hpp @@ -36,6 +36,10 @@ private: const bool allow_rename_; public: + MOCK_METHOD(bool, check_version, + (std::string & required_version, std::string &returned_version), + (const, override)); + MOCK_METHOD(api_error, create_directory, (const std::string &api_path, api_meta_map &meta), (override)); diff --git a/repertory/repertory_test/src/app_config_test.cpp b/repertory/repertory_test/src/app_config_test.cpp new file mode 100644 index 00000000..33d0809c --- /dev/null +++ b/repertory/repertory_test/src/app_config_test.cpp @@ -0,0 +1,763 @@ +/* + Copyright <2018-2025> + + 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/path.hpp" + +namespace repertory { +class app_config_test : public ::testing::Test { +public: + static std::atomic idx; + + std::string encrypt_directory; + std::string remote_directory; + std::string s3_directory; + std::string sia_directory; + + void SetUp() override { + encrypt_directory = utils::path::combine(test::get_test_output_dir(), + { + "app_config_test", + "encrypt", + std::to_string(++idx), + }); + + remote_directory = utils::path::combine(test::get_test_output_dir(), + { + "app_config_test", + "remote", + std::to_string(++idx), + }); + + s3_directory = utils::path::combine(test::get_test_output_dir(), + { + "app_config_test", + "s3", + std::to_string(++idx), + }); + + sia_directory = utils::path::combine(test::get_test_output_dir(), + { + "app_config_test", + "sia", + std::to_string(++idx), + }); + } +}; + +static void remove_unused_types(auto &data, provider_type prov) { + switch (prov) { + case provider_type::encrypt: + data.erase(JSON_DOWNLOAD_TIMEOUT_SECS); + data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT); + data.erase(JSON_EVICTION_DELAY_MINS); + data.erase(JSON_EVICTION_USE_ACCESS_TIME); + data.erase(JSON_HOST_CONFIG); + data.erase(JSON_MAX_CACHE_SIZE_BYTES); + data.erase(JSON_MAX_UPLOAD_COUNT); + data.erase(JSON_ONLINE_CHECK_RETRY_SECS); + data.erase(JSON_PREFERRED_DOWNLOAD_TYPE); + data.erase(JSON_REMOTE_CONFIG); + data.erase(JSON_RETRY_READ_COUNT); + data.erase(JSON_RING_BUFFER_FILE_SIZE); + data.erase(JSON_S3_CONFIG); + data.erase(JSON_SIA_CONFIG); + break; + + case provider_type::remote: + data.erase(JSON_DATABASE_TYPE); + data.erase(JSON_DOWNLOAD_TIMEOUT_SECS); + data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT); + data.erase(JSON_ENCRYPT_CONFIG); + data.erase(JSON_EVICTION_DELAY_MINS); + data.erase(JSON_EVICTION_USE_ACCESS_TIME); + data.erase(JSON_HIGH_FREQ_INTERVAL_SECS); + data.erase(JSON_HOST_CONFIG); + data.erase(JSON_LOW_FREQ_INTERVAL_SECS); + data.erase(JSON_MAX_CACHE_SIZE_BYTES); + data.erase(JSON_MAX_UPLOAD_COUNT); + data.erase(JSON_MED_FREQ_INTERVAL_SECS); + data.erase(JSON_ONLINE_CHECK_RETRY_SECS); + data.erase(JSON_PREFERRED_DOWNLOAD_TYPE); + data.erase(JSON_REMOTE_MOUNT); + data.erase(JSON_RETRY_READ_COUNT); + data.erase(JSON_RING_BUFFER_FILE_SIZE); + data.erase(JSON_S3_CONFIG); + data.erase(JSON_SIA_CONFIG); + break; + + case provider_type::s3: + data.erase(JSON_ENCRYPT_CONFIG); + data.erase(JSON_HOST_CONFIG); + data.erase(JSON_REMOTE_CONFIG); + data.erase(JSON_SIA_CONFIG); + break; + + case provider_type::sia: + data.erase(JSON_ENCRYPT_CONFIG); + data.erase(JSON_REMOTE_CONFIG); + data.erase(JSON_S3_CONFIG); + break; + + default: + return; + } +} + +std::atomic app_config_test::idx{0U}; + +static void defaults_tests(const json &json_data, provider_type prov) { + json json_defaults = { + {JSON_API_PORT, app_config::default_rpc_port(prov)}, + {JSON_API_USER, std::string{REPERTORY}}, + {JSON_DOWNLOAD_TIMEOUT_SECS, default_download_timeout_secs}, + {JSON_DATABASE_TYPE, database_type::rocksdb}, + {JSON_ENABLE_DOWNLOAD_TIMEOUT, true}, + {JSON_ENABLE_DRIVE_EVENTS, false}, +#if defined(_WIN32) + {JSON_ENABLE_MOUNT_MANAGER, false}, +#endif // defined(_WIN32) + {JSON_ENCRYPT_CONFIG, encrypt_config{}}, + {JSON_EVENT_LEVEL, event_level::info}, + {JSON_EVICTION_DELAY_MINS, default_eviction_delay_mins}, + {JSON_EVICTION_USE_ACCESS_TIME, false}, + {JSON_HIGH_FREQ_INTERVAL_SECS, default_high_freq_interval_secs}, + {JSON_HOST_CONFIG, host_config{}}, + {JSON_LOW_FREQ_INTERVAL_SECS, default_low_freq_interval_secs}, + {JSON_MAX_CACHE_SIZE_BYTES, default_max_cache_size_bytes}, + {JSON_MAX_UPLOAD_COUNT, default_max_upload_count}, + {JSON_MED_FREQ_INTERVAL_SECS, default_med_freq_interval_secs}, + {JSON_ONLINE_CHECK_RETRY_SECS, default_online_check_retry_secs}, + {JSON_PREFERRED_DOWNLOAD_TYPE, download_type::default_}, + {JSON_REMOTE_CONFIG, remote::remote_config{}}, + {JSON_REMOTE_MOUNT, remote::remote_mount{}}, + {JSON_RETRY_READ_COUNT, default_retry_read_count}, + {JSON_RING_BUFFER_FILE_SIZE, default_ring_buffer_file_size}, + {JSON_S3_CONFIG, s3_config{}}, + {JSON_SIA_CONFIG, sia_config{}}, + {JSON_TASK_WAIT_MS, default_task_wait_ms}, + {JSON_VERSION, REPERTORY_CONFIG_VERSION}, + }; + + remove_unused_types(json_defaults, prov); + + switch (prov) { + case provider_type::encrypt: + json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] = + app_config::default_remote_api_port(prov); + break; + + json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] = + app_config::default_remote_api_port(prov); + break; + + case provider_type::sia: + json_defaults[JSON_HOST_CONFIG][JSON_API_PORT] = + app_config::default_api_port(prov); + json_defaults[JSON_HOST_CONFIG][JSON_AGENT_STRING] = + app_config::default_agent_name(prov); + json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] = + app_config::default_remote_api_port(prov); + break; + + default: + return; + } + + fmt::println("testing default|{}-{}", app_config::get_provider_name(prov), + JSON_API_AUTH); + ASSERT_EQ(std::size_t(default_api_auth_size), + json_data.at(JSON_API_AUTH).get().size()); + for (const auto &[key, value] : json_defaults.items()) { + fmt::println("testing default|{}-{}", app_config::get_provider_name(prov), + key); + EXPECT_EQ(value, json_data.at(key)); + } +} + +template +static void test_getter_setter(app_config &cfg, get_t getter, set_t setter, + val_t val1, val_t val2, const std::string &key, + const std::string &val_str) { + (cfg.*setter)(val1); + ASSERT_TRUE((cfg.*getter)() == val1); + + (cfg.*setter)(val2); + ASSERT_TRUE((cfg.*getter)() == val2); + + if (key.empty()) { + return; + } + + EXPECT_STREQ(val_str.c_str(), cfg.set_value_by_name(key, val_str).c_str()); +} + +static void common_tests(app_config &config, provider_type prov) { + ASSERT_EQ(config.get_provider_type(), prov); + + std::map> methods{ + {JSON_API_AUTH, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_api_auth, + &app_config::set_api_auth, "", "auth", + JSON_API_AUTH, "auth2"); + }}, + {JSON_API_PORT, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_api_port, + &app_config::set_api_port, std::uint16_t{0U}, + std::uint16_t{1024U}, JSON_API_PORT, "1025"); + }}, + {JSON_API_USER, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_api_user, + &app_config::set_api_user, "", "user", + JSON_API_USER, "user2"); + }}, + {JSON_DOWNLOAD_TIMEOUT_SECS, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_download_timeout_secs, + &app_config::set_download_timeout_secs, + std::uint8_t{min_download_timeout_secs + 1U}, + std::uint8_t{min_download_timeout_secs + 2U}, + JSON_DOWNLOAD_TIMEOUT_SECS, + std::to_string(min_download_timeout_secs + 2U)); + + cfg.set_download_timeout_secs(min_download_timeout_secs - 1U); + EXPECT_EQ(min_download_timeout_secs, cfg.get_download_timeout_secs()); + }}, + {JSON_DATABASE_TYPE, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_database_type, + &app_config::set_database_type, + database_type::rocksdb, database_type::sqlite, + JSON_DATABASE_TYPE, "rocksdb"); + }}, + {JSON_ENABLE_DOWNLOAD_TIMEOUT, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_enable_download_timeout, + &app_config::set_enable_download_timeout, true, + false, JSON_ENABLE_DOWNLOAD_TIMEOUT, "1"); + }}, + {JSON_ENABLE_DRIVE_EVENTS, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_enable_drive_events, + &app_config::set_enable_drive_events, true, false, + JSON_ENABLE_DRIVE_EVENTS, "1"); + }}, +#if defined(_WIN32) + {JSON_ENABLE_MOUNT_MANAGER, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_enable_mount_manager, + &app_config::set_enable_mount_manager, true, false, + JSON_ENABLE_MOUNT_MANAGER, "1"); + }}, +#endif // defined(_WIN32) + {JSON_ENCRYPT_CONFIG, + [](app_config &cfg) { + encrypt_config cfg1{}; + cfg1.encryption_token = "1"; + cfg1.path = "2"; + + encrypt_config cfg2{}; + cfg2.encryption_token = "2"; + cfg2.path = "1"; + + ASSERT_NE(cfg1, cfg2); + test_getter_setter(cfg, &app_config::get_encrypt_config, + &app_config::set_encrypt_config, cfg1, cfg2, "", + ""); + + encrypt_config cfg3{}; + cfg3.encryption_token = "3"; + cfg3.path = "4"; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN), + cfg3.encryption_token); + EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_PATH), cfg3.path); + EXPECT_STREQ(cfg3.path.c_str(), value.c_str()); + }}, + {JSON_EVENT_LEVEL, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_event_level, + &app_config::set_event_level, event_level::critical, + event_level::debug, JSON_EVENT_LEVEL, "info"); + }}, + {JSON_EVICTION_DELAY_MINS, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_eviction_delay_mins, + &app_config::set_eviction_delay_mins, + std::uint32_t{0U}, std::uint32_t{1U}, + JSON_EVICTION_DELAY_MINS, "2"); + }}, + {JSON_EVICTION_USE_ACCESS_TIME, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_eviction_uses_accessed_time, + &app_config::set_eviction_uses_accessed_time, true, + false, JSON_EVICTION_USE_ACCESS_TIME, "1"); + }}, + {JSON_HIGH_FREQ_INTERVAL_SECS, + [](app_config &cfg) { + test_getter_setter( + cfg, &app_config::get_high_frequency_interval_secs, + &app_config::set_high_frequency_interval_secs, + std::uint16_t{default_high_freq_interval_secs + 1U}, + std::uint16_t{default_high_freq_interval_secs + 2U}, + JSON_HIGH_FREQ_INTERVAL_SECS, + std::to_string(default_high_freq_interval_secs + 3U)); + + cfg.set_high_frequency_interval_secs(0U); + EXPECT_EQ(1U, cfg.get_high_frequency_interval_secs()); + }}, + {JSON_HOST_CONFIG, + [](app_config &cfg) { + host_config cfg1{}; + cfg1.agent_string = "1"; + cfg1.api_password = "2"; + cfg1.api_user = "3"; + cfg1.api_port = 4U; + cfg1.host_name_or_ip = "5"; + cfg1.path = "6"; + cfg1.protocol = "http"; + cfg1.timeout_ms = 8U; + + host_config cfg2{}; + cfg2.agent_string = "9"; + cfg2.api_password = "10"; + cfg2.api_user = "11"; + cfg2.api_port = 12U; + cfg2.host_name_or_ip = "13"; + cfg2.path = "14"; + cfg2.protocol = "https"; + cfg2.timeout_ms = 16U; + + ASSERT_NE(cfg1, cfg2); + + test_getter_setter(cfg, &app_config::get_host_config, + &app_config::set_host_config, cfg1, cfg2, "", ""); + + host_config cfg3{}; + cfg3.agent_string = "17"; + cfg3.api_password = "18"; + cfg3.api_user = "19"; + cfg3.api_port = 20U; + cfg3.host_name_or_ip = "21"; + cfg3.path = "22"; + cfg3.protocol = "http"; + cfg3.timeout_ms = 24; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_AGENT_STRING), + cfg3.agent_string); + EXPECT_STREQ(cfg3.agent_string.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD), + cfg3.api_password); + EXPECT_STREQ(cfg3.api_password.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER), + cfg3.api_user); + EXPECT_STREQ(cfg3.api_user.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT), + std::to_string(cfg3.api_port)); + EXPECT_STREQ(std::to_string(cfg3.api_port).c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP), + cfg3.host_name_or_ip); + EXPECT_STREQ(cfg3.host_name_or_ip.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH), cfg3.path); + EXPECT_STREQ(cfg3.path.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL), + cfg3.protocol); + EXPECT_STREQ(cfg3.protocol.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS), + std::to_string(cfg3.timeout_ms)); + EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str()); + }}, + {JSON_LOW_FREQ_INTERVAL_SECS, + [](app_config &cfg) { + test_getter_setter( + cfg, &app_config::get_low_frequency_interval_secs, + &app_config::set_low_frequency_interval_secs, + std::uint16_t{default_low_freq_interval_secs + 1U}, + std::uint16_t{default_low_freq_interval_secs + 2U}, + JSON_LOW_FREQ_INTERVAL_SECS, + std::to_string(default_low_freq_interval_secs + 3U)); + + cfg.set_low_frequency_interval_secs(0U); + EXPECT_EQ(1U, cfg.get_low_frequency_interval_secs()); + }}, + {JSON_MAX_CACHE_SIZE_BYTES, + [](app_config &cfg) { + test_getter_setter( + cfg, &app_config::get_max_cache_size_bytes, + &app_config::set_max_cache_size_bytes, min_cache_size_bytes + 1U, + min_cache_size_bytes + 2U, JSON_MAX_CACHE_SIZE_BYTES, + std::to_string(min_cache_size_bytes + 3U)); + + cfg.set_max_cache_size_bytes(min_cache_size_bytes - 1U); + EXPECT_EQ(min_cache_size_bytes, cfg.get_max_cache_size_bytes()); + }}, + {JSON_MAX_UPLOAD_COUNT, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_max_upload_count, + &app_config::set_max_upload_count, std::uint8_t{1U}, + std::uint8_t{2U}, JSON_MAX_UPLOAD_COUNT, "3"); + + cfg.set_max_upload_count(0U); + EXPECT_EQ(1U, cfg.get_max_upload_count()); + }}, + {JSON_MED_FREQ_INTERVAL_SECS, + [](app_config &cfg) { + test_getter_setter( + cfg, &app_config::get_med_frequency_interval_secs, + &app_config::set_med_frequency_interval_secs, + std::uint16_t{default_med_freq_interval_secs + 1U}, + std::uint16_t{default_med_freq_interval_secs + 2U}, + JSON_MED_FREQ_INTERVAL_SECS, + std::to_string(default_med_freq_interval_secs + 3U)); + + cfg.set_med_frequency_interval_secs(0U); + EXPECT_EQ(1U, cfg.get_med_frequency_interval_secs()); + }}, + {JSON_ONLINE_CHECK_RETRY_SECS, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_online_check_retry_secs, + &app_config::set_online_check_retry_secs, + std::uint16_t{min_online_check_retry_secs + 1U}, + std::uint16_t{min_online_check_retry_secs + 2U}, + JSON_ONLINE_CHECK_RETRY_SECS, + std::to_string(min_online_check_retry_secs + 3U)); + + cfg.set_online_check_retry_secs(min_online_check_retry_secs - 1U); + EXPECT_EQ(min_online_check_retry_secs, + cfg.get_online_check_retry_secs()); + }}, + {JSON_PREFERRED_DOWNLOAD_TYPE, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_preferred_download_type, + &app_config::set_preferred_download_type, + download_type::direct, download_type::default_, + JSON_PREFERRED_DOWNLOAD_TYPE, "ring_buffer"); + }}, + {JSON_REMOTE_CONFIG, + [](app_config &cfg) { + remote::remote_config remote_cfg1{}; + remote_cfg1.api_port = 1U; + remote_cfg1.encryption_token = "2"; + remote_cfg1.host_name_or_ip = "3"; + remote_cfg1.max_connections = 4U; + remote_cfg1.recv_timeout_ms = 5U; + remote_cfg1.send_timeout_ms = 6U; + + remote::remote_config remote_cfg2{}; + remote_cfg1.api_port = 6U; + remote_cfg1.encryption_token = "5"; + remote_cfg1.host_name_or_ip = "4"; + remote_cfg1.max_connections = 3U; + remote_cfg1.recv_timeout_ms = 2U; + remote_cfg1.send_timeout_ms = 1U; + + ASSERT_NE(remote_cfg1, remote_cfg2); + + test_getter_setter(cfg, &app_config::get_remote_config, + &app_config::set_remote_config, remote_cfg1, + remote_cfg2, "", ""); + + remote::remote_config remote_cfg3{}; + remote_cfg1.api_port = 7U; + remote_cfg1.encryption_token = "8"; + remote_cfg1.host_name_or_ip = "9"; + remote_cfg1.max_connections = 10U; + remote_cfg1.recv_timeout_ms = 11U; + remote_cfg1.send_timeout_ms = 12U; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_API_PORT), + std::to_string(remote_cfg3.api_port)); + EXPECT_STREQ(std::to_string(remote_cfg3.api_port).c_str(), + value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN), + remote_cfg3.encryption_token); + EXPECT_STREQ(remote_cfg3.encryption_token.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_HOST_NAME_OR_IP), + remote_cfg3.host_name_or_ip); + EXPECT_STREQ(remote_cfg3.host_name_or_ip.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_MAX_CONNECTIONS), + std::to_string(remote_cfg3.max_connections)); + EXPECT_STREQ(std::to_string(remote_cfg3.max_connections).c_str(), + value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_RECV_TIMEOUT_MS), + std::to_string(remote_cfg3.recv_timeout_ms)); + EXPECT_STREQ(std::to_string(remote_cfg3.recv_timeout_ms).c_str(), + value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_SEND_TIMEOUT_MS), + std::to_string(remote_cfg3.send_timeout_ms)); + EXPECT_STREQ(std::to_string(remote_cfg3.send_timeout_ms).c_str(), + value.c_str()); + }}, + {JSON_REMOTE_MOUNT, + [](app_config &cfg) { + remote::remote_mount mnt_cfg1{}; + mnt_cfg1.api_port = 1U; + mnt_cfg1.client_pool_size = 2U; + mnt_cfg1.enable = false; + mnt_cfg1.encryption_token = "3"; + + remote::remote_mount mnt_cfg2{}; + mnt_cfg2.api_port = 3U; + mnt_cfg2.client_pool_size = 4U; + mnt_cfg2.enable = true; + mnt_cfg2.encryption_token = "5"; + + ASSERT_NE(mnt_cfg1, mnt_cfg2); + + test_getter_setter(cfg, &app_config::get_remote_mount, + &app_config::set_remote_mount, mnt_cfg1, mnt_cfg2, + "", ""); + + remote::remote_mount mnt_cfg3{}; + mnt_cfg3.api_port = 9U; + mnt_cfg3.client_pool_size = 10U; + mnt_cfg3.enable = false; + mnt_cfg3.encryption_token = "11"; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_API_PORT), + std::to_string(mnt_cfg3.api_port)); + EXPECT_STREQ(std::to_string(mnt_cfg3.api_port).c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_CLIENT_POOL_SIZE), + std::to_string(mnt_cfg3.client_pool_size)); + EXPECT_STREQ(std::to_string(mnt_cfg3.client_pool_size).c_str(), + value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENABLE_REMOTE_MOUNT), + utils::string::from_bool(mnt_cfg3.enable)); + EXPECT_STREQ(utils::string::from_bool(mnt_cfg3.enable).c_str(), + value.c_str()); + }}, + {JSON_RETRY_READ_COUNT, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_retry_read_count, + &app_config::set_retry_read_count, + std::uint16_t{min_retry_read_count + 1U}, + std::uint16_t{min_retry_read_count + 2U}, + JSON_RETRY_READ_COUNT, + std::to_string(min_retry_read_count + 3U)); + + cfg.set_retry_read_count(min_retry_read_count - 1U); + EXPECT_EQ(min_retry_read_count, cfg.get_retry_read_count()); + }}, + {JSON_RING_BUFFER_FILE_SIZE, + [](app_config &cfg) { + test_getter_setter(cfg, &app_config::get_ring_buffer_file_size, + &app_config::set_ring_buffer_file_size, + std::uint16_t{min_ring_buffer_file_size + 1U}, + std::uint16_t{min_ring_buffer_file_size + 2U}, + JSON_RING_BUFFER_FILE_SIZE, + std::to_string(min_ring_buffer_file_size + 3U)); + + cfg.set_ring_buffer_file_size(min_ring_buffer_file_size - 1U); + EXPECT_EQ(min_ring_buffer_file_size, cfg.get_ring_buffer_file_size()); + + cfg.set_ring_buffer_file_size(max_ring_buffer_file_size + 1U); + EXPECT_EQ(max_ring_buffer_file_size, cfg.get_ring_buffer_file_size()); + }}, + {JSON_S3_CONFIG, + [](auto &&cfg) { + s3_config cfg1{}; + cfg1.access_key = "1"; + cfg1.bucket = "2"; + cfg1.encryption_token = "3"; + cfg1.region = "4"; + cfg1.secret_key = "5"; + cfg1.timeout_ms = 6U; + cfg1.url = "7"; + cfg1.use_path_style = false; + cfg1.use_region_in_url = false; + + s3_config cfg2{}; + cfg2.access_key = "8"; + cfg2.bucket = "9"; + cfg2.encryption_token = "10"; + cfg2.region = "11"; + cfg2.secret_key = "12"; + cfg2.timeout_ms = 13U; + cfg2.url = "14"; + cfg2.use_path_style = true; + cfg2.use_region_in_url = true; + + ASSERT_NE(cfg1, cfg2); + + test_getter_setter(cfg, &app_config::get_s3_config, + &app_config::set_s3_config, cfg1, cfg2, "", ""); + + s3_config cfg3{}; + cfg3.access_key = "8"; + cfg3.bucket = "9"; + cfg3.encryption_token = "10"; + cfg3.region = "11"; + cfg3.secret_key = "12"; + cfg3.timeout_ms = 13U; + cfg3.url = "14"; + cfg3.use_path_style = true; + cfg3.use_region_in_url = true; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ACCESS_KEY), + cfg3.access_key); + EXPECT_STREQ(cfg3.access_key.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_BUCKET), cfg3.bucket); + EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN), + cfg3.encryption_token); + EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_REGION), cfg3.region); + EXPECT_STREQ(cfg3.region.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY), + cfg3.secret_key); + EXPECT_STREQ(cfg3.secret_key.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_TIMEOUT_MS), + std::to_string(cfg3.timeout_ms)); + EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_URL), cfg3.url); + EXPECT_STREQ(cfg3.url.c_str(), value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_PATH_STYLE), + utils::string::from_bool(cfg3.use_path_style)); + EXPECT_STREQ(utils::string::from_bool(cfg3.use_path_style).c_str(), + value.c_str()); + + value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_REGION_IN_URL), + utils::string::from_bool(cfg3.use_region_in_url)); + EXPECT_STREQ(utils::string::from_bool(cfg3.use_region_in_url).c_str(), + value.c_str()); + }}, + {JSON_SIA_CONFIG, + [](app_config &cfg) { + sia_config cfg1{}; + cfg1.bucket = "1"; + + sia_config cfg2{}; + cfg2.bucket = "2"; + + ASSERT_NE(cfg1, cfg2); + + test_getter_setter(cfg, &app_config::get_sia_config, + &app_config::set_sia_config, cfg1, cfg2, "", ""); + + sia_config cfg3{}; + cfg3.bucket = "3"; + + auto value = cfg.set_value_by_name( + fmt::format("{}.{}", JSON_SIA_CONFIG, JSON_BUCKET), cfg3.bucket); + EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str()); + }}, + {JSON_TASK_WAIT_MS, + [](app_config &cfg) { + test_getter_setter( + cfg, &app_config::get_task_wait_ms, &app_config::set_task_wait_ms, + std::uint16_t{min_task_wait_ms + 1U}, + std::uint16_t{min_task_wait_ms + 2U}, JSON_TASK_WAIT_MS, + std::to_string(min_task_wait_ms + 3U)); + + cfg.set_task_wait_ms(min_task_wait_ms - 1U); + EXPECT_EQ(min_task_wait_ms, cfg.get_task_wait_ms()); + }}, + }; + + remove_unused_types(methods, prov); + + for (const auto &[key, test_function] : methods) { + fmt::println("testing setting|{}-{}", app_config::get_provider_name(prov), + key); + test_function(config); + } +} + +TEST_F(app_config_test, encrypt_config) { + app_config config(provider_type::encrypt, encrypt_directory); + defaults_tests(config.get_json(), provider_type::encrypt); + common_tests(config, provider_type::encrypt); +} + +TEST_F(app_config_test, remote_config) { + app_config config(provider_type::remote, remote_directory); + defaults_tests(config.get_json(), provider_type::remote); + common_tests(config, provider_type::remote); +} + +TEST_F(app_config_test, s3_config) { + app_config config(provider_type::s3, s3_directory); + defaults_tests(config.get_json(), provider_type::s3); + common_tests(config, provider_type::s3); +} + +TEST_F(app_config_test, sia_config) { + app_config config(provider_type::sia, sia_directory); + defaults_tests(config.get_json(), provider_type::sia); + common_tests(config, provider_type::sia); +} +} // namespace repertory diff --git a/repertory/repertory_test/src/atomic_test.cpp b/repertory/repertory_test/src/atomic_test.cpp index 58df0484..c79aba3c 100644 --- a/repertory/repertory_test/src/atomic_test.cpp +++ b/repertory/repertory_test/src/atomic_test.cpp @@ -24,7 +24,7 @@ #include "types/repertory.hpp" namespace repertory { -TEST(atomic, atomic_primitive) { +TEST(atomic_test, atomic_primitive) { atomic value; value = 5U; EXPECT_EQ(5U, static_cast(value)); @@ -35,7 +35,7 @@ TEST(atomic, atomic_primitive) { EXPECT_EQ(6U, value.load()); } -TEST(atomic, atomic_primitive_equality) { +TEST(atomic_test, atomic_primitive_equality) { atomic value1{5U}; atomic value2{5U}; EXPECT_EQ(value1, value1); @@ -45,7 +45,7 @@ TEST(atomic, atomic_primitive_equality) { EXPECT_EQ(static_cast(value2), 5U); } -TEST(atomic, atomic_primitive_inequality) { +TEST(atomic_test, atomic_primitive_inequality) { atomic value1{5U}; atomic value2{6U}; EXPECT_NE(value1, value2); @@ -53,7 +53,7 @@ TEST(atomic, atomic_primitive_inequality) { EXPECT_NE(static_cast(value2), 5U); } -TEST(atomic, atomic_struct) { +TEST(atomic_test, atomic_struct) { atomic value{ encrypt_config{ .encryption_token = "token", diff --git a/repertory/repertory_test/src/config_test.cpp b/repertory/repertory_test/src/config_test.cpp deleted file mode 100644 index 2cd440a8..00000000 --- a/repertory/repertory_test/src/config_test.cpp +++ /dev/null @@ -1,696 +0,0 @@ -/* - Copyright <2018-2025> - - 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 "events/event_system.hpp" -#include "utils/common.hpp" -#include "utils/file_utils.hpp" -#include "utils/path.hpp" - -namespace repertory { -class config_test : public ::testing::Test { -public: - console_consumer cs; - - static std::atomic idx; - - std::string s3_directory; - std::string sia_directory; - - void SetUp() override { - s3_directory = utils::path::combine(test::get_test_output_dir(), - { - "config_test", - "s3", - std::to_string(++idx), - }); - - sia_directory = utils::path::combine(test::get_test_output_dir(), - { - "config_test", - "sia", - std::to_string(++idx), - }); - event_system::instance().start(); - } - - void TearDown() override { - event_system::instance().stop(); - } -}; - -std::atomic config_test::idx{0U}; - -TEST_F(config_test, api_path) { - std::string original_value; - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - EXPECT_EQ(original_value.substr(0, 2), config.get_api_user()); - } -} - -TEST_F(config_test, download_timeout_secs) { - std::uint8_t original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_download_timeout_secs(); - config.set_download_timeout_secs(original_value + 5); - EXPECT_EQ(original_value + 5, config.get_download_timeout_secs()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(original_value + 5, config.get_download_timeout_secs()); - } -} - -TEST_F(config_test, enable_download_timeout) { - bool original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_enable_download_timeout(); - config.set_enable_download_timeout(not original_value); - EXPECT_EQ(not original_value, config.get_enable_download_timeout()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(not original_value, config.get_enable_download_timeout()); - } -} - -TEST_F(config_test, enable_drive_events) { - bool original_value{}; - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - EXPECT_EQ(not original_value, config.get_enable_drive_events()); - } -} - -#if defined(_WIN32) -TEST_F(config_test, enable_mount_manager) { - bool original_value; - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - EXPECT_EQ(not original_value, config.get_enable_mount_manager()); - } -} -#endif -TEST_F(config_test, event_level) { - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time()); - } -} - -TEST_F(config_test, high_frequency_interval_secs) { - std::uint16_t original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_high_frequency_interval_secs(); - config.set_high_frequency_interval_secs(original_value + 5U); - EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs()); - } -} - -TEST_F(config_test, low_frequency_interval_secs) { - std::uint16_t original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_low_frequency_interval_secs(); - config.set_low_frequency_interval_secs(original_value + 5U); - EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs()); - } -} - -TEST_F(config_test, med_frequency_interval_secs) { - std::uint16_t original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_med_frequency_interval_secs(); - config.set_med_frequency_interval_secs(original_value + 5U); - EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs()); - } -} - -TEST_F(config_test, max_cache_size_bytes) { - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes()); - } -} - -TEST_F(config_test, max_upload_count) { - { - app_config config(provider_type::sia, sia_directory); - config.set_max_upload_count(8U); - EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count()); - } - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - config.set_orphaned_file_retention_days(32); - EXPECT_EQ(31, config.get_orphaned_file_retention_days()); - } -} - -TEST_F(config_test, get_cache_directory) { - { - app_config config(provider_type::sia, sia_directory); - EXPECT_STREQ(utils::path::combine(sia_directory, {"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(sia_directory, {"config.json"})); - - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - EXPECT_STREQ(sia_directory.c_str(), config.get_data_directory().c_str()); - } -} - -TEST_F(config_test, get_log_directory) { - { - app_config config(provider_type::sia, sia_directory); - EXPECT_STREQ(utils::path::combine(sia_directory, {"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, sia_directory); - 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, sia_directory); - 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, sia_directory); - config.set_ring_buffer_file_size(63u); - EXPECT_EQ(64u, config.get_ring_buffer_file_size()); - } - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - config.set_ring_buffer_file_size(1025u); - EXPECT_EQ(1024u, config.get_ring_buffer_file_size()); - } - { - app_config config(provider_type::sia, sia_directory); - 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, sia_directory); - 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, sia_directory); - 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 data_directory = { - app_config::default_data_directory(provider_type::sia), - }; - -#if defined(_WIN32) - const auto local_app_data = utils::get_environment_variable("localappdata"); -#endif -#if defined(__linux__) - const auto local_app_data = - utils::path::combine(utils::get_environment_variable("HOME"), {".local"}); -#endif -#if defined(__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, sia_directory); - EXPECT_EQ(REPERTORY_CONFIG_VERSION, config.get_version()); - } -} - -// TEST_F(config_test, enable_remote_mount) { -// bool original_value{}; -// { -// app_config config(provider_type::sia, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// EXPECT_STREQ("my.host.name", -// config.get_remote_host_name_or_ip().c_str()); -// } -// } - -// TEST_F(config_test, remote_api_port) { -// std::uint16_t original_value{}; -// { -// app_config config(provider_type::sia, sia_directory); -// original_value = config.get_remote_api_port(); -// config.set_remote_api_port(original_value + 5); -// EXPECT_EQ(original_value + 5, config.get_remote_api_port()); -// } -// { -// app_config config(provider_type::sia, sia_directory); -// EXPECT_EQ(original_value + 5, config.get_remote_api_port()); -// } -// } - -// TEST_F(config_test, remote_receive_timeout_secs) { -// std::uint16_t original_value{}; -// { -// app_config config(provider_type::sia, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs()); -// } -// } - -// TEST_F(config_test, remote_encryption_token) { -// { -// app_config config(provider_type::sia, sia_directory); -// config.set_remote_encryption_token("myToken"); -// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str()); -// } -// { -// app_config config(provider_type::sia, sia_directory); -// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str()); -// } -// } -// -// TEST_F(config_test, remote_client_pool_size) { -// std::uint8_t original_value{}; -// { -// app_config config(provider_type::sia, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// config.set_remote_client_pool_size(0); -// EXPECT_EQ(5, config.get_remote_client_pool_size()); -// } -// { -// app_config config(provider_type::sia, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// 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, sia_directory); -// config.set_remote_max_connections(0); -// EXPECT_EQ(1, config.get_remote_max_connections()); -// } -// { -// app_config config(provider_type::sia, sia_directory); -// 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, sia_directory); - 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, sia_directory); - 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, sia_directory); - config.set_retry_read_count(1); - EXPECT_EQ(2, config.get_retry_read_count()); - } -} - -TEST_F(config_test, task_wait_ms) { - std::uint16_t original_value{}; - { - app_config config(provider_type::sia, sia_directory); - original_value = config.get_task_wait_ms(); - config.set_task_wait_ms(original_value + 1U); - EXPECT_EQ(original_value + 1U, config.get_task_wait_ms()); - } - { - app_config config(provider_type::sia, sia_directory); - EXPECT_EQ(original_value + 1U, config.get_task_wait_ms()); - } -} - -TEST_F(config_test, task_wait_ms_minimum_value) { - { - app_config config(provider_type::sia, sia_directory); - config.set_task_wait_ms(1U); - EXPECT_EQ(50U, config.get_task_wait_ms()); - } -} - -TEST_F(config_test, can_set_database_type) { - { - app_config config(provider_type::sia, sia_directory); - config.set_database_type(database_type::rocksdb); - EXPECT_EQ(database_type::rocksdb, config.get_database_type()); - - config.set_database_type(database_type::sqlite); - EXPECT_EQ(database_type::sqlite, config.get_database_type()); - - config.set_database_type(database_type::rocksdb); - EXPECT_EQ(database_type::rocksdb, config.get_database_type()); - } -} -} // namespace repertory diff --git a/repertory/repertory_test/src/curl_comm_test.cpp b/repertory/repertory_test/src/curl_comm_test.cpp index 30bb9be6..a2191635 100644 --- a/repertory/repertory_test/src/curl_comm_test.cpp +++ b/repertory/repertory_test/src/curl_comm_test.cpp @@ -25,7 +25,7 @@ #include "types/repertory.hpp" namespace repertory { -TEST(curl_comm, can_create_s3_host_config) { +TEST(curl_comm_test, can_create_s3_host_config) { s3_config config{}; config.bucket = "repertory"; config.url = "https://s3.test.com"; @@ -37,7 +37,7 @@ TEST(curl_comm, can_create_s3_host_config) { EXPECT_TRUE(hc.path.empty()); } -TEST(curl_comm, can_create_s3_host_config_with_path_style) { +TEST(curl_comm_test, can_create_s3_host_config_with_path_style) { s3_config config{}; config.bucket = "repertory"; config.url = "https://s3.test.com"; @@ -49,7 +49,7 @@ TEST(curl_comm, can_create_s3_host_config_with_path_style) { EXPECT_STREQ("/repertory", hc.path.c_str()); } -TEST(curl_comm, can_create_s3_host_config_with_region) { +TEST(curl_comm_test, can_create_s3_host_config_with_region) { s3_config config{}; config.bucket = "repertory"; config.url = "https://s3.test.com"; @@ -62,7 +62,7 @@ TEST(curl_comm, can_create_s3_host_config_with_region) { EXPECT_TRUE(hc.path.empty()); } -TEST(curl_comm, can_create_s3_host_config_with_region_and_path_style) { +TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) { s3_config config{}; config.bucket = "repertory"; config.url = "https://s3.test.com"; diff --git a/repertory/repertory_test/src/json_serialize_test.cpp b/repertory/repertory_test/src/json_serialize_test.cpp index e9e79105..d6d72989 100644 --- a/repertory/repertory_test/src/json_serialize_test.cpp +++ b/repertory/repertory_test/src/json_serialize_test.cpp @@ -25,7 +25,7 @@ #include "types/repertory.hpp" namespace repertory { -TEST(json_serialize, can_handle_directory_item) { +TEST(json_serialize_test, can_handle_directory_item) { directory_item cfg{ "api", "parent", true, 2U, {{META_DIRECTORY, "true"}}, }; @@ -47,7 +47,7 @@ TEST(json_serialize, can_handle_directory_item) { } } -TEST(json_serialize, can_handle_encrypt_config) { +TEST(json_serialize_test, can_handle_encrypt_config) { encrypt_config cfg{ "token", "path", @@ -65,7 +65,7 @@ TEST(json_serialize, can_handle_encrypt_config) { } } -TEST(json_serialize, can_handle_host_config) { +TEST(json_serialize_test, can_handle_host_config) { host_config cfg{ "agent", "pwd", "user", 1024U, "host", "path", "http", 11U, }; @@ -94,7 +94,7 @@ TEST(json_serialize, can_handle_host_config) { } } -TEST(json_serialize, can_handle_remote_config) { +TEST(json_serialize_test, can_handle_remote_config) { remote::remote_config cfg{ 1024U, "token", "host", 11U, 20U, 21U, }; @@ -120,7 +120,7 @@ TEST(json_serialize, can_handle_remote_config) { } } -TEST(json_serialize, can_handle_remote_mount) { +TEST(json_serialize_test, can_handle_remote_mount) { remote::remote_mount cfg{1024U, 21U, true, "token"}; json data(cfg); @@ -139,7 +139,7 @@ TEST(json_serialize, can_handle_remote_mount) { } } -TEST(json_serialize, can_handle_s3_config) { +TEST(json_serialize_test, can_handle_s3_config) { s3_config cfg{ "access", "bucket", "token", "region", "secret", 31U, "url", true, false, }; @@ -170,7 +170,7 @@ TEST(json_serialize, can_handle_s3_config) { } } -TEST(json_serialize, can_handle_sia_config) { +TEST(json_serialize_test, can_handle_sia_config) { sia_config cfg{ "bucket", }; @@ -184,7 +184,7 @@ TEST(json_serialize, can_handle_sia_config) { } } -TEST(json_serialize, can_handle_atomic) { +TEST(json_serialize_test, can_handle_atomic) { atomic cfg({ "bucket", }); @@ -198,7 +198,7 @@ TEST(json_serialize, can_handle_atomic) { } } -TEST(json_serialize, can_handle_database_type) { +TEST(json_serialize_test, can_handle_database_type) { json data(database_type::rocksdb); EXPECT_EQ(database_type::rocksdb, data.get()); EXPECT_STREQ("rocksdb", data.get().c_str()); @@ -208,7 +208,7 @@ TEST(json_serialize, can_handle_database_type) { EXPECT_STREQ("sqlite", data.get().c_str()); } -TEST(json_serialize, can_handle_download_type) { +TEST(json_serialize_test, can_handle_download_type) { json data(download_type::direct); EXPECT_EQ(download_type::direct, data.get()); EXPECT_STREQ("direct", data.get().c_str()); @@ -222,7 +222,33 @@ TEST(json_serialize, can_handle_download_type) { EXPECT_STREQ("ring_buffer", data.get().c_str()); } -TEST(json_serialize, can_handle_atomic_database_type) { +TEST(json_serialize_test, can_handle_event_level) { + json data(event_level{event_level::critical}); + EXPECT_EQ(event_level::critical, data.get()); + EXPECT_STREQ("critical", data.get().c_str()); + + data = event_level(event_level::error); + EXPECT_EQ(event_level::error, data.get()); + EXPECT_STREQ("error", data.get().c_str()); + + data = event_level(event_level::warn); + EXPECT_EQ(event_level::warn, data.get()); + EXPECT_STREQ("warn", data.get().c_str()); + + data = event_level(event_level::info); + EXPECT_EQ(event_level::info, data.get()); + EXPECT_STREQ("info", data.get().c_str()); + + data = event_level(event_level::debug); + EXPECT_EQ(event_level::debug, data.get()); + EXPECT_STREQ("debug", data.get().c_str()); + + data = event_level(event_level::trace); + EXPECT_EQ(event_level::trace, data.get()); + EXPECT_STREQ("trace", data.get().c_str()); +} + +TEST(json_serialize_test, can_handle_atomic_database_type) { json data(atomic{database_type::rocksdb}); EXPECT_EQ(database_type::rocksdb, data.get>()); EXPECT_STREQ("rocksdb", data.get().c_str()); @@ -232,7 +258,7 @@ TEST(json_serialize, can_handle_atomic_database_type) { EXPECT_STREQ("sqlite", data.get().c_str()); } -TEST(json_serialize, can_handle_atomic_download_type) { +TEST(json_serialize_test, can_handle_atomic_download_type) { json data(atomic{download_type::direct}); EXPECT_EQ(download_type::direct, data.get>()); EXPECT_STREQ("direct", data.get().c_str()); @@ -245,4 +271,30 @@ TEST(json_serialize, can_handle_atomic_download_type) { EXPECT_EQ(download_type::ring_buffer, data.get>()); EXPECT_STREQ("ring_buffer", data.get().c_str()); } + +TEST(json_serialize_test, can_handle_atomic_event_level) { + json data(atomic{event_level::critical}); + EXPECT_EQ(event_level::critical, data.get>()); + EXPECT_STREQ("critical", data.get().c_str()); + + data = atomic(event_level::error); + EXPECT_EQ(event_level::error, data.get>()); + EXPECT_STREQ("error", data.get().c_str()); + + data = atomic(event_level::warn); + EXPECT_EQ(event_level::warn, data.get>()); + EXPECT_STREQ("warn", data.get().c_str()); + + data = atomic(event_level::info); + EXPECT_EQ(event_level::info, data.get>()); + EXPECT_STREQ("info", data.get().c_str()); + + data = atomic(event_level::debug); + EXPECT_EQ(event_level::debug, data.get>()); + EXPECT_STREQ("debug", data.get().c_str()); + + data = atomic(event_level::trace); + EXPECT_EQ(event_level::trace, data.get>()); + EXPECT_STREQ("trace", data.get().c_str()); +} } // namespace repertory diff --git a/repertory/repertory_test/src/lock_data_test.cpp b/repertory/repertory_test/src/lock_data_test.cpp index 87186ef0..fd1fa9e3 100644 --- a/repertory/repertory_test/src/lock_data_test.cpp +++ b/repertory/repertory_test/src/lock_data_test.cpp @@ -24,7 +24,7 @@ #include "platform/platform.hpp" namespace repertory { -TEST(lock_data, lock_and_unlock) { +TEST(lock_data_test, lock_and_unlock) { { lock_data l(provider_type::sia, "1"); EXPECT_EQ(lock_result::success, l.grab_lock()); @@ -50,7 +50,7 @@ TEST(lock_data, lock_and_unlock) { } #if defined(_WIN32) -TEST(lock_data, set_and_unset_mount_state) { +TEST(lock_data_test, set_and_unset_mount_state) { lock_data l(provider_type::sia, "1"); EXPECT_TRUE(l.set_mount_state(true, "C:", 99)); @@ -83,7 +83,7 @@ TEST(lock_data, set_and_unset_mount_state) { mount_state["Remote2"].dump().c_str()); } #else -TEST(lock_data, set_and_unset_mount_state) { +TEST(lock_data_test, set_and_unset_mount_state) { lock_data l(provider_type::sia, "1"); EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99)); diff --git a/repertory/repertory_test/src/packet_test.cpp b/repertory/repertory_test/src/packet_test.cpp index 0a29dab2..73ef16a8 100644 --- a/repertory/repertory_test/src/packet_test.cpp +++ b/repertory/repertory_test/src/packet_test.cpp @@ -24,7 +24,7 @@ #include "comm/packet/packet.hpp" namespace repertory { -TEST(packet, encrypt_and_decrypt) { +TEST(packet_test, encrypt_and_decrypt) { packet test_packet; test_packet.encode("test"); test_packet.encrypt("moose"); diff --git a/repertory/repertory_test/src/providers_test.cpp b/repertory/repertory_test/src/providers_test.cpp index 0e1752d7..e99ebd29 100644 --- a/repertory/repertory_test/src/providers_test.cpp +++ b/repertory/repertory_test/src/providers_test.cpp @@ -19,8 +19,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if 0 - #include "test_common.hpp" #include "comm/curl/curl_comm.hpp" @@ -99,8 +97,6 @@ const auto create_directory = [](repertory::i_provider &provider, 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(repertory::utils::string::to_uint32( meta2[repertory::META_UID]))); EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64( @@ -178,6 +174,9 @@ const auto decrypt_parts = [](const repertory::app_config &cfg, namespace repertory { static void can_create_and_remove_directory(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { api_meta_map meta{}; EXPECT_EQ(api_error::not_implemented, @@ -196,6 +195,9 @@ static void can_create_and_remove_directory(i_provider &provider) { } static void create_directory_fails_if_already_exists(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -210,6 +212,9 @@ static void create_directory_fails_if_already_exists(i_provider &provider) { static void create_directory_fails_if_file_already_exists(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -223,6 +228,9 @@ create_directory_fails_if_file_already_exists(i_provider &provider) { } static void create_directory_clone_source_meta(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { EXPECT_EQ(api_error::not_implemented, provider.create_directory_clone_source_meta("/moose", "/moose")); @@ -257,6 +265,9 @@ static void create_directory_clone_source_meta(i_provider &provider) { static void create_directory_clone_source_meta_fails_if_already_exists( i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -272,6 +283,9 @@ static void create_directory_clone_source_meta_fails_if_already_exists( static void create_directory_clone_source_meta_fails_if_directory_not_found( i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -282,6 +296,9 @@ static void create_directory_clone_source_meta_fails_if_directory_not_found( static void create_directory_clone_source_meta_fails_if_file_already_exists( i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -297,6 +314,9 @@ static void create_directory_clone_source_meta_fails_if_file_already_exists( } static void can_create_and_remove_file(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { api_meta_map meta{}; EXPECT_EQ(api_error::not_implemented, @@ -317,6 +337,9 @@ static void can_create_and_remove_file(i_provider &provider) { } static void create_file_fails_if_already_exists(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -331,6 +354,9 @@ static void create_file_fails_if_already_exists(i_provider &provider) { static void create_file_fails_if_directory_already_exists(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.is_read_only()) { return; } @@ -345,9 +371,12 @@ create_file_fails_if_directory_already_exists(i_provider &provider) { static void get_api_path_from_source(const app_config &cfg, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.get_provider_type() == provider_type::encrypt) { - const auto source_path = - utils::path::combine("./test_date/encrypt", {"test.txt"}); + auto source_path = + utils::path::combine("./test_input/encrypt", {"test.txt"}); std::string api_path{}; EXPECT_EQ(api_error::success, @@ -376,6 +405,9 @@ static void get_api_path_from_source(const app_config &cfg, static void get_api_path_from_source_fails_if_file_not_found(const app_config &cfg, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); std::string source_path{}; if (provider.get_provider_type() == provider_type::encrypt) { source_path = utils::path::combine(cfg.get_encrypt_config().path, @@ -391,28 +423,50 @@ get_api_path_from_source_fails_if_file_not_found(const app_config &cfg, EXPECT_TRUE(api_path.empty()); } -static void get_directory_item_count(const app_config &cfg, +static void get_directory_item_count(const app_config & /* cfg */, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); 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 = + auto source_path = utils::path::combine(test::get_test_input_dir(), {"encrypt", "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)); + return; } -} -static void get_directory_items(const app_config &cfg, i_provider &provider) { + create_file(provider, "/pt01.txt"); + create_file(provider, "/pt02.txt"); + create_directory(provider, "/dir01"); + create_directory(provider, "/dir02"); + directory_item_list list{}; EXPECT_EQ(api_error::success, provider.get_directory_items("/", list)); check_forced_dirs(list); + EXPECT_GE(list.size(), std::size_t(6U)); + EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt")); + EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt")); + EXPECT_EQ(api_error::success, provider.remove_directory("/dir01")); + EXPECT_EQ(api_error::success, provider.remove_directory("/dir02")); +} + +static void get_directory_items(const app_config &cfg, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.get_provider_type() == provider_type::encrypt) { + directory_item_list list{}; + EXPECT_EQ(api_error::success, provider.get_directory_items("/", list)); + check_forced_dirs(list); + EXPECT_EQ(std::size_t(4U), list.size()); directory_item_list list_decrypted{list.begin() + 2U, list.end()}; @@ -443,7 +497,7 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) { EXPECT_EQ(std::size_t(46U), file->size); #endif - const auto source_path = + auto source_path = utils::path::combine(cfg.get_encrypt_config().path, {"sub10"}); std::string api_path{}; EXPECT_EQ(api_error::success, @@ -472,11 +526,58 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) { #else EXPECT_EQ(std::size_t(45U), file2->size); #endif + return; } + + create_file(provider, "/pt01.txt"); + create_file(provider, "/pt02.txt"); + create_directory(provider, "/dir01"); + create_directory(provider, "/dir02"); + + directory_item_list list{}; + EXPECT_EQ(api_error::success, provider.get_directory_items("/", list)); + check_forced_dirs(list); + EXPECT_GE(list.size(), std::size_t(6U)); + + auto iter = std::ranges::find_if( + list, [](auto &&item) -> bool { return item.api_path == "/pt01.txt"; }); + EXPECT_NE(iter, list.end()); + EXPECT_STREQ("/", (*iter).api_parent.c_str()); + EXPECT_FALSE((*iter).directory); + EXPECT_EQ(std::uint64_t{0U}, (*iter).size); + + iter = std::ranges::find_if( + list, [](auto &&item) -> bool { return item.api_path == "/pt02.txt"; }); + EXPECT_NE(iter, list.end()); + EXPECT_STREQ("/", (*iter).api_parent.c_str()); + EXPECT_FALSE((*iter).directory); + EXPECT_EQ(std::uint64_t{0U}, (*iter).size); + + iter = std::ranges::find_if( + list, [](auto &&item) -> bool { return item.api_path == "/dir01"; }); + EXPECT_NE(iter, list.end()); + EXPECT_STREQ("/", (*iter).api_parent.c_str()); + EXPECT_TRUE((*iter).directory); + EXPECT_EQ(std::uint64_t{0U}, (*iter).size); + + iter = std::ranges::find_if( + list, [](auto &&item) -> bool { return item.api_path == "/dir02"; }); + EXPECT_NE(iter, list.end()); + EXPECT_STREQ("/", (*iter).api_parent.c_str()); + EXPECT_TRUE((*iter).directory); + EXPECT_EQ(std::uint64_t{0U}, (*iter).size); + + EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt")); + EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt")); + EXPECT_EQ(api_error::success, provider.remove_directory("/dir01")); + EXPECT_EQ(api_error::success, provider.remove_directory("/dir02")); } static void get_directory_items_fails_if_directory_not_found(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); directory_item_list list{}; EXPECT_EQ(api_error::directory_not_found, provider.get_directory_items("/not_found", list)); @@ -485,8 +586,11 @@ get_directory_items_fails_if_directory_not_found(i_provider &provider) { static void get_directory_items_fails_if_item_is_file(const app_config &cfg, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.get_provider_type() == provider_type::encrypt) { - const auto source_path = + auto source_path = utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"}); std::string api_path{}; @@ -497,12 +601,24 @@ static void get_directory_items_fails_if_item_is_file(const app_config &cfg, EXPECT_EQ(api_error::item_exists, provider.get_directory_items(api_path, list)); EXPECT_TRUE(list.empty()); + return; } + + create_file(provider, "/pt01.txt"); + + directory_item_list list{}; + EXPECT_EQ(api_error::item_exists, + provider.get_directory_items("/pt01.txt", list)); + + EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt")); } static void get_file(const app_config &cfg, i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.get_provider_type() == provider_type::encrypt) { - const auto source_path = + auto source_path = utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"}); std::string api_path{}; @@ -522,18 +638,43 @@ static void get_file(const app_config &cfg, i_provider &provider) { EXPECT_EQ(std::size_t(46U), file.file_size); #endif EXPECT_STREQ(source_path.c_str(), file.source_path.c_str()); + return; } + + create_file(provider, "/pt01.txt"); + + api_file file{}; + EXPECT_EQ(api_error::success, provider.get_file("/pt01.txt", file)); + + EXPECT_STREQ("/pt01.txt", file.api_path.c_str()); + EXPECT_STREQ("/", file.api_parent.c_str()); + EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U), + file.accessed_date); + EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U), + file.changed_date); + EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U), + file.creation_date); + EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U), + file.modified_date); + + EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt")); } static void get_file_fails_if_file_not_found(i_provider &provider) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); 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) { + fmt::println("testing|{}|{}", + app_config::get_provider_name(provider.get_provider_type()), + __FUNCTION__); if (provider.get_provider_type() == provider_type::encrypt) { - const auto source_path = + auto source_path = utils::path::combine(cfg.get_encrypt_config().path, {"sub10"}); std::string api_path{}; @@ -542,7 +683,15 @@ static void get_file_fails_if_item_is_directory(const app_config &cfg, api_file file{}; EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file)); + return; } + + create_directory(provider, "/dir01"); + + api_file file{}; + EXPECT_EQ(api_error::directory_exists, provider.get_file("/dir01", file)); + + EXPECT_EQ(api_error::success, provider.remove_directory("/dir01")); } static void get_file_list(const app_config &cfg, i_provider &provider) { @@ -593,7 +742,6 @@ static void run_tests(const app_config &cfg, i_provider &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); @@ -629,17 +777,16 @@ static void run_tests(const app_config &cfg, i_provider &provider) { upload_file(provider); */ } -TEST(providers, encrypt_provider) { - const auto config_path = - utils::path::combine(test::get_test_output_dir(), {"encrypt_provider"}); - +TEST(providers_test, encrypt_provider) { + auto config_path = utils::path::combine(test::get_test_output_dir(), + {"provider", "encrypt"}); console_consumer consumer{}; event_system::instance().start(); { app_config cfg(provider_type::encrypt, config_path); - const auto encrypt_path = + auto encrypt_path = utils::path::combine(test::get_test_input_dir(), {"encrypt"}); EXPECT_STREQ( @@ -673,9 +820,9 @@ TEST(providers, encrypt_provider) { event_system::instance().stop(); } -TEST(providers, s3_provider) { - const auto config_path = - utils::path::combine(test::get_test_output_dir(), {"s3_provider"}); +TEST(providers_test, s3_provider) { + auto config_path = + utils::path::combine(test::get_test_output_dir(), {"provider", "s3"}); console_consumer consumer{}; event_system::instance().start(); @@ -685,7 +832,7 @@ TEST(providers, s3_provider) { { app_config src_cfg( provider_type::s3, - utils::path::combine(test::get_test_config_dir(), {"storj"})); + utils::path::combine(test::get_test_config_dir(), {"s3"})); cfg.set_s3_config(src_cfg.get_s3_config()); } @@ -713,9 +860,9 @@ TEST(providers, s3_provider) { event_system::instance().stop(); } -TEST(providers, sia_provider) { - const auto config_path = - utils::path::combine(test::get_test_output_dir(), {"sia_provider"}); +TEST(providers_test, sia_provider) { + auto config_path = + utils::path::combine(test::get_test_output_dir(), {"sia", "provider"}); console_consumer consumer{}; event_system::instance().start(); @@ -753,5 +900,3 @@ TEST(providers, sia_provider) { event_system::instance().stop(); } } // namespace repertory - -#endif // 0 diff --git a/repertory/repertory_test/src/upload_test.cpp b/repertory/repertory_test/src/upload_test.cpp index 8b21fd8e..1f45d10b 100644 --- a/repertory/repertory_test/src/upload_test.cpp +++ b/repertory/repertory_test/src/upload_test.cpp @@ -29,7 +29,7 @@ namespace repertory { static constexpr const std::size_t test_chunk_size{1024U}; -TEST(upload, can_upload_a_valid_file) { +TEST(upload_test, can_upload_a_valid_file) { console_consumer con; event_system::instance().start(); @@ -71,7 +71,7 @@ TEST(upload, can_upload_a_valid_file) { event_system::instance().stop(); } -TEST(upload, can_cancel_upload) { +TEST(upload_test, can_cancel_upload) { console_consumer con; event_system::instance().start(); @@ -135,7 +135,7 @@ TEST(upload, can_cancel_upload) { event_system::instance().stop(); } -TEST(upload, can_stop_upload) { +TEST(upload_test, can_stop_upload) { console_consumer con; event_system::instance().start(); diff --git a/repertory/repertory_test/src/utils_test.cpp b/repertory/repertory_test/src/utils_test.cpp index aeb9b9dc..f95c3629 100644 --- a/repertory/repertory_test/src/utils_test.cpp +++ b/repertory/repertory_test/src/utils_test.cpp @@ -25,7 +25,7 @@ #include "utils/file.hpp" namespace repertory { -TEST(utils, convert_api_date) { +TEST(utils_test, convert_api_date) { #if defined(_WIN32) auto file_time = utils::time::unix_time_to_filetime( s3_provider::convert_api_date("2009-10-12T17:50:30.111Z")); @@ -63,7 +63,7 @@ TEST(utils, convert_api_date) { #endif // defined(_WIN32) } -TEST(utils, generate_sha256) { +TEST(utils_test, generate_sha256) { auto res = utils::file::file{__FILE__}.sha256(); EXPECT_TRUE(res.has_value()); if (res.has_value()) { diff --git a/scripts/env.sh b/scripts/env.sh index d43bc1cd..ce8873f1 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -42,6 +42,7 @@ done PROJECT_APP_LIST=() PROJECT_CMAKE_OPTS="" PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF +PROJECT_ENABLE_V2_ERRORS=OFF PROJECT_IS_ALPINE=0 PROJECT_IS_ARM64=0 PROJECT_MINGW64_COPY_DEPENDENCIES=() @@ -234,6 +235,7 @@ PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_DIR=${PROJECT_BUILD_DIR} ${PROJECT_CMAKE_OPT PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS} ${PROJECT_CMAKE_OPTS}" PROJECT_CMAKE_OPTS="-DPROJECT_CMAKE_BUILD_TYPE=${PROJECT_CMAKE_BUILD_TYPE} ${PROJECT_CMAKE_OPTS}" PROJECT_CMAKE_OPTS="-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR} ${PROJECT_CMAKE_OPTS}" +PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS} ${PROJECT_CMAKE_OPTS}" PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES} ${PROJECT_CMAKE_OPTS}" PROJECT_CMAKE_OPTS="-DPROJECT_EXTERNAL_BUILD_ROOT=${PROJECT_EXTERNAL_BUILD_ROOT} ${PROJECT_CMAKE_OPTS}" PROJECT_CMAKE_OPTS="-DPROJECT_GIT_REV=${PROJECT_GIT_REV} ${PROJECT_CMAKE_OPTS}" @@ -305,6 +307,7 @@ export PROJECT_COPYRIGHT export PROJECT_DESC export PROJECT_DIST_DIR export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES +export PROJECT_ENABLE_V2_ERRORS export PROJECT_FILE_PART export PROJECT_GIT_REV export PROJECT_IS_ALPINE @@ -355,6 +358,7 @@ echo " Company name: ${PROJECT_COMPANY_NAME}" echo " Copyright: ${PROJECT_COPYRIGHT}" echo " Description: ${PROJECT_DESC}" echo " Dist dir: ${PROJECT_DIST_DIR}" +echo " Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}" echo " External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}" echo " File part: ${PROJECT_FILE_PART}" echo " Is ARM64: ${PROJECT_IS_ARM64}" diff --git a/support/include/utils/error.hpp b/support/include/utils/error.hpp index 83e153d1..a78a02aa 100644 --- a/support/include/utils/error.hpp +++ b/support/include/utils/error.hpp @@ -25,12 +25,16 @@ #include "utils/config.hpp" namespace repertory::utils::error { -[[nodiscard]] auto -create_error_message(std::vector items) -> std::string; +[[nodiscard]] auto create_error_message(std::vector items) + -> std::string; -[[nodiscard]] auto -create_exception(std::string_view function_name, - std::vector items) -> std::runtime_error; +[[nodiscard]] auto create_error_message(std::string_view function_name, + std::vector items) + -> std::string; + +[[nodiscard]] auto create_exception(std::string_view function_name, + std::vector items) + -> std::runtime_error; struct i_exception_handler { virtual ~i_exception_handler() {} @@ -40,6 +44,11 @@ struct i_exception_handler { auto operator=(const i_exception_handler &) noexcept = delete; auto operator=(i_exception_handler &&) noexcept = delete; +#if defined(PROJECT_ENABLE_V2_ERRORS) + virtual void handle_debug(std::string_view function_name, + std::string_view msg) const = 0; +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + virtual void handle_error(std::string_view function_name, std::string_view msg) const = 0; @@ -48,56 +57,107 @@ struct i_exception_handler { virtual void handle_exception(std::string_view function_name, const std::exception &ex) const = 0; +#if defined(PROJECT_ENABLE_V2_ERRORS) + virtual void handle_info(std::string_view function_name, + std::string_view msg) const = 0; + + virtual void handle_trace(std::string_view function_name, + std::string_view msg) const = 0; + + virtual void handle_warn(std::string_view function_name, + std::string_view msg) const = 0; +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + protected: i_exception_handler() = default; }; -struct iostream_exception_handler final : i_exception_handler { - void handle_error(std::string_view function_name, - std::string_view msg) const override { - std::cerr << create_error_message({ - function_name, - msg, - }) - << std::endl; - } +struct iostream_exception_handler final : public i_exception_handler { +#if defined(PROJECT_ENABLE_V2_ERRORS) + void handle_debug(std::string_view function_name, + std::string_view msg) const override; +#endif // defined(PROJECT_ENABLE_V2_ERRORS) - void handle_exception(std::string_view function_name) const override { - std::cerr << create_error_message({ - function_name, - "exception", - "unknown", - }) - << std::endl; - } + void handle_error(std::string_view function_name, + std::string_view msg) const override; + + void handle_exception(std::string_view function_name) const override; void handle_exception(std::string_view function_name, - const std::exception &ex) const override { - std::cerr << create_error_message({ - function_name, - "exception", - (ex.what() == nullptr ? "unknown" : ex.what()), - }) - << std::endl; - } -}; -inline const iostream_exception_handler default_exception_handler{}; + const std::exception &ex) const override; -extern std::atomic exception_handler; +#if defined(PROJECT_ENABLE_V2_ERRORS) + void handle_info(std::string_view function_name, + std::string_view msg) const override; + + void handle_trace(std::string_view function_name, + std::string_view msg) const override; + + void handle_warn(std::string_view function_name, + std::string_view msg) const override; +#endif // defined(PROJECT_ENABLE_V2_ERRORS) +}; + +#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) +struct spdlog_exception_handler final : public i_exception_handler { + void handle_debug(std::string_view function_name, + std::string_view msg) const override; + + void handle_error(std::string_view function_name, + std::string_view msg) const override; + + void handle_exception(std::string_view function_name) const override; + + void handle_exception(std::string_view function_name, + const std::exception &ex) const override; + + void handle_info(std::string_view function_name, + std::string_view msg) const override; + + void handle_trace(std::string_view function_name, + std::string_view msg) const override; + + void handle_warn(std::string_view function_name, + std::string_view msg) const override; + +private: + iostream_exception_handler fallback{}; +}; +#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) + +#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) +inline const spdlog_exception_handler default_exception_handler{}; +#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS) +inline const iostream_exception_handler default_exception_handler{}; +#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) #if defined(PROJECT_ENABLE_TESTING) -[[nodiscard]] inline auto -get_exception_handler() -> const i_exception_handler * { +extern std::atomic exception_handler; + +[[nodiscard]] inline auto get_exception_handler() + -> const i_exception_handler * { return exception_handler; } #endif // defined(PROJECT_ENABLE_TESTING) +#if defined(PROJECT_ENABLE_V2_ERRORS) +void handle_debug(std::string_view function_name, std::string_view msg); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + void handle_error(std::string_view function_name, std::string_view msg); void handle_exception(std::string_view function_name); void handle_exception(std::string_view function_name, const std::exception &ex); +#if defined(PROJECT_ENABLE_V2_ERRORS) +void handle_info(std::string_view function_name, std::string_view msg); + +void handle_trace(std::string_view function_name, std::string_view msg); + +void handle_warn(std::string_view function_name, std::string_view msg); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + void set_exception_handler(const i_exception_handler *handler); } // namespace repertory::utils::error diff --git a/support/src/utils/error.cpp b/support/src/utils/error.cpp index 73d573e2..feebdbcd 100644 --- a/support/src/utils/error.cpp +++ b/support/src/utils/error.cpp @@ -22,9 +22,6 @@ #include "utils/error.hpp" namespace repertory::utils::error { -std::atomic exception_handler{ - &default_exception_handler}; - auto create_error_message(std::vector items) -> std::string { std::stringstream stream{}; for (std::size_t idx = 0U; idx < items.size(); ++idx) { @@ -38,13 +35,30 @@ auto create_error_message(std::vector items) -> std::string { return stream.str(); } +auto create_error_message(std::string_view function_name, + std::vector items) -> std::string { + items.insert(items.begin(), function_name); + return create_error_message(items); +} + auto create_exception(std::string_view function_name, std::vector items) -> std::runtime_error { - items.insert(items.begin(), function_name); - return std::runtime_error(create_error_message(items)); + return std::runtime_error(create_error_message(function_name, items)); } +#if defined(PROJECT_ENABLE_V2_ERRORS) +void handle_debug(std::string_view function_name, std::string_view msg) { + const i_exception_handler *handler{exception_handler}; + if (handler != nullptr) { + handler->handle_debug(function_name, msg); + return; + } + + default_exception_handler.handle_debug(function_name, msg); +} +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + void handle_error(std::string_view function_name, std::string_view msg) { const i_exception_handler *handler{exception_handler}; if (handler != nullptr) { @@ -76,6 +90,38 @@ void handle_exception(std::string_view function_name, default_exception_handler.handle_exception(function_name, ex); } +#if defined(PROJECT_ENABLE_V2_ERRORS) +void handle_info(std::string_view function_name, std::string_view msg) { + const i_exception_handler *handler{exception_handler}; + if (handler != nullptr) { + handler->handle_info(function_name, msg); + return; + } + + default_exception_handler.handle_info(function_name, msg); +} + +void handle_trace(std::string_view function_name, std::string_view msg) { + const i_exception_handler *handler{exception_handler}; + if (handler != nullptr) { + handler->handle_trace(function_name, msg); + return; + } + + default_exception_handler.handle_trace(function_name, msg); +} + +void handle_warn(std::string_view function_name, std::string_view msg) { + const i_exception_handler *handler{exception_handler}; + if (handler != nullptr) { + handler->handle_warn(function_name, msg); + return; + } + + default_exception_handler.handle_warn(function_name, msg); +} +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + void set_exception_handler(const i_exception_handler *handler) { exception_handler = handler; } diff --git a/support/src/utils/error_handler.cpp b/support/src/utils/error_handler.cpp new file mode 100644 index 00000000..827ce2b1 --- /dev/null +++ b/support/src/utils/error_handler.cpp @@ -0,0 +1,241 @@ +/* + Copyright <2018-2025> + + 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 "utils/config.hpp" +#include "utils/error.hpp" + +namespace repertory::utils::error { +std::atomic exception_handler{ + &default_exception_handler}; + +#if defined(PROJECT_ENABLE_V2_ERRORS) +void iostream_exception_handler::handle_debug(std::string_view function_name, + std::string_view msg) const { + std::cout << create_error_message({ + "debug", + function_name, + msg, + }) + << std::endl; +} +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + +void iostream_exception_handler::handle_error(std::string_view function_name, + std::string_view msg) const { + std::cerr << create_error_message({ + "error", + function_name, + msg, + }) + << std::endl; +} + +void iostream_exception_handler::handle_exception( + std::string_view function_name) const { + std::cerr << create_error_message({ + "error", + function_name, + "exception", + "unknown", + }) + << std::endl; +} + +void iostream_exception_handler::handle_exception( + std::string_view function_name, const std::exception &ex) const { + std::cerr << create_error_message({ + "error", + function_name, + "exception", + (ex.what() == nullptr ? "unknown" : ex.what()), + }) + << std::endl; +} + +#if defined(PROJECT_ENABLE_V2_ERRORS) +void iostream_exception_handler::handle_info(std::string_view function_name, + std::string_view msg) const { + std::cout << create_error_message({ + "info", + function_name, + msg, + }) + << std::endl; +} + +void iostream_exception_handler::handle_trace(std::string_view function_name, + std::string_view msg) const { + std::cout << create_error_message({ + "trace", + function_name, + msg, + }) + << std::endl; +} + +void iostream_exception_handler::handle_warn(std::string_view function_name, + std::string_view msg) const { + std::cout << create_error_message({ + "warn", + function_name, + msg, + }) + << std::endl; +} +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + +#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) +void spdlog_exception_handler::handle_debug(std::string_view function_name, + std::string_view msg) const { + auto console = spdlog::get("console"); + if (console) { + console->debug(utils::error::create_error_message(function_name, {msg})); + } else { + fallback.handle_debug(function_name, msg); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->debug(utils::error::create_error_message(function_name, {msg})); +} + +void spdlog_exception_handler::handle_error(std::string_view function_name, + std::string_view msg) const { + auto console = spdlog::get("console"); + if (console) { + console->error(utils::error::create_error_message(function_name, {msg})); + } else { + fallback.handle_error(function_name, msg); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->error(utils::error::create_error_message(function_name, {msg})); +} + +void spdlog_exception_handler::handle_exception( + std::string_view function_name) const { + auto console = spdlog::get("console"); + if (console) { + console->error(utils::error::create_error_message(function_name, + { + "exception", + "unknown exception", + })); + } else { + fallback.handle_exception(function_name); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->error( + utils::error::create_error_message(function_name, { + "exception", + "unknown exception", + })); +} + +void spdlog_exception_handler::handle_exception( + std::string_view function_name, const std::exception &ex) const { + auto console = spdlog::get("console"); + if (console) { + console->error(utils::error::create_error_message( + function_name, { + "exception", + (ex.what() == nullptr ? "unknown" : ex.what()), + })); + } else { + fallback.handle_exception(function_name, ex); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->error(utils::error::create_error_message( + function_name, { + "exception", + (ex.what() == nullptr ? "unknown" : ex.what()), + })); +} + +void spdlog_exception_handler::handle_info(std::string_view function_name, + std::string_view msg) const { + auto console = spdlog::get("console"); + if (console) { + console->info(utils::error::create_error_message(function_name, {msg})); + } else { + fallback.handle_info(function_name, msg); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->info(utils::error::create_error_message(function_name, {msg})); +} + +void spdlog_exception_handler::handle_trace(std::string_view function_name, + std::string_view msg) const { + auto console = spdlog::get("console"); + if (console) { + console->trace(utils::error::create_error_message(function_name, {msg})); + } else { + fallback.handle_trace(function_name, msg); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->trace(utils::error::create_error_message(function_name, {msg})); +} + +void spdlog_exception_handler::handle_warn(std::string_view function_name, + std::string_view msg) const { + auto console = spdlog::get("console"); + if (console) { + console->warn(utils::error::create_error_message(function_name, {msg})); + } else { + fallback.handle_warn(function_name, msg); + } + + auto file = spdlog::get("file"); + if (not file) { + return; + } + + file->warn(utils::error::create_error_message(function_name, {msg})); +} +#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) +} // namespace repertory::utils::error diff --git a/support/src/utils/file.cpp b/support/src/utils/file.cpp index 1d747156..8727918d 100644 --- a/support/src/utils/file.cpp +++ b/support/src/utils/file.cpp @@ -41,8 +41,16 @@ auto change_to_process_directory() -> bool { ::GetModuleFileNameA(nullptr, file_name.data(), static_cast(file_name.size() - 1U)); - auto path = utils::path::strip_to_file_name(file_name.c_str()); - ::SetCurrentDirectoryA(path.c_str()); + auto path = utils::path::get_parent_path(file_name.c_str()); + auto res = ::SetCurrentDirectoryA(path.c_str()) != 0; + if (not res) { + throw utils::error::create_exception( + function_name, { + "failed to set current directory", + std::to_string(utils::get_last_error_code()), + path, + }); + } #else // !defined(_WIN32) std::string path; path.resize(PATH_MAX + 1); diff --git a/support/test/src/utils/error_test.cpp b/support/test/src/utils/error_test.cpp index 1b345693..540322a5 100644 --- a/support/test/src/utils/error_test.cpp +++ b/support/test/src/utils/error_test.cpp @@ -29,15 +29,28 @@ TEST(utils_error, check_default_exception_handler) { EXPECT_TRUE(utils::error::get_exception_handler() != nullptr); if (&utils::error::default_exception_handler == utils::error::get_exception_handler()) { +#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS) + auto default_handler_is_spdlog = + is_decay_equ; + EXPECT_TRUE(default_handler_is_spdlog); +#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS) auto default_handler_is_iostream = is_decay_equ; EXPECT_TRUE(default_handler_is_iostream); +#endif } } TEST(utils_error, can_override_exception_handler) { struct my_exc_handler final : public utils::error::i_exception_handler { +#if defined(PROJECT_ENABLE_V2_ERRORS) + MOCK_METHOD(void, handle_debug, + (std::string_view function_name, std::string_view msg), + (const, override)); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + MOCK_METHOD(void, handle_error, (std::string_view function_name, std::string_view msg), (const, override)); @@ -48,11 +61,30 @@ TEST(utils_error, can_override_exception_handler) { MOCK_METHOD(void, handle_exception, (std::string_view function_name, const std::exception &ex), (const, override)); + +#if defined(PROJECT_ENABLE_V2_ERRORS) + MOCK_METHOD(void, handle_info, + (std::string_view function_name, std::string_view msg), + (const, override)); + + MOCK_METHOD(void, handle_trace, + (std::string_view function_name, std::string_view msg), + (const, override)); + + MOCK_METHOD(void, handle_warn, + (std::string_view function_name, std::string_view msg), + (const, override)); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) }; my_exc_handler handler{}; utils::error::set_exception_handler(&handler); +#if defined(PROJECT_ENABLE_V2_ERRORS) + EXPECT_CALL(handler, handle_debug("test_func", "debug")).WillOnce(Return()); + utils::error::handle_debug("test_func", "debug"); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + EXPECT_CALL(handler, handle_error("test_func", "error")).WillOnce(Return()); utils::error::handle_error("test_func", "error"); @@ -68,6 +100,17 @@ TEST(utils_error, can_override_exception_handler) { }); utils::error::handle_exception("test_func_ex", ex); +#if defined(PROJECT_ENABLE_V2_ERRORS) + EXPECT_CALL(handler, handle_info("test_func", "info")).WillOnce(Return()); + utils::error::handle_info("test_func", "info"); + + EXPECT_CALL(handler, handle_trace("test_func", "trace")).WillOnce(Return()); + utils::error::handle_trace("test_func", "trace"); + + EXPECT_CALL(handler, handle_warn("test_func", "warn")).WillOnce(Return()); + utils::error::handle_warn("test_func", "warn"); +#endif // defined(PROJECT_ENABLE_V2_ERRORS) + utils::error::set_exception_handler(&utils::error::default_exception_handler); } } // namespace repertory