From 6d92416d6c11786712a8b8e32dd3748c5b419360 Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Fri, 29 Oct 2021 23:58:20 +0200
Subject: [PATCH] refactor erros

---
 common/cpp/include/asapo/common/error.h       | 77 ++++++++-----------
 common/cpp/include/asapo/common/error.tpp     | 74 ++++++++++++++++++
 common/cpp/include/asapo/logger/logger.h      |  1 +
 common/cpp/src/logger/logger.cpp              |  1 +
 .../test_receiver_discovery_service.cpp       |  2 +-
 .../test_request_handler_receive_data.cpp     |  2 +-
 .../test_request_handler_receive_metadata.cpp |  2 +-
 .../test_statistics_sender_influx_db.cpp      |  2 +-
 receiver/unittests/test_request.cpp           |  2 +-
 9 files changed, 113 insertions(+), 50 deletions(-)
 create mode 100644 common/cpp/include/asapo/common/error.tpp

diff --git a/common/cpp/include/asapo/common/error.h b/common/cpp/include/asapo/common/error.h
index 53dbb4473..4363fb05b 100644
--- a/common/cpp/include/asapo/common/error.h
+++ b/common/cpp/include/asapo/common/error.h
@@ -5,21 +5,26 @@
 #include <memory>
 #include <utility>
 #include <ostream>
