diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 870c810c33b9182d9e2566f928f10ead44ea4d0c..df8ef0a9f18f5754eae33686e832bd88f37da9de 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -1,7 +1,7 @@ -FROM debian:buster-backports +FROM debian:bullseye RUN apt-get update -RUN apt-get install -y cmake/buster-backports +RUN apt-get install -y cmake RUN apt-get install -y lcov RUN apt-get install -y doxygen graphviz RUN apt-get install -y clang-format-11 clang-tidy-11 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 334ff10baab25ac2ea08bec30592858282f6c3d2..16e4ac02c9f27a3026bb3c746c97fff4d154be54 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,9 +85,6 @@ test: - mkdir build - cd build - conan install .. -s "compiler.libcxx=libstdc++11" - - FILE_TO_BE_PATCHED="$(grep "std::unique_ptr<ContextAllocator> context_allocator) {}" -l -r $(conan config home))" - - echo "FILE_TO_BE_PATCHED=$FILE_TO_BE_PATCHED" - - sed -e "s|std::unique_ptr<ContextAllocator> context_allocator) {}|std::unique_ptr<ContextAllocator> /*context_allocator*/) {}|" -i $FILE_TO_BE_PATCHED - cmake -DCMAKE_BUILD_TYPE=Debug .. - cmake --build . -j - cmake --build . -j --target unit_test_coverage diff --git a/doc/README_SETUP.md b/doc/README_SETUP.md index 8374ffade4eb1529736c4d5a99202ad80dac1dc8..ceb857617f4c4a890a15afa65a7a58e7db857e76 100644 --- a/doc/README_SETUP.md +++ b/doc/README_SETUP.md @@ -122,7 +122,7 @@ For the tests there is a slightly different setup required (with option `-D CMAK 1. `mkdir build && cd build/` 2. `conan install .. ` (with gcc, append ` -s "compiler.libcxx=libstdc++11"`, with apple-clang, -append ` -s compiler.cppstd=17`) + append ` -s compiler.cppstd=17`) 3. `cmake -B . -D CMAKE_BUILD_TYPE=Debug ..` * If your clang-format version is too old, formatting, linting etc. can be skipped: `cmake -B . -D CMAKE_BUILD_TYPE=Debug -D SKIP_LINTING=ON ..` diff --git a/include/caosdb/authentication.h b/include/caosdb/authentication.h index 070346c9366d89e7476f125b74feaea4ceb40a32..8e98a17e6d94fe118cf2fc478efbbf77733be4a6 100644 --- a/include/caosdb/authentication.h +++ b/include/caosdb/authentication.h @@ -28,10 +28,10 @@ * @brief Configuration and setup of the client authentication. */ #include "caosdb/utility.h" // for base64_encode -#include "grpcpp/impl/codegen/interceptor.h" // for Status -#include "grpcpp/impl/codegen/security/auth_context.h" // for AuthContext -#include "grpcpp/impl/codegen/status.h" // for Status -#include "grpcpp/impl/codegen/string_ref.h" // for string_ref +#include <grpcpp/impl/codegen/interceptor.h> // for Status +#include <grpcpp/impl/codegen/security/auth_context.h> // for AuthContext +#include <grpcpp/impl/codegen/status.h> // for Status +#include <grpcpp/impl/codegen/string_ref.h> // for string_ref #include <grpcpp/security/credentials.h> // for CallCredentials #include <map> // for multimap #include <memory> // for shared_ptr diff --git a/include/caosdb/configuration.h b/include/caosdb/configuration.h index be51bab1ac3152b035857929c6c6f9844f630d78..649495f9a3722c9009edcb6b383f5c02941ade28 100644 --- a/include/caosdb/configuration.h +++ b/include/caosdb/configuration.h @@ -21,20 +21,23 @@ #ifndef CAOSDB_CONFIGURATION_H #define CAOSDB_CONFIGURATION_H -#include "boost/json/object.hpp" // for object -#include "boost/json/value.hpp" // for value -#include "boost/json/value_ref.hpp" // IWYU pragma: keep + +#include "caosdb/authentication.h" // for Authenticator, PlainPassw... +#include "caosdb/certificate_provider.h" // for CertificateProvider, path +#include "caosdb/exceptions.h" // for ConfigurationError +#include "caosdb/logging.h" // for SinkConfiguration, Loggin... +#include "caosdb/utility.h" // for load_json_file +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/extension_set.h> // for Arena +#include <grpcpp/security/credentials.h> // for ChannelCredentials +#include <boost/json/object.hpp> // for object +#include <boost/json/value.hpp> // for value +#include <boost/json/value_ref.hpp> // for array, object // IWYU pragma: no_include "boost/json/fwd.hpp" -#include "caosdb/authentication.h" // for Authenticator, PlainPassw... -#include "caosdb/certificate_provider.h" // for CertificateProvider, path -#include "caosdb/exceptions.h" // for ConfigurationError -#include "caosdb/logging.h" -#include "caosdb/utility.h" // for load_json_file -#include "grpcpp/security/credentials.h" // for ChannelCredentials -#include <iosfwd> // for ostream -#include <filesystem> // for exists -#include <memory> // for unique_ptr, shared_ptr -#include <string> // for string +#include <filesystem> // for path, exists +#include <iosfwd> // for ostream +#include <memory> // for shared_ptr, unique_ptr +#include <string> // for string namespace caosdb::configuration { using boost::json::array; @@ -44,6 +47,7 @@ using caosdb::authentication::Authenticator; using caosdb::authentication::PlainPasswordAuthenticator; using caosdb::exceptions::ConfigurationError; using caosdb::utility::load_json_file; +using google::protobuf::Arena; using grpc::ChannelCredentials; using std::filesystem::exists; using std::filesystem::path; @@ -217,7 +221,10 @@ public: ConfigurationManager(ConfigurationManager const &) = delete; void operator=(ConfigurationManager const &) = delete; + inline static auto GetArena() -> Arena * { return &GetInstance().arena; } + private: + Arena arena; value json_configuration; ConnectionConfigurationHelper connection_configuration_helper; LoggingConfigurationHelper logging_configuration_helper; diff --git a/include/caosdb/constants.h.in b/include/caosdb/constants.h.in index a42c9dfd563df0a340553daf3cbcf3726bf0054e..2661806d63a23b419da44de664f087b3c95c9a87 100644 --- a/include/caosdb/constants.h.in +++ b/include/caosdb/constants.h.in @@ -23,7 +23,7 @@ #ifndef CAOSDB_CONSTANTS_H #define CAOSDB_CONSTANTS_H #ifndef __GNUC__ -# define __attribute__(x) +#define __attribute__(x) #endif #ifdef __cplusplus namespace caosdb { diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h index 9070453e36241c307888d226c40adf28c16dadc6..155d4ff6f5b12ac9ece29b4fa5f08fdccde29053 100644 --- a/include/caosdb/entity.h +++ b/include/caosdb/entity.h @@ -43,11 +43,11 @@ #include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... #include <cstdint> // for int64_t #include <filesystem> // for path +#include <google/protobuf/arena.h> // for Arena #include <google/protobuf/message.h> // for RepeatedPtrField #include <iosfwd> // for streamsize #include <iterator> // for iterator, output_iterato... #include <map> // for map -#include <random> // for mt19937, rand... #include <stdexcept> // for out_of_range #include <string> // for string, basic... #include <utility> // for move @@ -711,7 +711,7 @@ public: properties.wrapped = this->wrapped->mutable_properties(); parents.wrapped = this->wrapped->mutable_parents(); }; - explicit inline Entity(EntityResponse *response) : Entity(response->release_entity()) { + explicit inline Entity(EntityResponse *response) : Entity(response->mutable_entity()) { this->errors.wrapped->Swap(response->mutable_errors()); this->warnings.wrapped->Swap(response->mutable_warnings()); this->infos.wrapped->Swap(response->mutable_infos()); @@ -861,9 +861,7 @@ public: auto SetFilePath(const std::string &path) -> void; inline auto HasFile() const -> bool { return !this->file_descriptor.local_path.empty(); } - auto SetFileTransmissionRegistrationId(const std::string ®istration_id) -> void; inline auto SetFileTransmissionId(FileTransmissionId *file_transmission_id) -> void { - file_transmission_id->set_file_id(GetNextFileId()); file_descriptor.file_transmission_id = file_transmission_id; } @@ -910,20 +908,10 @@ public: } private: - inline auto GetNextFileId() -> std::string { - std::string str = "0123456789abcdef"; - std::mt19937 generator(std::random_device{}()); - std::uniform_int_distribution<int> distribution(0, str.size() - 1); - std::string result(10, '\0'); - - for (auto &dis : result) { - dis = str[distribution(generator)]; - } - return result; - } static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *; auto SetId(const std::string &id) -> void; auto SetVersionId(const std::string &id) -> void; + auto inline GetArena() const -> Arena * { return get_arena(); } private: FileDescriptor file_descriptor; diff --git a/include/caosdb/logging.h b/include/caosdb/logging.h index 35c5fdfa1a72ba5f55933f3bd99aa93f313c3e33..eb99f9a51b3630ce48849acf935b316044aa82b2 100644 --- a/include/caosdb/logging.h +++ b/include/caosdb/logging.h @@ -24,12 +24,11 @@ #define CAOSDB_LOGGING_H #include "caosdb/log_level.h" // for CAOSDB_LOG_... -#include "boost/log/sources/global_logger_storage.hpp" // for BOOST_LOG_I... -#include "boost/log/sources/record_ostream.hpp" // IWYU pragma: keep -#include "boost/log/sources/severity_channel_logger.hpp" // for BOOST_LOG_C... -#include "boost/log/utility/setup/settings.hpp" // for settings -#include "boost/smart_ptr/intrusive_ptr.hpp" // for intrusive_ptr -#include "boost/smart_ptr/intrusive_ref_counter.hpp" // for intrusive_p... +#include <boost/log/sources/record_ostream.hpp> // IWYU pragma: keep +#include <boost/log/sources/severity_channel_logger.hpp> // for BOOST_LOG_C... +#include <boost/log/utility/setup/settings.hpp> // for settings +#include <boost/smart_ptr/intrusive_ptr.hpp> // for intrusive_ptr +#include <boost/smart_ptr/intrusive_ref_counter.hpp> // for intrusive_p... #include <memory> // for shared_ptr #include <string> // for string #include <vector> // for vector @@ -40,7 +39,17 @@ const std::string logger_name = "caosdb::logging"; typedef boost::log::sources::severity_channel_logger_mt<int, std::string> boost_logger_class; -BOOST_LOG_GLOBAL_LOGGER(logger, boost_logger_class) +class logger { +public: + static auto get() -> boost_logger_class & { return logger::GetInstance()._logger_instance; } + +private: + static logger &GetInstance() { + static logger instance; + return instance; + } + boost_logger_class _logger_instance; +}; /** * This class stores the integer log level. diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h index dad62a9af2f8a538ce23d86fa52189df2c75c4b9..ef4cb8383eb384cd058a3f210c9d27f99b199658 100644 --- a/include/caosdb/protobuf_helper.h +++ b/include/caosdb/protobuf_helper.h @@ -40,6 +40,7 @@ namespace caosdb::utility { using google::protobuf::Arena; auto get_arena() -> Arena *; +auto reset_arena() -> void; /** * Abstract wrapper class for Protobuf messages. diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h index 31a537e4483b1a715d01dec0929d18f27c6a6a79..0e11d3f1a5d9145795b2bdcd4e1c82c31e360aa2 100644 --- a/include/caosdb/transaction.h +++ b/include/caosdb/transaction.h @@ -406,7 +406,7 @@ public: * Instead, do Execute() or WaitForIt() and only call this method afterwards. */ [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & { - if (!this->result_set) { + if (this->result_set == nullptr) { CAOSDB_LOG_ERROR(logger_name) << "GetResultSet was called before the transaction has terminated. This is a programming " "error of the code which uses the transaction."; @@ -517,11 +517,6 @@ private: std::vector<FileDescriptor> upload_files; std::map<std::string, FileDescriptor> download_files; - // auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void; - auto UploadFile(FileUploadResponse *response, const FileDescriptor &file_descriptor, - const std::string ®istration_id) -> void; - auto DownloadFile(FileDownloadResponse *response, const FileTransmissionId &file_transmission_id) - -> void; bool has_query = false; TransactionType transaction_type = TransactionType::NONE; mutable std::unique_ptr<ResultSet> result_set; diff --git a/src/caosdb/file_transmission/download_request_handler.cpp b/src/caosdb/file_transmission/download_request_handler.cpp index dfe7d8b9ebb278577d292970b84356c3cba0af0b..23520e0d78c5c8c8606ad5acf7611ba7c4806fc4 100644 --- a/src/caosdb/file_transmission/download_request_handler.cpp +++ b/src/caosdb/file_transmission/download_request_handler.cpp @@ -130,7 +130,8 @@ void DownloadRequestHandler::handleNewCallState() { << ", download_id = " << file_descriptor_.file_transmission_id; fileWriter_ = std::make_unique<FileWriter>(file_descriptor_.local_path); - request_->mutable_file_transmission_id()->CopyFrom(*(file_descriptor_.file_transmission_id)); + auto *tid = request_->mutable_file_transmission_id(); + tid->CopyFrom(*(file_descriptor_.file_transmission_id)); rpc_ = stub_->PrepareAsyncFileDownload(&ctx_, *request_, cq_); diff --git a/src/caosdb/logging.cpp b/src/caosdb/logging.cpp index cb852d4195c332ff44b6db41792b3ee7b6486612..22cda0b65f5428fe485f62972fde3aac70f84080 100644 --- a/src/caosdb/logging.cpp +++ b/src/caosdb/logging.cpp @@ -25,7 +25,6 @@ #include <boost/log/attributes/clock.hpp> #include <boost/log/core/core.hpp> // for core #include <boost/log/core/record.hpp> -#include <boost/log/sources/global_logger_storage.hpp> #include <boost/log/sources/record_ostream.hpp> #include <boost/log/sources/severity_channel_logger.hpp> #include <boost/log/utility/setup/from_settings.hpp> @@ -46,10 +45,6 @@ namespace caosdb::logging { -BOOST_LOG_GLOBAL_LOGGER_INIT(logger, boost_logger_class) { - boost_logger_class lg; - return lg; -} LoggingConfiguration::LoggingConfiguration(int level) : LevelConfiguration(level) {} auto LoggingConfiguration::AddSink(const std::shared_ptr<SinkConfiguration> &sink) -> void { @@ -116,9 +111,12 @@ SyslogSinkConfiguration::SyslogSinkConfiguration(const std::string &name, int le // Called if no custom logging settings are specified. auto initialize_logging_defaults() -> int { // first: turn everything off - boost::log::settings off_settings; - off_settings["Core.DisableLogging"] = true; - boost::log::init_from_settings(off_settings); + auto core = boost::log::core::get(); + if (core->get_logging_enabled()) { + core->flush(); + core->remove_all_sinks(); + core->set_logging_enabled(false); + } // now set everything up const static std::vector<std::shared_ptr<SinkConfiguration>> default_sinks = { @@ -133,7 +131,6 @@ auto initialize_logging_defaults() -> int { } boost::log::init_from_settings(default_settings); - auto core = boost::log::core::get(); core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); CAOSDB_LOG_DEBUG(logger_name) << "Initialized default settings."; @@ -144,20 +141,22 @@ auto initialize_logging_defaults() -> int { // Called if custom logging settings are specified. auto initialize_logging(const LoggingConfiguration &configuration) -> void { // first: turn everything off - boost::log::settings off_settings; - off_settings["Core.DisableLogging"] = true; - boost::log::init_from_settings(off_settings); - - // now set everything up - boost::log::settings new_settings; + auto core = boost::log::core::get(); + if (core->get_logging_enabled()) { + core->flush(); + core->remove_all_sinks(); + core->set_logging_enabled(false); + } if (configuration.GetLevel() == CAOSDB_LOG_LEVEL_OFF) { - new_settings["Core.DisableLogging"] = true; + // it is off return; - } else { - new_settings["Core.DisableLogging"] = false; } + // now set everything up + boost::log::settings new_settings; + new_settings["Core.DisableLogging"] = false; + for (const auto &sink : configuration.GetSinks()) { sink->Configure(new_settings); } diff --git a/src/caosdb/protobuf_helper.cpp b/src/caosdb/protobuf_helper.cpp index 418d14b9c847bc204582f6165fae81bf6adcc156..2b5847687d4926324cbbd5d4f49caca4131dc951 100644 --- a/src/caosdb/protobuf_helper.cpp +++ b/src/caosdb/protobuf_helper.cpp @@ -19,15 +19,15 @@ * */ #include "caosdb/protobuf_helper.h" +#include "caosdb/configuration.h" #include <google/protobuf/arena.h> // for Arena namespace caosdb::utility { using google::protobuf::Arena; -auto get_arena() -> Arena * { - static Arena arena; - return &arena; -} +auto get_arena() -> Arena * { return caosdb::configuration::ConfigurationManager::GetArena(); } + +auto reset_arena() -> void { get_arena()->Reset(); } } // namespace caosdb::utility diff --git a/src/caosdb/status_code_description.cpp b/src/caosdb/status_code_description.cpp index a18c3fbcba3c93f66b837bbfe0d7e0ff725ff4ca..d1f651257bc1a682870ffb52650a42c4d16ec642 100644 --- a/src/caosdb/status_code_description.cpp +++ b/src/caosdb/status_code_description.cpp @@ -132,7 +132,7 @@ auto get_status_description(int code) -> const std::string & { {StatusCode::CONFIGURATION_ERROR, "An error occurred during the configuration of the ConfigurationManager."}, {StatusCode::CONNECTION_CONFIGURATION_ERROR, - "Wither there is no connection of the given name or the given connection has a faulty " + "Either there is no connection of the given name or the given connection has a faulty " "configuration"}, {StatusCode::TRANSACTION_STATUS_ERROR, "The Transaction is in a wrong state for the attempted action."}, diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp index 694274a1af888c22b0892a3b78ef2a1f93260a4b..0460d4c7b660bc4e7d0b387b0d62e3d34f338e33 100644 --- a/src/caosdb/transaction.cpp +++ b/src/caosdb/transaction.cpp @@ -41,6 +41,7 @@ #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue #include <map> // for map, operator!= #include <memory> // for unique_ptr +#include <random> // for mt19937, rand... #include <sstream> #include <utility> // for move, pair @@ -52,6 +53,7 @@ using caosdb::entity::v1::MultiTransactionResponse; using TransactionResponseCase = caosdb::entity::v1::TransactionResponse::TransactionResponseCase; using RetrieveResponseCase = caosdb::entity::v1::RetrieveResponse::RetrieveResponseCase; using ProtoEntity = caosdb::entity::v1::Entity; +using caosdb::entity::v1::EntityRequest; using google::protobuf::Arena; using NextStatus = grpc::CompletionQueue::NextStatus; using RegistrationStatus = caosdb::entity::v1::RegistrationStatus; @@ -142,20 +144,39 @@ auto Transaction::DeleteById(const std::string &id) noexcept -> StatusCode { return this->status.GetCode(); } -auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { - ASSERT_CAN_ADD_INSERTION +auto get_next_file_id() -> std::string { + const std::string str = "0123456789abcdef"; + std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution<int> distribution(0, 15); // NOLINT + std::string result(10, '\0'); // NOLINT - auto *entity_request = - this->request->add_requests()->mutable_insert_request()->mutable_entity_request(); - auto *proto_entity = entity_request->mutable_entity(); + for (auto &dis : result) { + dis = str[distribution(generator)]; + } + return result; +} - // copy the original entity for the transaction +// only used in the next two functions. +auto add_entity_to_request(Entity *entity, EntityRequest *entity_request, + std::vector<FileDescriptor> *upload_files) -> void { + auto *proto_entity = entity_request->mutable_entity(); entity->CopyTo(proto_entity); if (entity->HasFile()) { auto *file_transmission_id = entity_request->mutable_upload_id(); + file_transmission_id->set_file_id(get_next_file_id()); entity->SetFileTransmissionId(file_transmission_id); - upload_files.push_back(entity->GetFileDescriptor()); + upload_files->push_back(entity->GetFileDescriptor()); } +} + +auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { + ASSERT_CAN_ADD_INSERTION + + auto *entity_request = + this->request->add_requests()->mutable_insert_request()->mutable_entity_request(); + + add_entity_to_request(entity, entity_request, &upload_files); + this->status = TransactionStatus::GO_ON(); return this->status.GetCode(); } @@ -165,14 +186,9 @@ auto Transaction::UpdateEntity(Entity *entity) noexcept -> StatusCode { auto *entity_request = this->request->add_requests()->mutable_update_request()->mutable_entity_request(); - auto *proto_entity = entity_request->mutable_entity(); - entity->CopyTo(proto_entity); - if (entity->HasFile()) { - auto *file_transmission_id = entity_request->mutable_upload_id(); - entity->SetFileTransmissionId(file_transmission_id); - upload_files.push_back(entity->GetFileDescriptor()); - } + add_entity_to_request(entity, entity_request, &upload_files); + this->status = TransactionStatus::GO_ON(); return this->status.GetCode(); } @@ -250,8 +266,9 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT auto *entity_response = sub_response.mutable_retrieve_response()->mutable_entity_response(); auto entity_id = entity_response->entity().id(); - download_files[entity_id].file_transmission_id = entity_response->release_download_id(); - // TODO(tf) handle error + download_files[entity_id].file_transmission_id = + Arena::CreateMessage<FileTransmissionId>(GetArena()); + download_files[entity_id].file_transmission_id->CopyFrom(entity_response->download_id()); } } } @@ -289,7 +306,7 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { // NOLINT switch (retrieve_response->retrieve_response_case()) { case RetrieveResponseCase::kEntityResponse: { - auto *retrieve_entity_response = retrieve_response->release_entity_response(); + auto *retrieve_entity_response = retrieve_response->mutable_entity_response(); result = std::make_unique<Entity>(retrieve_entity_response); } break; case RetrieveResponseCase::kSelectResult: { @@ -320,17 +337,17 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { // NOLINT } case TransactionResponseCase::kInsertResponse: { - auto *inserted_id_response = sub_response.mutable_insert_response()->release_id_response(); + auto *inserted_id_response = sub_response.mutable_insert_response()->mutable_id_response(); result = std::make_unique<Entity>(inserted_id_response); break; } case TransactionResponseCase::kDeleteResponse: { - auto *deleted_id_response = sub_response.mutable_delete_response()->release_id_response(); + auto *deleted_id_response = sub_response.mutable_delete_response()->mutable_id_response(); result = std::make_unique<Entity>(deleted_id_response); break; } case TransactionResponseCase::kUpdateResponse: { - auto *updated_id_response = sub_response.mutable_update_response()->release_id_response(); + auto *updated_id_response = sub_response.mutable_update_response()->mutable_id_response(); result = std::make_unique<Entity>(updated_id_response); break; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9cacb63b0f6b74368508df6920e2dc03db81a929..12741c41d4e31e12548711f14dc716b4eb7f65c8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -110,5 +110,10 @@ if (LCOV_PATH) set_target_properties(ccaosdb PROPERTIES COMPILE_FLAGS "${TARGET_CCAOSDB_COMPILE_FLAGS}") else () - message(WARNING "Could not generate code coverage report. Please install lcov.") + if (NOT SKIP_CODE_COVERAGE) + message(WARNING "Could not generate code coverage report. Please install lcov.") + add_custom_target(unit_test_coverage ctest -L caosdb-cpplib-unit-tests + DEPENDS caosdb ccaosdb ${test_cases} + ) + endif() endif () diff --git a/test/test_connection.cpp b/test/test_connection.cpp index 4a5260e10964bc652c4ac803bf376b6b6cf39ead..00c3bcf58e605e112a404fdfe6ece62e829562ea 100644 --- a/test/test_connection.cpp +++ b/test/test_connection.cpp @@ -26,7 +26,7 @@ #include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE, TEST_... #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPartR... -#include "gtest/gtest_pred_impl.h" // for AssertionResult, TestInfo +#include <gtest/gtest_pred_impl.h> // for AssertionResult, TestInfo #include <memory> // for allocator, operator!=, shar... #include <string> // for operator+, string diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp index c846dceb5ca196db3b58a5aae901f735ee9dc3f2..bccc853e283cb00fd6fd1b40838f5a8ac1faae64 100644 --- a/test/test_data_type.cpp +++ b/test/test_data_type.cpp @@ -65,6 +65,7 @@ TEST(test_data_type, test_atomic) { EXPECT_TRUE(data_type.IsAtomic()); EXPECT_EQ(data_type.GetAsAtomic(), map_el.first); } + caosdb::utility::reset_arena(); } TEST(test_data_type, test_reference) { diff --git a/test/test_entity.cpp b/test/test_entity.cpp index a027ad7e8e3e5bac30d7e8c33e15f0e15ee6a91f..5f5aaaab4a5f6727f38ea30c0205ea8d79a925b1 100644 --- a/test/test_entity.cpp +++ b/test/test_entity.cpp @@ -143,33 +143,34 @@ TEST(test_entity, test_append_property) { } TEST(test_entity, entity_copy_constructor) { - ProtoParent parent; - parent.set_description("the parent desc"); - parent.set_id("the parent id"); - parent.set_name("the parent name"); - ProtoProperty property; - property.set_id("the-prop-id"); - property.set_description("the prop-desc"); - property.set_name("the-prop-name"); - property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); - property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( + Arena arena; + auto *parent = Arena::CreateMessage<ProtoParent>(&arena); + parent->set_description("the parent desc"); + parent->set_id("the parent id"); + parent->set_name("the parent name"); + auto *property = Arena::CreateMessage<ProtoProperty>(&arena); + property->set_id("the-prop-id"); + property->set_description("the prop-desc"); + property->set_name("the-prop-name"); + property->mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); + property->mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE); - EntityResponse entity_response; - entity_response.mutable_entity()->set_id("the-id"); - entity_response.mutable_entity()->set_name("the-name"); - entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); - entity_response.mutable_entity()->set_description("the description"); - entity_response.mutable_entity()->set_unit("the-unit"); - entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( + auto *entity_response = Arena::CreateMessage<EntityResponse>(&arena); + entity_response->mutable_entity()->set_id("the-id"); + entity_response->mutable_entity()->set_name("the-name"); + entity_response->mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); + entity_response->mutable_entity()->set_description("the description"); + entity_response->mutable_entity()->set_unit("the-unit"); + entity_response->mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( "the-value"); - entity_response.mutable_entity()->mutable_version()->set_id("version-id"); - entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( + entity_response->mutable_entity()->mutable_version()->set_id("version-id"); + entity_response->mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( "refname"); - entity_response.mutable_entity()->mutable_file_descriptor(); - entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property); - entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent); + entity_response->mutable_entity()->mutable_file_descriptor(); + entity_response->mutable_entity()->mutable_properties()->Add()->CopyFrom(*property); + entity_response->mutable_entity()->mutable_parents()->Add()->CopyFrom(*parent); - Entity this_entity(&entity_response); + Entity this_entity(entity_response); Entity copy_entity(this_entity); EXPECT_EQ(this_entity, copy_entity); @@ -198,39 +199,40 @@ TEST(test_entity, entity_copy_constructor) { } TEST(test_entity, entity_move_constructor) { - ProtoParent parent; - parent.set_description("the parent desc"); - parent.set_id("the parent id"); - parent.set_name("the parent name"); - ProtoProperty property; - property.set_id("the-prop-id"); - property.set_description("the prop-desc"); - property.set_name("the-prop-name"); - property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); - property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( + Arena arena; + auto *parent = Arena::CreateMessage<ProtoParent>(&arena); + parent->set_description("the parent desc"); + parent->set_id("the parent id"); + parent->set_name("the parent name"); + auto *property = Arena::CreateMessage<ProtoProperty>(&arena); + property->set_id("the-prop-id"); + property->set_description("the prop-desc"); + property->set_name("the-prop-name"); + property->mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); + property->mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE); - EntityResponse entity_response; - entity_response.mutable_errors()->Add()->set_code(25); - entity_response.mutable_errors()->Mutable(0)->set_description("asdf"); - entity_response.mutable_warnings()->Add()->set_code(23); - entity_response.mutable_warnings()->Mutable(0)->set_description("asdgsafdg"); - entity_response.mutable_infos()->Add()->set_code(235); - entity_response.mutable_infos()->Mutable(0)->set_description("asdfsad"); - entity_response.mutable_entity()->set_id("the-id"); - entity_response.mutable_entity()->set_name("the-name"); - entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); - entity_response.mutable_entity()->set_description("the description"); - entity_response.mutable_entity()->set_unit("the-unit"); - entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( + auto *entity_response = Arena::CreateMessage<EntityResponse>(&arena); + entity_response->mutable_errors()->Add()->set_code(25); + entity_response->mutable_errors()->Mutable(0)->set_description("asdf"); + entity_response->mutable_warnings()->Add()->set_code(23); + entity_response->mutable_warnings()->Mutable(0)->set_description("asdgsafdg"); + entity_response->mutable_infos()->Add()->set_code(235); + entity_response->mutable_infos()->Mutable(0)->set_description("asdfsad"); + entity_response->mutable_entity()->set_id("the-id"); + entity_response->mutable_entity()->set_name("the-name"); + entity_response->mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); + entity_response->mutable_entity()->set_description("the description"); + entity_response->mutable_entity()->set_unit("the-unit"); + entity_response->mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( "the-value"); - entity_response.mutable_entity()->mutable_version()->set_id("version-id"); - entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( + entity_response->mutable_entity()->mutable_version()->set_id("version-id"); + entity_response->mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( "refname"); - entity_response.mutable_entity()->mutable_file_descriptor(); - entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property); - entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent); + entity_response->mutable_entity()->mutable_file_descriptor(); + entity_response->mutable_entity()->mutable_properties()->Add()->CopyFrom(*property); + entity_response->mutable_entity()->mutable_parents()->Add()->CopyFrom(*parent); - Entity this_entity(&entity_response); + Entity this_entity(entity_response); std::string original_string = this_entity.ToString(); Entity copy_entity(this_entity); EXPECT_EQ(this_entity, copy_entity); @@ -321,7 +323,7 @@ TEST(test_entity, property_move_assignment) { // we compare the moved one with this one const Property copy_prop(prop); - Property other_prop = std::move(prop); + Property other_prop = std::move(prop); // NOLINT EXPECT_NE(prop, copy_prop); // NOLINT EXPECT_NE(prop, other_prop); // NOLINT EXPECT_NE(prop.ToString(), prop_string); // NOLINT @@ -791,10 +793,11 @@ TEST(test_entity, test_description) { entity.SetDescription("desc entity"); property.SetDescription("desc property"); - // Parent has not setter - ProtoParent protoParent; - protoParent.set_description("desc parent"); - parent = Parent(&protoParent); + // Parent has no setter + Arena arena; + auto *protoParent = Arena::CreateMessage<ProtoParent>(&arena); + protoParent->set_description("desc parent"); + parent = Parent(protoParent); EXPECT_EQ(entity.GetDescription(), "desc entity"); EXPECT_EQ(property.GetDescription(), "desc property"); @@ -901,13 +904,14 @@ TEST(test_entity, test_parent_to_string) { } TEST(test_entity, test_messages_to_string) { - IdResponse idResponse; - idResponse.set_id("entity_id"); - auto *error = idResponse.add_errors(); + Arena arena; + auto *idResponse = Arena::CreateMessage<IdResponse>(&arena); + idResponse->set_id("entity_id"); + auto *error = idResponse->add_errors(); error->set_code(MessageCode::ENTITY_DOES_NOT_EXIST); error->set_description("error_desc"); - Entity entity(&idResponse); + Entity entity(idResponse); // Messages are not printed, currently. EXPECT_EQ(entity.ToString(), "{\n \"id\": \"entity_id\",\n \"version\": {}\n}\n"); @@ -916,13 +920,14 @@ TEST(test_entity, test_messages_to_string) { } TEST(test_entity, test_message_to_string) { - IdResponse idResponse; - idResponse.set_id("entity_id"); - auto *error = idResponse.add_errors(); + Arena arena; + auto *idResponse = Arena::CreateMessage<IdResponse>(&arena); + idResponse->set_id("entity_id"); + auto *error = idResponse->add_errors(); error->set_code(MessageCode::ENTITY_DOES_NOT_EXIST); error->set_description("error_desc"); - Entity entity(&idResponse); + Entity entity(idResponse); // Messages are not printed, currently. EXPECT_EQ(entity.ToString(), "{\n \"id\": \"entity_id\",\n \"version\": {}\n}\n"); diff --git a/test/test_protobuf.cpp b/test/test_protobuf.cpp index 8e5c84e2e5ccb80e4a03d99cf8914593df996131..42e1e574437e47f0129cb30b336ab336613daede 100644 --- a/test/test_protobuf.cpp +++ b/test/test_protobuf.cpp @@ -22,6 +22,7 @@ #include "caosdb/data_type.h" // for DataType, ReferenceDataType #include "caosdb/entity.h" // for Entity #include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField, Message +#include <google/protobuf/arena.h> // for Arena #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPa... #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, TEST @@ -31,77 +32,81 @@ namespace caosdb { using ProtoEntity = caosdb::entity::v1::Entity; using caosdb::entity::Entity; using caosdb::entity::v1::Message; +using google::protobuf::Arena; TEST(test_protobuf, test_swap_trivial) { - Message message_source; - message_source.set_code(1234); - message_source.set_description("desc"); + Arena arena; + auto *message_source = Arena::CreateMessage<Message>(&arena); + message_source->set_code(1234); + message_source->set_description("desc"); - Message message_destination; + auto *message_destination = Arena::CreateMessage<Message>(&arena); - EXPECT_EQ(message_source.code(), 1234); - EXPECT_EQ(message_source.description(), "desc"); - EXPECT_EQ(message_destination.code(), 0); - EXPECT_EQ(message_destination.description(), ""); + EXPECT_EQ(message_source->code(), 1234); + EXPECT_EQ(message_source->description(), "desc"); + EXPECT_EQ(message_destination->code(), 0); + EXPECT_EQ(message_destination->description(), ""); - message_source.Swap(&message_destination); + message_source->Swap(message_destination); - EXPECT_EQ(message_source.code(), 0); - EXPECT_EQ(message_source.description(), ""); - EXPECT_EQ(message_destination.code(), 1234); - EXPECT_EQ(message_destination.description(), "desc"); + EXPECT_EQ(message_source->code(), 0); + EXPECT_EQ(message_source->description(), ""); + EXPECT_EQ(message_destination->code(), 1234); + EXPECT_EQ(message_destination->description(), "desc"); } TEST(test_protobuf, test_swap_nested) { - ProtoEntity entity_source; - entity_source.set_id("entity_id"); - auto *version_source = entity_source.mutable_version(); + Arena arena; + auto *entity_source = Arena::CreateMessage<ProtoEntity>(&arena); + entity_source->set_id("entity_id"); + auto *version_source = entity_source->mutable_version(); version_source->set_id("version_id"); - ProtoEntity entity_destination; - auto *version_destination = entity_destination.mutable_version(); + auto *entity_destination = Arena::CreateMessage<ProtoEntity>(&arena); + auto *version_destination = entity_destination->mutable_version(); - EXPECT_EQ(entity_source.id(), "entity_id"); - EXPECT_EQ(entity_source.version().id(), "version_id"); + EXPECT_EQ(entity_source->id(), "entity_id"); + EXPECT_EQ(entity_source->version().id(), "version_id"); EXPECT_EQ(version_source->id(), "version_id"); - EXPECT_EQ(entity_destination.id(), ""); - EXPECT_EQ(entity_destination.version().id(), ""); + EXPECT_EQ(entity_destination->id(), ""); + EXPECT_EQ(entity_destination->version().id(), ""); EXPECT_EQ(version_destination->id(), ""); - entity_source.Swap(&entity_destination); + entity_source->Swap(entity_destination); - EXPECT_EQ(entity_source.id(), ""); - EXPECT_EQ(entity_source.version().id(), ""); - EXPECT_EQ(entity_destination.id(), "entity_id"); - EXPECT_EQ(entity_destination.version().id(), "version_id"); + EXPECT_EQ(entity_source->id(), ""); + EXPECT_EQ(entity_source->version().id(), ""); + EXPECT_EQ(entity_destination->id(), "entity_id"); + EXPECT_EQ(entity_destination->version().id(), "version_id"); // has not been swapped! EXPECT_EQ(version_source->id(), "version_id"); EXPECT_EQ(version_destination->id(), ""); // Member pointers to nested messages have been swapped - EXPECT_EQ(entity_source.mutable_version(), version_destination); - EXPECT_EQ(entity_destination.mutable_version(), version_source); + EXPECT_EQ(entity_source->mutable_version(), version_destination); + EXPECT_EQ(entity_destination->mutable_version(), version_source); } TEST(test_protobuf, test_copy_nested) { - ProtoEntity entity_source; - auto *data_type_source = entity_source.mutable_data_type(); + Arena arena; + auto *entity_source = Arena::CreateMessage<ProtoEntity>(&arena); + auto *data_type_source = entity_source->mutable_data_type(); data_type_source->mutable_reference_data_type()->set_name("src_per"); - ProtoEntity entity_destination; - auto *data_type_destination = entity_destination.mutable_data_type(); + auto *entity_destination = Arena::CreateMessage<ProtoEntity>(&arena); + auto *data_type_destination = entity_destination->mutable_data_type(); data_type_destination->mutable_reference_data_type()->set_name("dest_per"); - EXPECT_EQ(entity_source.data_type().reference_data_type().name(), "src_per"); - EXPECT_EQ(entity_destination.data_type().reference_data_type().name(), "dest_per"); + EXPECT_EQ(entity_source->data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_destination->data_type().reference_data_type().name(), "dest_per"); - entity_destination.CopyFrom(entity_source); + entity_destination->CopyFrom(*entity_source); - EXPECT_EQ(entity_source.data_type().reference_data_type().name(), "src_per"); - EXPECT_EQ(entity_destination.data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_source->data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_destination->data_type().reference_data_type().name(), "src_per"); - Entity entity(&entity_destination); + Entity entity(entity_destination); EXPECT_EQ(entity.GetDataType().GetAsReference().GetName(), "src_per"); const Entity ©_entity(entity); diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp index ef72ac93491c0d120a5b9a4478e60a0296b4b360..797b6acc37a43a882b83aa540f17124b462add02 100644 --- a/test/test_transaction.cpp +++ b/test/test_transaction.cpp @@ -17,17 +17,18 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include "caosdb/configuration.h" // for InsecureConnectionConfig... -#include "caosdb/connection.h" // for Connection -#include "caosdb/entity.h" // for Entity -#include "caosdb/entity/v1/main.pb.h" // for Entity -#include "caosdb/exceptions.h" // for ConnectionError -#include "caosdb/status_code.h" +#include "caosdb/configuration.h" // for InsecureConnectionConfig... +#include "caosdb/connection.h" // for Connection +#include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1/main.pb.h" // for Entity +#include "caosdb/exceptions.h" // for ConnectionError +#include "caosdb/status_code.h" // for StatusCode #include "caosdb/transaction.h" // for Transaction #include "caosdb/transaction_handler.h" // for MultiTransactionResponse #include "caosdb/transaction_status.h" // for ConnectionError #include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE #include <algorithm> // for max +#include <google/protobuf/arena.h> // for Arena #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPa... #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, TEST @@ -114,9 +115,10 @@ TEST(test_transaction, test_multi_result_set_empty) { TEST(test_transaction, test_multi_result_iterator) { std::vector<std::unique_ptr<Entity>> one_elem; - RetrieveResponse response; - response.mutable_entity_response()->mutable_entity()->set_id("100"); - one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); + Arena arena; + auto *response = Arena::CreateMessage<RetrieveResponse>(&arena); + response->mutable_entity_response()->mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response->mutable_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -128,9 +130,10 @@ TEST(test_transaction, test_multi_result_iterator) { TEST(test_transaction, test_multi_result_set_one) { std::vector<std::unique_ptr<Entity>> one_elem; - RetrieveResponse response; - response.mutable_entity_response()->mutable_entity()->set_id("100"); - one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); + Arena arena; + auto *response = Arena::CreateMessage<RetrieveResponse>(&arena); + response->mutable_entity_response()->mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response->mutable_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -140,27 +143,28 @@ TEST(test_transaction, test_multi_result_set_one) { TEST(test_transaction, test_multi_result_set_three) { std::vector<std::unique_ptr<Entity>> three_elem; - MultiTransactionResponse response; - response.add_responses() + Arena arena; + auto *response = Arena::CreateMessage<MultiTransactionResponse>(&arena); + response->add_responses() ->mutable_retrieve_response() ->mutable_entity_response() ->mutable_entity() ->set_id("100"); auto *entity_with_error = - response.add_responses()->mutable_retrieve_response()->mutable_entity_response(); + response->add_responses()->mutable_retrieve_response()->mutable_entity_response(); entity_with_error->mutable_entity()->set_id("101"); entity_with_error->add_errors()->set_code(1); - response.add_responses() + response->add_responses() ->mutable_retrieve_response() ->mutable_entity_response() ->mutable_entity() ->set_id("102"); - auto *responses = response.mutable_responses(); + auto *responses = response->mutable_responses(); std::vector<std::unique_ptr<Entity>> entities; for (auto sub_response : *responses) { three_elem.push_back(std::make_unique<Entity>( - sub_response.mutable_retrieve_response()->release_entity_response())); + sub_response.mutable_retrieve_response()->mutable_entity_response())); } MultiResultSet rs(std::move(three_elem)); diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index d11580a845a3660e22be3ade1a3cc04cb95f1dd3..6e0db0446b0d4a2e1767f1ecdf2156ffb5dbb295 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -14,7 +14,7 @@ set(test_cases # dependencies include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup() +conan_basic_setup(KEEP_RPATHS) # supress warnings during build of gtest cmake_policy(SET CMP0054 NEW) @@ -33,6 +33,9 @@ foreach (i RANGE "${len_test_cases}") ${CONAN_LIBS_GTEST} ${CONAN_LIBS_GRPC} ${CONAN_LIBS_ABSEIL} ${CONAN_LIBS_OPENSSL} ${CONAN_LIBS_C-ARES} ${CONAN_LIBS_BZIP2} ${CONAN_LIBS_PROTOBUF} ${CONAN_LIBS_ZLIB}) + if("${CMAKE_BUILD_TYPE}" MATCHES "Debug") + target_link_libraries(${test_case_name} PRIVATE caosdb_grpc) + endif() target_include_directories(${test_case_name} PUBLIC ${CONAN_INCLUDE_DIRS}) set_target_properties(${test_case_name} PROPERTIES