diff --git a/CMakeLists.txt b/CMakeLists.txt index ec6d2aeb16d31fc3282bb391dbbb034d24f3380e..80a13968af18e0d8967038cca106d6f48c5e7479 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -415,7 +415,7 @@ option(AUTOFORMATTING "call clang-format at configure time" ON) if(AUTOFORMATTING AND NOT SKIP_LINTING) find_program(clang_format NAMES clang-format-11 clang-format) file(GLOB format_test_sources test/*.cpp test/*.h test/*.h.in) - execute_process(COMMAND $(clang-format) -i --verbose ${libcaosdb_INCL} + execute_process(COMMAND ${clang_format} -i --verbose ${libcaosdb_INCL} ${libcaosdb_SRC} ${libcaosdb_TEST_SRC} ${PROJECT_SOURCE_DIR}/src/cxxcaosdbcli.cpp ${PROJECT_SOURCE_DIR}/src/ccaosdbcli.c diff --git a/Makefile b/Makefile index 84a07651b80dc6039b4ec8c534e730b84811fb3b..a024d31675b8ca1e3c1ec9967b0e5e3045872f25 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ # This Makefile is a wrapper for several other scripts. -CLANG-FORMAT = clang-format-11 +CLANG_FORMAT ?= clang-format-11 .PHONY: help help: @@ -31,7 +31,7 @@ help: @echo " style - auto-format the source files." style: - $(CLANG-FORMAT) -i --verbose \ + $(CLANG_FORMAT) -i --verbose \ $$(find test/ src/ include/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in") .PHONY: style diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h index f5b5a590306df4526d961f8c9a1aa52ba0066444..3a8f1f9effb149ced867b5012d38296278e9832f 100644 --- a/include/caosdb/entity.h +++ b/include/caosdb/entity.h @@ -454,9 +454,7 @@ class Property { public: explicit inline Property(ProtoProperty *other) : value(Value(other->mutable_value())), data_type(DataType(other->mutable_data_type())), - wrapped(other) { - FixValue(); - }; + wrapped(other){}; Property(); /** @@ -553,12 +551,6 @@ public: friend class RepeatedPtrFieldWrapper<Property, ProtoProperty>; private: - /** - * Workaround until non-string values are supported by the server. - * - * Only has an effect if there is a DataType. - */ - auto FixValue() -> void; static auto CreateProtoProperty() -> ProtoProperty *; Value value; DataType data_type; @@ -610,7 +602,6 @@ public: errors.wrapped = CreateMessagesField(); warnings.wrapped = CreateMessagesField(); infos.wrapped = CreateMessagesField(); - FixValue(); }; explicit Entity(IdResponse *id_response); explicit Entity(ProtoEntity *other) @@ -623,13 +614,11 @@ public: errors.wrapped = CreateMessagesField(); warnings.wrapped = CreateMessagesField(); infos.wrapped = CreateMessagesField(); - FixValue(); }; explicit inline Entity(EntityResponse *response) : Entity(response->release_entity()) { errors.wrapped->Swap(response->mutable_errors()); warnings.wrapped->Swap(response->mutable_warnings()); infos.wrapped->Swap(response->mutable_infos()); - FixValue(); }; [[nodiscard]] inline auto GetId() const noexcept -> const std::string & { return wrapped->id(); }; @@ -755,13 +744,6 @@ private: auto SetId(const std::string &id) -> void; auto SetVersionId(const std::string &id) -> void; - /** - * Workaround until non-string values are supported by the server. - * - * Only has an effect if there is a DataType. - */ - auto FixValue() -> void; - private: FileDescriptor file_descriptor; ProtoEntity *wrapped; diff --git a/include/caosdb/status_code.h b/include/caosdb/status_code.h index 5689b9ebeab94d01272ce049d3cb0e3f16d13665..8a21ea32ef10c28e194b29e0ab91b63a4a62bf65 100644 --- a/include/caosdb/status_code.h +++ b/include/caosdb/status_code.h @@ -22,7 +22,8 @@ #ifndef CAOSDB_STATUS_CODE_H #define CAOSDB_STATUS_CODE_H -#include <string> +#include <grpcpp/impl/codegen/status_code_enum.h> // for StatusCode +#include <string> // for string namespace caosdb { @@ -40,10 +41,23 @@ enum StatusCode { GO_ON = -3, INITIAL = -2, EXECUTING = -1, - SUCCESS = 0, - // TODO(tf) Map other GRPC errors - AUTHENTICATION_ERROR = 16, - CONNECTION_ERROR = 14, + SUCCESS = grpc::StatusCode::OK, // = 0 + CANCELLED = grpc::StatusCode::CANCELLED, // = 1 + UNKNOWN = grpc::StatusCode::UNKNOWN, // = 2 + INVALID_ARGUMENT = grpc::StatusCode::INVALID_ARGUMENT, // = 3 + DEADLINE_EXCEEDED = grpc::StatusCode::DEADLINE_EXCEEDED, // = 4 + NOT_FOUND = grpc::StatusCode::NOT_FOUND, // = 5 + ALREADY_EXISTS = grpc::StatusCode::ALREADY_EXISTS, // = 6 + PERMISSION_DENIED = grpc::StatusCode::PERMISSION_DENIED, // = 7 + RESOURCE_EXHAUSTED = grpc::StatusCode::RESOURCE_EXHAUSTED, // = 8 + FAILED_PRECONDITION = grpc::StatusCode::FAILED_PRECONDITION, // = 9 + ABORTED = grpc::StatusCode::ABORTED, // = 10 + OUT_OF_RANGE = grpc::StatusCode::OUT_OF_RANGE, // = 11 + UNIMPLEMENTED = grpc::StatusCode::UNIMPLEMENTED, // = 12 + INTERNAL = grpc::StatusCode::INTERNAL, // = 13 + CONNECTION_ERROR = grpc::StatusCode::UNAVAILABLE, // = 14 + DATA_LOSS = grpc::StatusCode::DATA_LOSS, // = 15 + AUTHENTICATION_ERROR = grpc::StatusCode::UNAUTHENTICATED, // = 16 GENERIC_RPC_ERROR = 20, GENERIC_ERROR = 21, GENERIC_TRANSACTION_ERROR = 22, diff --git a/include/caosdb/utility.h b/include/caosdb/utility.h index bfe3780cdae31b66f2227057e0efe060385d6af5..5af1b491c0b5b9d48606ba6b46130b3ef3de1d9c 100644 --- a/include/caosdb/utility.h +++ b/include/caosdb/utility.h @@ -21,25 +21,25 @@ #ifndef CAOSDB_UTILS_H #define CAOSDB_UTILS_H -#include "caosdb/entity.h" -#include "caosdb/data_type.h" -#include <boost/beast/core/detail/base64.hpp> -#include <boost/filesystem.hpp> -#include <boost/filesystem/fstream.hpp> -#include <boost/filesystem/string_file.hpp> -#include <boost/lexical_cast.hpp> // for lexical_cast -#include <boost/json.hpp> -#include <cassert> -#include <cstdlib> -#include <exception> // for logic_error -#include <fstream> -#include <iostream> -#include <map> -#include <memory> -#include <mutex> -#include <shared_mutex> -#include <string> -#include <string_view> +#include "caosdb/data_type.h" // for AtomicDataType +#include "caosdb/entity.h" // for Importance, Role +#include <boost/beast/core/detail/base64.hpp> // for encoded_size +#include <boost/beast/core/detail/base64.ipp> // for encode +#include <boost/filesystem/operations.hpp> // for exists +#include <boost/filesystem/path.hpp> // for path +#include <boost/filesystem/fstream.hpp> // for basic_ifstream, ifstream +#include <boost/filesystem/string_file.hpp> // for load_string_file +#include <boost/json/stream_parser.hpp> // for stream_parser +#include <boost/json/value.hpp> // for value +#include <boost/lexical_cast.hpp> // for lexical_cast +#include <cassert> // for assert +#include <cstdlib> // for getenv +#include <fstream> // for basic_istream<>::__ist... +#include <memory> // for allocator, unique_ptr +#include <stdexcept> // for logic_error +#include <string> // for string, operator+, cha... +#include <type_traits> // for underlying_type_t +#include <typeinfo> // for type_info namespace caosdb::utility { using boost::filesystem::exists; @@ -71,9 +71,7 @@ template <> auto getEnumNameFromValue<caosdb::entity::Role>(caosdb::entity::Role * * @detail May be useful for higher-order CaosDB clients and only makes sense if specialized. */ -template <typename Enum> auto getEnumValueFromName(const std::string &name) -> Enum { - throw std::logic_error(std::string("Enum type ") + typeid(Enum).name() + " not implemented."); -} +template <typename Enum> auto getEnumValueFromName(const std::string &name) -> Enum; // Forward declaration of specializations template <> diff --git a/include/caosdb/value.h b/include/caosdb/value.h index 989f780ed25a535fb34a97281f55e29c005a6c53..2ec817e54ba32561d2c66c843a5451c143beacf0 100644 --- a/include/caosdb/value.h +++ b/include/caosdb/value.h @@ -197,7 +197,6 @@ public: inline auto ToString() const noexcept -> const std::string { CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out) - CAOSDB_LOG_DEBUG("caosdb::entity") << "HERE 1 [" << wrapped << "] " << out; return out; } diff --git a/include/ccaosdb.h b/include/ccaosdb.h index cfe5cf446511d7272554cf4ac7be958bb0a55c11..38b5d5ea0c7540610d7d5b21003f50c35f84568a 100644 --- a/include/ccaosdb.h +++ b/include/ccaosdb.h @@ -68,7 +68,7 @@ int caosdb_status_code_OTHER_CLIENT_ERROR(); * capability for type checking in C even though the C++ class * Connection is opaque in C. */ -typedef struct { +typedef struct caosdb_connection_connection { void *wrapped_connection; bool _deletable = false; } caosdb_connection_connection; @@ -80,7 +80,7 @@ typedef struct { * capability for type checking in C even though the C++ class * Connection is opaque in C. */ -typedef struct { +typedef struct caosdb_connection_connection_configuration { void *wrapped_connection_configuration; bool _deletable = false; } caosdb_connection_connection_configuration; @@ -92,7 +92,7 @@ typedef struct { * capability for type checking in C even though the C++ class * Connection is opaque in C. */ -typedef struct { +typedef struct caosdb_info_version_info { int major; int minor; int patch; @@ -100,12 +100,12 @@ typedef struct { const char *build; } caosdb_info_version_info; -typedef struct { +typedef struct caosdb_connection_certificate_provider { void *wrapped_certificate_provider; bool _deletable = false; } caosdb_connection_certificate_provider; -typedef struct { +typedef struct caosdb_authentication_authenticator { void *wrapped_authenticator; bool _deletable = false; } caosdb_authentication_authenticator; @@ -266,7 +266,7 @@ int caosdb_connection_connection_manager_get_connection(caosdb_connection_connec // TODO(fspreck) implementations needed, and probably these declarations are // not sufficient yet. -typedef struct { +typedef struct caosdb_transaction_transaction { void *wrapped_transaction; bool _deletable = false; } caosdb_transaction_transaction; @@ -292,7 +292,7 @@ int caosdb_transaction_transaction_execute(caosdb_transaction_transaction *trans // TODO(fspreck) execute_asynchronously may be added as a separate // function once we actually support asynchronous execution. -typedef struct { +typedef struct caosdb_transaction_result_set { void *wrapped_result_set; bool _deletable = false; } caosdb_transaction_result_set; @@ -303,7 +303,7 @@ int caosdb_transaction_transaction_get_result_set(caosdb_transaction_transaction int caosdb_transaction_transaction_get_count_result(caosdb_transaction_transaction *transaction, long *out); -typedef struct { +typedef struct caosdb_entity_entity { void *wrapped_entity; bool _deletable = false; } caosdb_entity_entity; @@ -319,15 +319,17 @@ int caosdb_transaction_transaction_update_entity(caosdb_transaction_transaction int caosdb_transaction_transaction_delete_by_id(caosdb_transaction_transaction *transaction, const char *id); -typedef struct { +typedef struct caosdb_entity_property { void *wrapped_property; bool _deletable = false; } caosdb_entity_property; -typedef struct { + +typedef struct caosdb_entity_parent { void *wrapped_parent; bool _deletable = false; } caosdb_entity_parent; -typedef struct { + +typedef struct caosdb_entity_message { void *wrapped_message; bool _deletable = false; } caosdb_entity_message; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cb00898b70776b99c197556c435398d254578cbf..a3654e01f5aa6f184338ff74070755df87f9147c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ set(libcaosdb_SRC ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/download_request_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/file_writer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/file_reader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/status_code_description.cpp ) # pass variable to parent scope diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp index ed7ede3b5a59fb1bb4fb4138f4aa89296bc57b43..18c9cb525b97ba9f638b2b300908cbc404f51cae 100644 --- a/src/caosdb/entity.cpp +++ b/src/caosdb/entity.cpp @@ -20,14 +20,10 @@ * */ #include "caosdb/entity.h" -#include "caosdb/data_type.h" // for DataType -#include "caosdb/entity/v1alpha1/main.pb.h" // for Messages -#include "caosdb/exceptions.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/utility.h" -#include "caosdb/value.h" // for Value -#include <boost/algorithm/string.hpp> +#include "caosdb/data_type.h" // for DataType +#include "caosdb/entity/v1alpha1/main.pb.h" // for Messages +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/value.h" // for Value #include <google/protobuf/arena.h> // for Arena #include <google/protobuf/generated_message_util.h> // for Arena::Create... #include <new> // for operator new @@ -46,10 +42,6 @@ using google::protobuf::Arena; Messages::~Messages() = default; -// Forward declarations /////////////////////////////////////////////////////// - -template <typename E> auto FixValueImpl(E *ent) -> void; - // Parent ///////////////////////////////////////////////////////////////////// Parent::Parent() : wrapped(Parent::CreateProtoParent()) { @@ -76,7 +68,7 @@ auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); } return this->wrapped->description(); } -Property::Property() : Property(Property::CreateProtoProperty()) { FixValue(); } +Property::Property() : Property(Property::CreateProtoProperty()) {} auto Property::CreateProtoProperty() -> ProtoProperty * { return Arena::CreateMessage<ProtoProperty>(get_arena()); @@ -162,8 +154,6 @@ auto Property::SetDataType(const std::string &new_data_type, bool list_type) -> return SetDataType(DataType(new_data_type, list_type)); } -auto Property::FixValue() -> void { FixValueImpl(this); } - // Entity ///////////////////////////////////////////////////////////////////// [[nodiscard]] auto Entity::GetParents() const -> const Parents & { return parents; } @@ -187,10 +177,9 @@ Entity::Entity(IdResponse *id_response) : Entity() { this->errors.wrapped->Swap(id_response->mutable_errors()); this->warnings.wrapped->Swap(id_response->mutable_warnings()); this->infos.wrapped->Swap(id_response->mutable_infos()); - FixValue(); } -Entity::Entity() : Entity(Entity::CreateProtoEntity()) { FixValue(); } +Entity::Entity() : Entity(Entity::CreateProtoEntity()) {} auto Entity::CreateMessagesField() -> RepeatedPtrField<ProtoMessage> * { return Arena::CreateMessage<RepeatedPtrField<ProtoMessage>>(get_arena()); @@ -270,104 +259,4 @@ auto Entity::SetFilePath(const std::string &path) -> void { this->wrapped->mutable_file_descriptor()->set_path(path); } -auto Entity::FixValue() -> void { FixValueImpl(this); } - -// Utility functions ////////////////////////////////////////////////////////// - -// TODO(daniel) cognitive complexity is too high -template <typename E> auto FixValueImpl(E *ent) -> void { // NOLINT - const auto &dtype = ent->GetDataType(); - const auto &value = ent->GetValue(); - auto new_value = Value(); - CAOSDB_LOG_TRACE(logger_name) << "FixValueImpl()\n" << value.ToString(); - if (value.IsNull() || !value.IsString()) { // Don't treat NULL and non-string values. - return; - } - if (value.IsList()) { // Also don't treat empty or non-string lists. - const auto &list = value.AsList(); - if (list.empty() || !list[0].IsString()) { - return; - } - } - auto atype = AtomicDataType::UNSPECIFIED; - if (dtype.IsList()) { // List Datatype - if (!value.IsList()) { - throw caosdb::exceptions::Exception(StatusCode::OTHER_CLIENT_ERROR, - "DataType is list, but Value is scalar."); - } - auto &list_type = dtype.AsList(); - atype = list_type.GetAtomicDataType(); - if (!list_type.IsListOfAtomic() // References, strings etc. need no treatment. - || atype == AtomicDataType::UNSPECIFIED || atype == AtomicDataType::TEXT || - atype == AtomicDataType::DATETIME) { - return; - } - if (atype == AtomicDataType::DOUBLE) { - std::vector<double> data; - for (auto &d : value.AsList()) { - data.push_back(std::stod(d.AsString())); - } - new_value = Value(data); - } else if (atype == AtomicDataType::INTEGER) { - std::vector<int32_t> data; - for (auto &d : value.AsList()) { - data.push_back(std::stoi(d.AsString())); - } - new_value = Value(data); - } else if (atype == AtomicDataType::BOOLEAN) { - std::vector<bool> data; - for (auto &d : value.AsList()) { - const auto &bool_value = d.AsString(); - if (boost::to_upper_copy(bool_value) == "TRUE") { - data.push_back(true); - } else if (boost::to_upper_copy(bool_value) == "FALSE") { - data.push_back(false); - } else { - throw caosdb::exceptions::Exception(StatusCode::OTHER_CLIENT_ERROR, - "Boolean value is neither true nor false."); - } - } - new_value = Value(data); - } else { - std::cout << "Unhandled datatype: " << ent->ToString() << std::endl; - throw std::logic_error("Unhandled datatype"); - } - } else { // Scalar Datatype - if (value.IsList()) { - throw caosdb::exceptions::Exception(StatusCode::OTHER_CLIENT_ERROR, - "Value is list, but DataType is scalar."); - } - atype = dtype.AsAtomic(); - if (!dtype.IsAtomic() // References, strings etc. need no treatment. - || atype == AtomicDataType::UNSPECIFIED || atype == AtomicDataType::TEXT || - atype == AtomicDataType::DATETIME) { - return; - } - CAOSDB_LOG_TRACE(logger_name) << "AtomicDataType: " - << caosdb::utility::getEnumNameFromValue(atype); - if (atype == AtomicDataType::DOUBLE) { - CAOSDB_LOG_TRACE(logger_name) << "double: " << value.AsString(); - new_value = Value(std::strtod(value.AsString().c_str(), nullptr)); - CAOSDB_LOG_TRACE(logger_name) << " -> " << new_value.AsDouble(); - } else if (atype == AtomicDataType::INTEGER) { - new_value = Value(std::stol(value.AsString())); - } else if (atype == AtomicDataType::BOOLEAN) { - const auto &bool_value = value.AsString(); - if (boost::to_upper_copy(bool_value) == "TRUE") { - new_value = Value(true); - } else if (boost::to_upper_copy(bool_value) == "FALSE") { - new_value = Value(false); - } else { - throw caosdb::exceptions::Exception(StatusCode::OTHER_CLIENT_ERROR, - "Boolean value is neither true nor false."); - } - } else { - std::cout << "Unhandled datatype: " << ent->ToString() << std::endl; - throw std::logic_error("Unhandled datatype"); - } - } - - ent->SetValue(new_value); -} - } // namespace caosdb::entity diff --git a/src/caosdb/status_code_description.cpp b/src/caosdb/status_code_description.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72e11e0ce4fa5663da6f7ed3617033714110d417 --- /dev/null +++ b/src/caosdb/status_code_description.cpp @@ -0,0 +1,170 @@ +/* + * This file is a part of the CaosDB Project. + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * 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/status_code.h" // for StatusCode, ABORTED, ALREADY_EXISTS +#include <map> // for allocator, map +#include <stdexcept> // for out_of_range +#include <string> // for string, basic_string + +namespace caosdb { + +/* + * The descriptions of the StatusCodes 1-16 are originally taken from + * https://github.com/grpc/grpc/blob/ce5b4e949fc75ed4c19e9ccfec7dc95c8ee9ae45/doc/statuscodes.md + * and adapted to our purposes. + * + * They are origially released under an Apache-2.0 license in the linked + * repository. However, the linked file itself does not contain a copyright or + * license statement and so we have to assume that the copyright holders are an + * unknown subset of the contributers of that repository: + * + * Copyright (C) 2015-2021 unknown gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +auto get_status_description(int code) -> const std::string & { + static const std::string MISSING_DESCRIPTION = "MISSING DESCRIPTION"; + static const std::map<int, std::string> descriptions = { + {StatusCode::INITIAL, "The transaction has just been intialized. It has not been executed yet " + "and clients can still change it and add sub-transactions."}, + {StatusCode::GO_ON, "The transaction has a transaction_type yet and clients may add matching " + "sub-transaction or execute it right-away."}, + {StatusCode::READY, "The transaction is ready for execution and cannot be changed anymore."}, + {StatusCode::EXECUTING, "The transaction is currently being executed."}, + {StatusCode::SUCCESS, "The action was successful"}, + + {StatusCode::CANCELLED, "The operation was cancelled (typically by the caller)."}, + {StatusCode::UNKNOWN, "Unknown error. This is typically a bug (server or client)."}, + {StatusCode::INVALID_ARGUMENT, + "Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. " + "INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the " + "system (e.g., a malformed file name)."}, + {StatusCode::DEADLINE_EXCEEDED, + "Deadline expired before operation could complete. For operations that change the state of " + "the system, this error may be returned even if the operation has completed successfully. For " + "example, a successful response from a server could have been delayed long enough for the " + "deadline to expire."}, + {StatusCode::NOT_FOUND, "Some requested entity (e.g., file or directory) was not found."}, + {StatusCode::ALREADY_EXISTS, + "Some entity that we attempted to create (e.g., file or directory) already exists."}, + {StatusCode::PERMISSION_DENIED, + "The caller does not have permission to execute the specified operation. PERMISSION_DENIED " + "must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED " + "instead for those errors). PERMISSION_DENIED must not be used if the caller can not be " + "identified (use UNAUTHENTICATED instead for those errors)."}, + {StatusCode::RESOURCE_EXHAUSTED, "Some resource has been exhausted, perhaps a per-user quota, " + "or perhaps the entire file system is out of space."}, + {StatusCode::FAILED_PRECONDITION, + "Operation was rejected because the system is not in a state required for the operation's " + "execution. For example, directory to be deleted may be non-empty, an rmdir operation is " + "applied to a non-directory, etc. A litmus test that may help a service implementor in " + "deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: (a) Use UNAVAILABLE if the " + "client can retry just the failing call. (b) Use ABORTED if the client should retry at a " + "higher-level (e.g., restarting a read-modify-write sequence). (c) Use FAILED_PRECONDITION if " + "the client should not retry until the system state has been explicitly fixed. E.g., if an " + "'rmdir' fails because the directory is non-empty, FAILED_PRECONDITION should be returned " + "since the client should not retry unless they have first fixed up the directory by deleting " + "files from it. (d) Use FAILED_PRECONDITION if the client performs conditional REST " + "Get/Update/Delete on a resource and the resource on the server does not match the condition. " + "E.g., conflicting read-modify-write on the same resource."}, + {StatusCode::ABORTED, + "The operation was aborted, typically due to a concurrency issue like sequencer check " + "failures, transaction aborts, etc. See litmus test above for deciding between " + "FAILED_PRECONDITION, ABORTED, and UNAVAILABLE."}, + {StatusCode::OUT_OF_RANGE, + "Operation was attempted past the valid range. E.g., seeking or reading past end of file. " + "Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system " + "state changes. For example, a 32-bit file system will generate INVALID_ARGUMENT if asked to " + "read at an offset that is not in the range [0,2^32-1], but it will generate OUT_OF_RANGE if " + "asked to read from an offset past the current file size. There is a fair bit of overlap " + "between FAILED_PRECONDITION and OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more " + "specific error) when it applies so that callers who are iterating through a space can easily " + "look for an OUT_OF_RANGE error to detect when they are done."}, + {StatusCode::UNIMPLEMENTED, + "Operation is not implemented or not supported/enabled in this service. In contrast to " + "UNSUPPORTED_FEATURE (which is a client error) this error indicates that the server does not " + "support this operation."}, + {StatusCode::INTERNAL, + "Internal errors. Means some invariants expected by underlying System has been broken. If you " + "see one of these errors, Something is very broken. "}, + {StatusCode::DATA_LOSS, "Unrecoverable data loss or corruption."}, + + {StatusCode::CONNECTION_ERROR, + "The attempt to execute this transaction was not successful because the " + "connection to the server could not be established."}, + {StatusCode::AUTHENTICATION_ERROR, + "The attempt to execute this transaction has not been executed at all " + "because the authentication did not succeed."}, + {StatusCode::GENERIC_RPC_ERROR, + "The attempt to execute this transaction was not successful because an " + "error occured in the transport or RPC protocol layer."}, + {StatusCode::GENERIC_ERROR, "An error occured. Please review the logs for more information."}, + {StatusCode::GENERIC_TRANSACTION_ERROR, + "The transaction terminated unsuccessfully with transaction errors."}, + {StatusCode::CONFIGURATION_ERROR, + "An error occurred during the configuration of the ConfigurationManager."}, + {StatusCode::UNKNOWN_CONNECTION_ERROR, + "The ConnectionManager does not know any connection of this name."}, + {StatusCode::TRANSACTION_STATUS_ERROR, + "The Transaction is in a wrong state for the attempted action."}, + {StatusCode::TRANSACTION_TYPE_ERROR, + "The Transaction has a transaction type which does not allow the " + "attempted action."}, + {StatusCode::ORIGINAL_ENTITY_MISSING_ID, + "The attempt to update this entity failed because this entity does not " + "have " + "an id. This is the case when you did not retrieve it before applying any " + "changes and instantiated the Entity class explicitely."}, + {StatusCode::NOT_A_FILE_ENTITY, "You can only add files to file entities."}, + {StatusCode::PATH_IS_A_DIRECTORY, "The given path is a directory."}, + {StatusCode::FILE_DOES_NOT_EXIST_LOCALLY, + "The file does not not exist in the local file system."}, + {StatusCode::FILE_DOWNLOAD_ERROR, "The transaction failed during the download of the files"}, + {StatusCode::FILE_UPLOAD_ERROR, "The transaction failed during the upload of the files"}, + {StatusCode::UNSUPPORTED_FEATURE, + "This feature is not available in the this client implementation."}, + {StatusCode::EXTERN_C_ASSIGNMENT_ERROR, + "You tried to assign a new object to the wrapped void pointer. You have " + "to delete the old pointee first."}, + {StatusCode::ENUM_MAPPING_ERROR, + "The role, importance, or datatype you specified does not exist."}, + {StatusCode::OTHER_CLIENT_ERROR, + "This is code is reserved to errors raised by other clients wrapping the " + "C++ client (or its Extern C interface). This should never occur when " + "working with the C++ code itself."}}; + try { + return descriptions.at(code); + } catch (const std::out_of_range &exc) { + return MISSING_DESCRIPTION; + } +} + +} // namespace caosdb diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp index 58bf54e92554f4660293a869954e9e3482eebdf7..551d90560498a2aee4b3ce169d416079e8cc80c0 100644 --- a/src/caosdb/transaction.cpp +++ b/src/caosdb/transaction.cpp @@ -43,74 +43,8 @@ #include <iosfwd> // for streamsize #include <map> // for map, operator!= #include <memory> // for unique_ptr -#include <stdexcept> // for out_of_range #include <utility> // for move, pair -namespace caosdb { - -// TODO(tf) move to another source file. -auto get_status_description(int code) -> const std::string & { - static const std::string MISSING_DESCRIPTION = "MISSING DESCRIPTION"; - static const std::map<int, std::string> descriptions = { - {StatusCode::INITIAL, "The transaction has just been intialized. It has not been executed yet " - "and clients can still change it and add sub-transactions."}, - {StatusCode::GO_ON, "The transaction has a transaction_type yet and clients may add matching " - "sub-transaction or execute it right-away."}, - {StatusCode::READY, "The transaction is ready for execution and cannot be changed anymore."}, - {StatusCode::EXECUTING, "The transaction is currently being executed."}, - {StatusCode::SUCCESS, "The action was successful"}, - {StatusCode::CONNECTION_ERROR, - "The attempt to execute this transaction was not successful because the " - "connection to the server could not be established."}, - {StatusCode::AUTHENTICATION_ERROR, - "The attempt to execute this transaction has not been executed at all " - "because the authentication did not succeed."}, - {StatusCode::GENERIC_RPC_ERROR, - "The attempt to execute this transaction was not successful because an " - "error occured in the transport or RPC protocol layer."}, - {StatusCode::GENERIC_ERROR, "An error occured. Please review the logs for more information."}, - {StatusCode::GENERIC_TRANSACTION_ERROR, - "The transaction terminated unsuccessfully with transaction errors."}, - {StatusCode::CONFIGURATION_ERROR, - "An error occurred during the configuration of the ConfigurationManager."}, - {StatusCode::UNKNOWN_CONNECTION_ERROR, - "The ConnectionManager does not know any connection of this name."}, - {StatusCode::TRANSACTION_STATUS_ERROR, - "The Transaction is in a wrong state for the attempted action."}, - {StatusCode::TRANSACTION_TYPE_ERROR, - "The Transaction has a transaction type which does not allow the " - "attempted action."}, - {StatusCode::ORIGINAL_ENTITY_MISSING_ID, - "The attempt to update this entity failed because this entity does not " - "have " - "an id. This is the case when you did not retrieve it before applying any " - "changes and instantiated the Entity class explicitely."}, - {StatusCode::NOT_A_FILE_ENTITY, "You can only add files to file entities."}, - {StatusCode::PATH_IS_A_DIRECTORY, "The given path is a directory."}, - {StatusCode::FILE_DOES_NOT_EXIST_LOCALLY, - "The file does not not exist in the local file system."}, - {StatusCode::FILE_DOWNLOAD_ERROR, "The transaction failed during the download of the files"}, - {StatusCode::FILE_UPLOAD_ERROR, "The transaction failed during the upload of the files"}, - {StatusCode::UNSUPPORTED_FEATURE, - "This feature is not available in the this client implementation."}, - {StatusCode::EXTERN_C_ASSIGNMENT_ERROR, - "You tried to assign a new object to the wrapped void pointer. You have " - "to delete the old pointee first."}, - {StatusCode::ENUM_MAPPING_ERROR, - "The role, importance, or datatype you specified does not exist."}, - {StatusCode::OTHER_CLIENT_ERROR, - "This is code is reserved to errors raised by other clients wrapping the " - "C++ client (or its Extern C interface). This should never occur when " - "working with the C++ code itself."}}; - try { - return descriptions.at(code); - } catch (const std::out_of_range &exc) { - return MISSING_DESCRIPTION; - } -} - -} // namespace caosdb - namespace caosdb::transaction { using caosdb::entity::v1alpha1::EntityTransactionService; using caosdb::entity::v1alpha1::FileTransmissionService; diff --git a/src/caosdb/utility.cpp b/src/caosdb/utility.cpp index d049b91c4ce06337de57f24715df983e80ba88e3..a4ed293adb6bd4fbfb10860e03185aeb567de163 100644 --- a/src/caosdb/utility.cpp +++ b/src/caosdb/utility.cpp @@ -18,10 +18,11 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ -#include "caosdb/data_type.h" -#include "caosdb/entity.h" #include "caosdb/utility.h" -#include <algorithm> +#include "caosdb/data_type.h" // for AtomicDataType, atomicdatatype_names +#include "caosdb/entity.h" // for Importance, Role, importance_names +#include <map> // for map, operator!=, _Rb_tree_const_iterator +#include <utility> // for pair namespace caosdb::utility { diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp index 475a5d1a96cb89a3b10ea9e29b0d3e6ab80a6b5d..90e72e59ebf69102c1abd2edbde1c1cbebc9ab79 100644 --- a/test/test_ccaosdb.cpp +++ b/test/test_ccaosdb.cpp @@ -28,8 +28,7 @@ #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, EXPECT_EQ, TEST -#include <iostream> -#include <string> // for allocator +#include <string> // for allocator, operator+, string,... class test_ccaosdb : public ::testing::Test { protected: diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp index 9200a68356695b5bde9bbd1e2125e604ea2c078c..bb2e97ba412d52a979e060f2d9920d591c07e9e8 100644 --- a/test/test_data_type.cpp +++ b/test/test_data_type.cpp @@ -22,7 +22,9 @@ #include "caosdb/data_type.h" // for DataType, AtomicDataType #include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1alpha1/main.pb.h" // for DataType, Ato... #include "caosdb/logging.h" // for CAOSDB_LOG_DEBUG +#include "caosdb/protobuf_helper.h" // for CAOSDB_DEBUG_... #include <boost/log/core/record.hpp> // for record #include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... #include <boost/log/sources/record_ostream.hpp> // for operator<< @@ -32,7 +34,9 @@ #include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... #include <gtest/gtest_pred_impl.h> // for AssertionResult, Test #include <iosfwd> // for streamsize +#include <map> // for map, operator!= #include <string> // for allocator +#include <utility> // for pair namespace caosdb::entity { using ProtoEntity = caosdb::entity::v1alpha1::Entity; diff --git a/test/test_entity.cpp b/test/test_entity.cpp index 95c451d8d83154352731f1947d3972586e5b6a79..df196c124de8901dc047f2fdafe8efaa2e789939 100644 --- a/test/test_entity.cpp +++ b/test/test_entity.cpp @@ -20,25 +20,24 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ -#include "caosdb_test_utility.h" #include "caosdb/data_type.h" // for DataType, AtomicDat... -#include "caosdb/entity.h" // for Entity, Parent, Par... +#include "caosdb/entity.h" // for Entity, Property #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe... #include "caosdb/entity/v1alpha1/main.pb.h" // for IdResponse, Message -#include "caosdb/message_code.h" // for MessageCode +#include "caosdb/message_code.h" // for MessageCode, ENTITY... #include "caosdb/protobuf_helper.h" // for get_arena #include "caosdb/status_code.h" // for StatusCode, FILE_DO... #include "caosdb/transaction.h" // for Transaction #include "caosdb/value.h" // for Value -#include <exception> -#include <google/protobuf/arena.h> // for Arena -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, Sui... -#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ -#include <iostream> -#include <memory> // for allocator, shared_ptr -#include <stdexcept> -#include <string> // for operator+, string +#include "caosdb_test_utility.h" // for TEST_DATA_DIR +#include <google/protobuf/arena.h> // for Arena +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, Sui... +#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ +#include <iostream> // for operator<<, basic_o... +#include <memory> // for allocator, shared_ptr +#include <stdexcept> // for out_of_range +#include <string> // for operator+, to_string namespace caosdb::entity { using caosdb::entity::v1alpha1::IdResponse; diff --git a/test/test_issues.cpp b/test/test_issues.cpp index 2b414a76a3ee122fe2d622bdf685262e2eb4e56b..389c8ee40c12a89a347a811cca5a4e7dd756068e 100644 --- a/test/test_issues.cpp +++ b/test/test_issues.cpp @@ -17,14 +17,15 @@ * 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/exceptions.h" // for ConnectionError -#include "caosdb/status_code.h" -#include "caosdb/transaction.h" // for Transaction -#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 +#include "caosdb/configuration.h" // for InsecureConnectionConfig... +#include "caosdb/connection.h" // for Connection +#include "caosdb/status_code.h" // for StatusCode, EXECUTING +#include "caosdb/transaction.h" // for Transaction +#include "caosdb/transaction_status.h" // for StatusCode +#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 +#include <memory> // for allocator, unique_ptr namespace caosdb::transaction { using caosdb::configuration::InsecureConnectionConfiguration; diff --git a/test/test_utility.cpp b/test/test_utility.cpp index a64fcee8c94fa527692bbd96ca0b54f94bd6f524..875cfbfcf199100d4a03d847680c997ecc4cb582 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -31,7 +31,10 @@ #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for TestPartResult, SuiteA... #include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, TestInfo +#include <map> // for map, operator!=, _Rb_t... +#include <stdexcept> // for out_of_range #include <string> // for allocator, string, ope... +#include <utility> // for pair namespace caosdb::utility { using ::testing::ElementsAre; @@ -73,9 +76,6 @@ TEST(test_utility, enum_names) { // Some non-working examples EXPECT_THROW_MESSAGE(getEnumValueFromName<caosdb::entity::Importance>("Invalid name"), std::out_of_range, "Could not find enum value for string 'Invalid name'."); - enum e1 { a }; - EXPECT_THROW_STARTS_WITH(getEnumNameFromValue<e1>(a), std::logic_error, "Enum type "); - EXPECT_THROW_STARTS_WITH(getEnumValueFromName<e1>("Hello!"), std::logic_error, "Enum type "); } } // namespace caosdb::utility