+
 namespace asapo {
 
 class ErrorInterface;
 class ErrorTemplateInterface;
 class CustomErrorData;
 
+
 using Error = std::unique_ptr<ErrorInterface>;
 
 class ErrorInterface {
   public:
     virtual std::string Explain() const noexcept = 0;
+    virtual std::string ExplainInJSON() const noexcept = 0;
     virtual void Append(const std::string& value) noexcept = 0;
     virtual void Prepend(const std::string& value) noexcept = 0;
-    virtual CustomErrorData* GetCustomData() = 0;
-    virtual void SetCustomData(std::unique_ptr<CustomErrorData> data) = 0;
+    virtual ErrorInterface* AddContext(std::string context) noexcept = 0;
+    virtual ErrorInterface* AddCause(Error cause_err) noexcept = 0;
+    virtual CustomErrorData* GetCustomData() noexcept = 0;
+    virtual void SetCustomData(std::unique_ptr<CustomErrorData> data) noexcept = 0;
     virtual ~ErrorInterface() = default; // needed for unique_ptr to delete itself
 };
 
@@ -42,45 +47,28 @@ template<typename ServiceErrorType>
 class ServiceError : public ErrorInterface {
   private:
     ServiceErrorType error_type_;
-    std::string error_;
+    std::string error_name_;
+    std::string error_message_;
+    std::string context_;
+    Error cause_err_;
     std::unique_ptr<CustomErrorData> custom_data_;
   public:
-    ServiceError(const std::string& error, ServiceErrorType error_type) : error_type_{error_type},
-        error_{std::move(error)} {
-    }
-    ServiceErrorType GetServiceErrorType() const noexcept {
-        return error_type_;
-    }
-    CustomErrorData* GetCustomData() override {
-        if (custom_data_) {
-            return custom_data_.get();
-        } else {
-            return nullptr;
-        }
-    };
-
-    void SetCustomData(std::unique_ptr<CustomErrorData> data) override {
-        custom_data_ = std::move(data);
-    }
-
-    void Append(const std::string& value) noexcept override {
-        error_ += ": " + value;
-    }
-
-    void Prepend(const std::string& value) noexcept override {
-        error_ = value + ": " + error_;
-    }
-
-    std::string Explain() const noexcept override {
-        return error_;
-    }
+    ServiceError(std::string error_name, std::string error_message, ServiceErrorType error_type);
+    ServiceErrorType GetServiceErrorType() const noexcept;
+    CustomErrorData* GetCustomData() noexcept override;
+    void SetCustomData(std::unique_ptr<CustomErrorData> data) noexcept override;
+    void Append(const std::string& value) noexcept override;
+    void Prepend(const std::string& value) noexcept override;
+    ErrorInterface* AddContext(std::string context) noexcept override;
+    ErrorInterface* AddCause(Error cause_err) noexcept override;
+    std::string Explain() const noexcept override;
+    std::string ExplainInJSON() const noexcept override;
 };
 
 class ErrorTemplateInterface {
   public:
     virtual Error Generate() const noexcept = 0;
-    virtual Error Generate(const std::string& suffix) const noexcept = 0;
-
+    virtual Error Generate(std::string error_message) const noexcept = 0;
     virtual bool operator==(const Error& rhs) const = 0;
     virtual bool operator!=(const Error& rhs) const = 0;
 
@@ -97,30 +85,25 @@ static inline bool operator!=(const Error& lhs, const ErrorTemplateInterface& rh
 template<typename ServiceErrorType>
 class ServiceErrorTemplate : public ErrorTemplateInterface {
   private:
-    std::string error_;
+    std::string error_name_;
     ServiceErrorType error_type_;
   public:
-    ServiceErrorTemplate(const std::string& error, ServiceErrorType error_type) {
-        error_ = error;
+    ServiceErrorTemplate(const std::string& error_name, ServiceErrorType error_type) {
+        error_name_ = error_name;
         error_type_ = error_type;
     }
 
     const std::string& Text() const noexcept {
-        return error_;
+        return error_name_;
     }
 
     ServiceErrorType GetServiceErrorType() const noexcept {
         return error_type_;
     }
 
-    Error Generate() const noexcept override{
-        auto err = new ServiceError<ServiceErrorType>(error_, error_type_);
-        return Error(err);
-    }
+    Error Generate() const noexcept override;
 
-    Error Generate(const std::string& suffix) const noexcept override {
-        return Error(new ServiceError<ServiceErrorType>(error_ + (error_.empty() ? "" : ": ") + suffix, error_type_));
-    }
+    Error Generate(std::string error_message) const noexcept override;
 
     inline bool operator==(const Error& rhs) const override {
         return rhs != nullptr
@@ -170,4 +153,8 @@ auto const kSimpleError = GeneralErrorTemplate {
 }
 
 }
+
+#include "error.tpp"
+
+
 #endif //ASAPO_ERROR_H
diff --git a/common/cpp/include/asapo/common/error.tpp b/common/cpp/include/asapo/common/error.tpp
new file mode 100644
index 000000000..384014fcf
--- /dev/null
+++ b/common/cpp/include/asapo/common/error.tpp
@@ -0,0 +1,74 @@
+
+#include "error.h"
+
+namespace asapo {
+
+template<typename ServiceErrorType>
+ServiceError<ServiceErrorType>::ServiceError(std::string error_name,
+                                             std::string error_message,
+                                             ServiceErrorType error_type) : error_type_{
+    error_type}, error_name_{std::move(error_name)}, error_message_{std::move(error_message)} {
+}
+
+template<typename ServiceErrorType>
+ServiceErrorType ServiceError<ServiceErrorType>::GetServiceErrorType() const noexcept {
+    return error_type_;
+}
+
+template<typename ServiceErrorType>
+CustomErrorData *ServiceError<ServiceErrorType>::GetCustomData() noexcept {
+    if (custom_data_) {
+        return custom_data_.get();
+    } else {
+        return nullptr;
+    }
+}
+
+template<typename ServiceErrorType>
+void ServiceError<ServiceErrorType>::SetCustomData(std::unique_ptr<CustomErrorData> data) noexcept {
+    custom_data_ = std::move(data);
+}
+
+template<typename ServiceErrorType>
+void ServiceError<ServiceErrorType>::Append(const std::string &value) noexcept {
+    error_message_ += ": " + value;
+}
+
+template<typename ServiceErrorType>
+void ServiceError<ServiceErrorType>::Prepend(const std::string &value) noexcept {
+    error_message_ = value + ": " + error_message_;
+
+}
+
+template<typename ServiceErrorType>
+std::string ServiceError<ServiceErrorType>::Explain() const noexcept {
+    return error_name_ + ": " + error_message_;
+}
+
+template<typename ServiceErrorType>
+ErrorInterface *ServiceError<ServiceErrorType>::AddContext(std::string context) noexcept {
+    context_ = std::move(context);
+    return this;
+}
+template<typename ServiceErrorType>
+ErrorInterface *ServiceError<ServiceErrorType>::AddCause(Error cause_err) noexcept {
+    cause_err_ = std::move(cause_err);
+    return this;
+}
+
+template<typename ServiceErrorType>
+std::string ServiceError<ServiceErrorType>::ExplainInJSON() const noexcept {
+    return std::string();
+}
+
+template<typename ServiceErrorType>
+Error ServiceErrorTemplate<ServiceErrorType>::Generate() const noexcept {
+    auto err = new ServiceError<ServiceErrorType>(error_name_, "", error_type_);
+    return Error(err);
+}
+template<typename ServiceErrorType>
+Error ServiceErrorTemplate<ServiceErrorType>::Generate(std::string error_message) const noexcept {
+    return Error(new ServiceError<ServiceErrorType>(error_name_, std::move(error_message), error_type_));
+}
+
+}
diff --git a/common/cpp/include/asapo/logger/logger.h b/common/cpp/include/asapo/logger/logger.h
index 75fdc958b..3f077d1be 100644
--- a/common/cpp/include/asapo/logger/logger.h
+++ b/common/cpp/include/asapo/logger/logger.h
@@ -6,6 +6,7 @@
 
 #include "asapo/common/error.h"
 #include <ostream>
+
 namespace asapo {
 
 enum class LogLevel {
diff --git a/common/cpp/src/logger/logger.cpp b/common/cpp/src/logger/logger.cpp
index bd474fb53..3d997032b 100644
--- a/common/cpp/src/logger/logger.cpp
+++ b/common/cpp/src/logger/logger.cpp
@@ -2,6 +2,7 @@
 #include <asapo/logger/logger.h>
 
 #include "spd_logger.h"
+#include "asapo/common/error.h"
 
 namespace asapo {
 
diff --git a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
index 0c501e632..c4103b8df 100644
--- a/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
+++ b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
@@ -64,7 +64,7 @@ TEST_F(ReceiversStatusTests, LogWhenHttpError) {
     EXPECT_CALL(*mock_http_client, Get_t(expected_endpoint, _, _))
     .Times(1)
     .WillOnce(
-        DoAll(SetArgPointee<2>(new asapo::IOError("Test Read Error", asapo::IOErrorType::kReadError)),
+        DoAll(SetArgPointee<2>(new asapo::IOError("Test Read Error", "", asapo::IOErrorType::kReadError)),
               Return("")
              ));
 
diff --git a/receiver/unittests/request_handler/test_request_handler_receive_data.cpp b/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
index 33039cf30..d3e679b7c 100644
--- a/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_receive_data.cpp
@@ -69,7 +69,7 @@ void ReceiveDataHandlerTests::ExpectReceive(uint64_t expected_size, bool ok) {
     EXPECT_CALL(mock_io, Receive_t(socket_fd_, _, expected_size, _)).WillOnce(
         DoAll(
             CopyStr(expected_metadata),
-            SetArgPointee<3>(ok ? nullptr : new asapo::IOError("Test Read Error", asapo::IOErrorType::kReadError)),
+            SetArgPointee<3>(ok ? nullptr : new asapo::IOError("Test Read Error", "", asapo::IOErrorType::kReadError)),
             Return(0)
         ));
 
diff --git a/receiver/unittests/request_handler/test_request_handler_receive_metadata.cpp b/receiver/unittests/request_handler/test_request_handler_receive_metadata.cpp
index 1a6c66f04..99b3e4ed5 100644
--- a/receiver/unittests/request_handler/test_request_handler_receive_metadata.cpp
+++ b/receiver/unittests/request_handler/test_request_handler_receive_metadata.cpp
@@ -69,7 +69,7 @@ void ReceiveMetaDataHandlerTests::ExpectReceive(uint64_t expected_size, bool ok)
     EXPECT_CALL(mock_io, Receive_t(socket_fd_, _, expected_size, _)).WillOnce(
         DoAll(
             CopyStr(expected_metadata),
-            SetArgPointee<3>(ok ? nullptr : new asapo::IOError("Test Read Error", asapo::IOErrorType::kReadError)),
+            SetArgPointee<3>(ok ? nullptr : new asapo::IOError("Test Read Error", "", asapo::IOErrorType::kReadError)),
             Return(0)
         ));
 
diff --git a/receiver/unittests/statistics/test_statistics_sender_influx_db.cpp b/receiver/unittests/statistics/test_statistics_sender_influx_db.cpp
index cb7116bf5..fef03d5a8 100644
--- a/receiver/unittests/statistics/test_statistics_sender_influx_db.cpp
+++ b/receiver/unittests/statistics/test_statistics_sender_influx_db.cpp
@@ -64,7 +64,7 @@ TEST_F(SenderInfluxDbTests, SendStatisticsCallsPost) {
                                 "n_requests=4,db_share=0.1000,network_share=0.3000,disk_share=0.6000";
     EXPECT_CALL(mock_http_client, Post_t("test_uri/write?db=test_name", _, expect_string, _, _)).
     WillOnce(
-        DoAll(SetArgPointee<4>(new asapo::IOError("Test Read Error", asapo::IOErrorType::kReadError)),
+        DoAll(SetArgPointee<4>(new asapo::IOError("Test Read Error","", asapo::IOErrorType::kReadError)),
               Return("")
              ));
 
diff --git a/receiver/unittests/test_request.cpp b/receiver/unittests/test_request.cpp
index 096ebe890..a8c966690 100644
--- a/receiver/unittests/test_request.cpp
+++ b/receiver/unittests/test_request.cpp
@@ -85,7 +85,7 @@ TEST_F(RequestTests, HandleProcessesRequests) {
     EXPECT_CALL(mock_request_handler, ProcessRequest_t(_)).WillOnce(
         Return(nullptr)
     ).WillOnce(
-        Return(new asapo::IOError("Test Send Error", asapo::IOErrorType::kUnknownIOError))
+        Return(new asapo::IOError("Test Send Error", "", asapo::IOErrorType::kUnknownIOError))
     );
 
     request->AddHandler(&mock_request_handler);
-- 
GitLab