From c22594c6ab511f58611871513b8a42fbfc2e9b5c Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Tue, 17 Dec 2024 13:46:14 -0600 Subject: [PATCH] encryption provider db unit tests and fixes --- .../librepertory/include/db/i_file_db.hpp | 3 + .../include/db/impl/rdb_file_db.hpp | 43 ++++++ .../include/db/impl/sqlite_file_db.hpp | 3 + .../librepertory/src/db/impl/rdb_file_db.cpp | 38 +++++ .../src/db/impl/sqlite_file_db.cpp | 19 ++- .../providers/encrypt/encrypt_provider.cpp | 25 ++-- .../include/fixtures/file_db_fixture.hpp | 71 +++++++++ repertory/repertory_test/src/file_db_test.cpp | 141 ++++++++++++++++++ 8 files changed, 325 insertions(+), 18 deletions(-) create mode 100644 repertory/repertory_test/include/fixtures/file_db_fixture.hpp create mode 100644 repertory/repertory_test/src/file_db_test.cpp diff --git a/repertory/librepertory/include/db/i_file_db.hpp b/repertory/librepertory/include/db/i_file_db.hpp index 66007b13..574a6979 100644 --- a/repertory/librepertory/include/db/i_file_db.hpp +++ b/repertory/librepertory/include/db/i_file_db.hpp @@ -86,6 +86,9 @@ public: [[nodiscard]] virtual auto get_source_path(const std::string &api_path, std::string &source_path) const -> api_error = 0; + + [[nodiscard]] virtual auto remove_item(const std::string &api_path) + -> api_error = 0; }; } // namespace repertory diff --git a/repertory/librepertory/include/db/impl/rdb_file_db.hpp b/repertory/librepertory/include/db/impl/rdb_file_db.hpp index cd8c6928..37e639f2 100644 --- a/repertory/librepertory/include/db/impl/rdb_file_db.hpp +++ b/repertory/librepertory/include/db/impl/rdb_file_db.hpp @@ -58,7 +58,50 @@ private: std::function action) -> bool; public: + [[nodiscard]] auto add_directory(const std::string &api_path, + const std::string &source_path) + -> api_error override; + + [[nodiscard]] auto add_or_update_file(const i_file_db::file_data &data) + -> api_error override; + void clear() override; + + [[nodiscard]] auto count() const -> std::uint64_t override; + + [[nodiscard]] auto get_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_directory_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_directory_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; + + [[nodiscard]] auto get_file_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_file_data(const std::string &api_path, + i_file_db::file_data &data) const + -> api_error override; + + [[nodiscard]] auto get_file_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; + + [[nodiscard]] auto get_item_list() const + -> std::vector override; + + [[nodiscard]] auto get_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; + + [[nodiscard]] auto remove_item(const std::string &api_path) + -> api_error override; }; } // namespace repertory diff --git a/repertory/librepertory/include/db/impl/sqlite_file_db.hpp b/repertory/librepertory/include/db/impl/sqlite_file_db.hpp index dacb95d8..de5dbeca 100644 --- a/repertory/librepertory/include/db/impl/sqlite_file_db.hpp +++ b/repertory/librepertory/include/db/impl/sqlite_file_db.hpp @@ -83,6 +83,9 @@ public: [[nodiscard]] auto get_source_path(const std::string &api_path, std::string &source_path) const -> api_error override; + + [[nodiscard]] auto remove_item(const std::string &api_path) + -> api_error override; }; } // namespace repertory diff --git a/repertory/librepertory/src/db/impl/rdb_file_db.cpp b/repertory/librepertory/src/db/impl/rdb_file_db.cpp index ba143185..7ac44ca9 100644 --- a/repertory/librepertory/src/db/impl/rdb_file_db.cpp +++ b/repertory/librepertory/src/db/impl/rdb_file_db.cpp @@ -80,6 +80,12 @@ void rdb_file_db::create_or_open(bool clear) { db_ = create_rocksdb(cfg_, "file", families, handles, clear); } +auto rdb_file_db::add_directory(const std::string &api_path, + const std::string &source_path) -> api_error {} + +auto rdb_file_db::add_or_update_file(const i_file_db::file_data &data) + -> api_error {} + void rdb_file_db::clear() { create_or_open(true); } auto rdb_file_db::create_iterator() const @@ -88,6 +94,36 @@ auto rdb_file_db::create_iterator() const db_->NewIterator(rocksdb::ReadOptions())); } +auto rdb_file_db::count() const -> std::uint64_t {} + +auto rdb_file_db::get_api_path(const std::string &source_path, + std::string &api_path) const -> api_error {} + +auto rdb_file_db::get_directory_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error {} + +auto rdb_file_db::get_directory_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error {} + +auto rdb_file_db::get_file_api_path(const std::string &source_path, + std::string &api_path) const -> api_error {} + +auto rdb_file_db::get_file_data(const std::string &api_path, + i_file_db::file_data &data) const -> api_error { +} + +auto rdb_file_db::get_file_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error {} + +auto rdb_file_db::get_item_list() const -> std::vector {} + +auto rdb_file_db::get_source_path(const std::string &api_path, + std::string &source_path) const -> api_error { +} + auto rdb_file_db::perform_action(std::string_view function_name, std::function action) -> bool { @@ -138,4 +174,6 @@ auto rdb_file_db::perform_action( rollback_res.ToString()); return false; } + +auto rdb_file_db::remove_item(const std::string &api_path) -> api_error {} } // namespace repertory diff --git a/repertory/librepertory/src/db/impl/sqlite_file_db.cpp b/repertory/librepertory/src/db/impl/sqlite_file_db.cpp index 9f69baa6..b72a9475 100644 --- a/repertory/librepertory/src/db/impl/sqlite_file_db.cpp +++ b/repertory/librepertory/src/db/impl/sqlite_file_db.cpp @@ -41,9 +41,9 @@ const std::map sql_create_tables = { "(" "source_path TEXT PRIMARY KEY ASC, " "api_path TEXT UNIQUE NOT NULL, " - "iv TEXT, " + "iv TEXT DEFAULT '' NOT NULL, " "directory INTEGER NOT NULL, " - "size INTEGER" + "size INTEGER DEFAULT 0 NOT NULL" ");"}, }, }; @@ -73,7 +73,7 @@ auto sqlite_file_db::add_directory(const std::string &api_path, } utils::error::raise_api_path_error( - function_name, api_path, + function_name, api_path, api_error::error, fmt::format("failed to add directory|{}", result.get_error_str())); return api_error::error; } @@ -96,7 +96,7 @@ auto sqlite_file_db::add_or_update_file(const i_file_db::file_data &data) } utils::error::raise_api_path_error( - function_name, data.api_path, + function_name, data.api_path, api_error::error, fmt::format("failed to add file|{}", result.get_error_str())); return api_error::error; } @@ -280,7 +280,7 @@ auto sqlite_file_db::get_item_list() const std::vector ret; auto result = utils::db::sqlite::db_select{*db_, file_table}.go(); - while (result.has_value()) { + while (result.has_row()) { std::optional row; if (result.get_row(row) && row.has_value()) { ret.emplace_back(i_file_db::file_info{ @@ -315,4 +315,13 @@ auto sqlite_file_db::get_source_path(const std::string &api_path, return api_error::item_not_found; } + +auto sqlite_file_db::remove_item(const std::string &api_path) -> api_error { + auto result = utils::db::sqlite::db_delete{*db_, file_table} + .where("api_path") + .equals(api_path) + .go(); + + return result.ok() ? api_error::success : api_error::error; +} } // namespace repertory diff --git a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp index 7d131409..05f44bf1 100644 --- a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp +++ b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp @@ -219,8 +219,8 @@ auto encrypt_provider::get_directory_items(const std::string &api_path, process_directory_entry(*dir_entry.get(), cfg, current_api_path); - result = get_directory_api_path(dir_entry->get_path(), - current_api_path); + result = db_->get_directory_api_path(dir_entry->get_path(), + current_api_path); if (result != api_error::success && result != api_error::directory_not_found) { // TODO raise error @@ -687,15 +687,14 @@ auto encrypt_provider::process_directory_entry( api_path = utils::path::create_api_path( api_parent + "/" + reader.get_encrypted_file_name()); - file_res = db_->add_or_update_file( - i_file_db::file_data{ - api_path, - dynamic_cast(&dir_entry) - ->size() - .value_or(0U), - reader.get_iv_list(), - }, - dir_entry.get_path()); + file_res = db_->add_or_update_file(i_file_db::file_data{ + api_path, + dynamic_cast(&dir_entry) + ->size() + .value_or(0U), + reader.get_iv_list(), + dir_entry.get_path(), + }); if (file_res != api_error::success) { // TODO raise error return false; @@ -727,7 +726,7 @@ auto encrypt_provider::read_file_bytes(const std::string &api_path, return result; } - auto opt_size = utils::file::file{data.source_path}.size(); + auto opt_size = utils::file::file{file_data.source_path}.size(); if (not opt_size.has_value()) { return api_error::os_error; } @@ -808,7 +807,7 @@ void encrypt_provider::remove_deleted_files(const stop_type &stop_requested) { } // TODO handle error - auto del_res = db_->remove_item(item); + auto del_res = db_->remove_item(item.api_path); if (item.directory) { event_system::instance().raise( item.api_path, item.source_path); diff --git a/repertory/repertory_test/include/fixtures/file_db_fixture.hpp b/repertory/repertory_test/include/fixtures/file_db_fixture.hpp new file mode 100644 index 00000000..3846c758 --- /dev/null +++ b/repertory/repertory_test/include/fixtures/file_db_fixture.hpp @@ -0,0 +1,71 @@ +/* + Copyright <2018-2024> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP +#define REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP + +#include "test_common.hpp" + +#include "app_config.hpp" +#include "db/impl/rdb_file_db.hpp" +#include "db/impl/sqlite_file_db.hpp" +#include "events/consumers/console_consumer.hpp" +#include "events/event_system.hpp" + +namespace repertory { +template class file_db_test : public ::testing::Test { +protected: + static std::unique_ptr config; + static console_consumer console_; + static std::unique_ptr file_db; + +protected: + static void SetUpTestCase() { + static std::uint64_t idx{}; + + event_system::instance().start(); + auto cfg_directory = utils::path::combine(test::get_test_output_dir(), + { + "file_db_test", + std::to_string(++idx), + }); + config = std::make_unique(provider_type::s3, cfg_directory); + file_db = std::make_unique(*config); + } + + static void TearDownTestCase() { + file_db.reset(); + config.reset(); + event_system::instance().stop(); + } +}; + +// using file_db_types = ::testing::Types; +using file_db_types = ::testing::Types; + +template std::unique_ptr file_db_test::config; + +template console_consumer file_db_test::console_; + +template std::unique_ptr file_db_test::file_db; +} // namespace repertory + +#endif // REPERTORY_TEST_INCLUDE_FIXTURES_FILE_DB_FIXTURE_HPP diff --git a/repertory/repertory_test/src/file_db_test.cpp b/repertory/repertory_test/src/file_db_test.cpp new file mode 100644 index 00000000..b5f05502 --- /dev/null +++ b/repertory/repertory_test/src/file_db_test.cpp @@ -0,0 +1,141 @@ +/* + Copyright <2018-2024> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "fixtures/file_db_fixture.hpp" + +namespace repertory { +TYPED_TEST_CASE(file_db_test, file_db_types); + +TYPED_TEST(file_db_test, can_add_and_remove_directory) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test")); + + auto list = this->file_db->get_item_list(); + EXPECT_EQ(1U, list.size()); + + EXPECT_EQ(api_error::success, this->file_db->remove_item("/")); + + list = this->file_db->get_item_list(); + EXPECT_EQ(0U, list.size()); +} + +TYPED_TEST(file_db_test, can_add_and_remove_file) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({ + "/file", + 0U, + {}, + "c:\\test\\file.txt", + })); + + auto list = this->file_db->get_item_list(); + EXPECT_EQ(1U, list.size()); + + EXPECT_EQ(api_error::success, this->file_db->remove_item("/file")); + + list = this->file_db->get_item_list(); + EXPECT_EQ(0U, list.size()); +} + +TYPED_TEST(file_db_test, can_get_api_path_for_directory) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test")); + std::string api_path; + EXPECT_EQ(api_error::success, + this->file_db->get_api_path("c:\\test", api_path)); + EXPECT_STREQ("/", api_path.c_str()); +} + +TYPED_TEST(file_db_test, can_get_api_path_for_file) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({ + "/file", + 0U, + {}, + "c:\\test\\file.txt", + })); + std::string api_path; + EXPECT_EQ(api_error::success, + this->file_db->get_api_path("c:\\test\\file.txt", api_path)); + EXPECT_STREQ("/file", api_path.c_str()); +} + +TYPED_TEST(file_db_test, item_not_found_is_returned_for_non_existing_api_path) { + this->file_db->clear(); + + std::string api_path; + EXPECT_EQ(api_error::item_not_found, + this->file_db->get_api_path("c:\\test", api_path)); + EXPECT_TRUE(api_path.empty()); +} + +TYPED_TEST(file_db_test, can_get_directory_api_path) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_directory("/", "c:\\test")); + std::string api_path; + EXPECT_EQ(api_error::success, + this->file_db->get_directory_api_path("c:\\test", api_path)); + EXPECT_STREQ("/", api_path.c_str()); +} + +TYPED_TEST(file_db_test, + directory_not_found_is_returned_for_non_existing_directory) { + this->file_db->clear(); + + std::string api_path; + EXPECT_EQ(api_error::directory_not_found, + this->file_db->get_directory_api_path("c:\\test", api_path)); + EXPECT_TRUE(api_path.empty()); +} + +TYPED_TEST(file_db_test, can_get_file_api_path) { + this->file_db->clear(); + + EXPECT_EQ(api_error::success, this->file_db->add_or_update_file({ + "/file", + 0U, + {}, + "c:\\test\\file.txt", + })); + + std::string api_path; + EXPECT_EQ(api_error::success, + this->file_db->get_file_api_path("c:\\test\\file.txt", api_path)); + EXPECT_STREQ("/file", api_path.c_str()); +} + +TYPED_TEST(file_db_test, file_not_found_is_returned_for_non_existing_file) { + this->file_db->clear(); + + std::string api_path; + EXPECT_EQ(api_error::item_not_found, + this->file_db->get_file_api_path("c:\\test", api_path)); + EXPECT_TRUE(api_path.empty()); +} + +// test can update file source, iv, size +} // namespace repertory