Print error messages to stderr in Cyad 88/34388/6
authorAleksander Zdyb <a.zdyb@samsung.com>
Mon, 2 Feb 2015 13:11:47 +0000 (14:11 +0100)
committerAleksander Zdyb <a.zdyb@samsung.com>
Mon, 23 Feb 2015 13:11:50 +0000 (14:11 +0100)
Every dispatched command checks return value from Cynara API
and prints possible error message using cynara_strerror() function.

Call to cynara_strerror() is not of course subject to above
check & print routine.

Change-Id: I008d1fbd592061646478b47be8ae53bbc408cb1b

src/cyad/BaseErrorApiWrapper.h [new file with mode: 0644]
src/cyad/CMakeLists.txt
src/cyad/CommandsDispatcher.cpp
src/cyad/CommandsDispatcher.h
src/cyad/Cyad.cpp
src/cyad/Cyad.h
src/cyad/ErrorApiWrapper.cpp [new file with mode: 0644]
src/cyad/ErrorApiWrapper.h [new file with mode: 0644]
test/cyad/FakeErrorApiWrapper.h [new file with mode: 0644]
test/cyad/commands_dispatcher.cpp

diff --git a/src/cyad/BaseErrorApiWrapper.h b/src/cyad/BaseErrorApiWrapper.h
new file mode 100644 (file)
index 0000000..721edef
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+/**
+ * @file        src/cyad/BaseErrorApiWrapper.h
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ * @brief       Wrapper around cynara-error API (base)
+ */
+
+#ifndef SRC_CYAD_BASEERRORAPIWRAPPER_H_
+#define SRC_CYAD_BASEERRORAPIWRAPPER_H_
+
+#include <cstddef>
+
+namespace Cynara {
+
+class BaseErrorApiWrapper {
+public:
+    virtual ~BaseErrorApiWrapper() {};
+    virtual int cynara_strerror(int errnum, char *buf, size_t buflen) = 0;
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_CYAD_BASEERRORAPIWRAPPER_H_ */
index 1415f6d..1873046 100644 (file)
@@ -30,6 +30,7 @@ SET(CYAD_SOURCES
     ${CYAD_PATH}/CommandlineParser/HumanReadableParser.cpp
     ${CYAD_PATH}/CommandsDispatcher.cpp
     ${CYAD_PATH}/DispatcherIO.cpp
+    ${CYAD_PATH}/ErrorApiWrapper.cpp
     ${CYAD_PATH}/main.cpp
     )
 
index 0b8f0c0..6862a42 100644 (file)
 
 namespace Cynara {
 
-CommandsDispatcher::CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper)
-    : m_io(io), m_adminApiWrapper(adminApiWrapper), m_cynaraAdmin(nullptr)
+CommandsDispatcher::CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper,
+                                       BaseErrorApiWrapper &errorApiWrapper)
+    : m_io(io), m_adminApiWrapper(adminApiWrapper), m_errorApiWrapper(errorApiWrapper),
+      m_cynaraAdmin(nullptr)
 {
     auto ret = m_adminApiWrapper.cynara_admin_initialize(&m_cynaraAdmin);
-    if (ret != CYNARA_API_SUCCESS)
+    if (ret != CYNARA_API_SUCCESS) {
+        printAdminApiError(ret);
         throw AdminLibraryInitializationFailedException(ret);
+    }
 }
 
 CommandsDispatcher::~CommandsDispatcher() {
-    m_adminApiWrapper.cynara_admin_finish(m_cynaraAdmin);
+    auto ret = m_adminApiWrapper.cynara_admin_finish(m_cynaraAdmin);
+    if (ret != CYNARA_API_SUCCESS)
+        printAdminApiError(ret);
 }
 
 int CommandsDispatcher::execute(CyadCommand &) {
-    m_io.cout() << "Whatever you wanted, it's not implemented" << std::endl;
+    m_io.cerr() << "Whatever you wanted, it's not implemented" << std::endl;
     return CYNARA_API_UNKNOWN_ERROR;
 }
 
@@ -58,25 +64,35 @@ int CommandsDispatcher::execute(HelpCyadCommand &) {
 }
 
 int CommandsDispatcher::execute(ErrorCyadCommand &result) {
-    m_io.cout() << "There was an error in command-line options:" << std::endl;
-    m_io.cout() << result.message() << std::endl;
+    m_io.cerr() << "There was an error in command-line options:" << std::endl;
+    m_io.cerr() << result.message() << std::endl;
 
-    m_io.cout() << std::endl << CmdlineOpts::makeHelp() << std::endl;
+    m_io.cerr() << std::endl << CmdlineOpts::makeHelp() << std::endl;
     return CYNARA_API_INVALID_COMMANDLINE_PARAM;
 }
 
 int CommandsDispatcher::execute(DeleteBucketCyadCommand &result) {
-    return m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, result.bucketId().c_str(),
-                                                     CYNARA_ADMIN_DELETE, nullptr);
+    auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin, result.bucketId().c_str(),
+                                                         CYNARA_ADMIN_DELETE, nullptr);
+
+    if (ret != CYNARA_API_SUCCESS)
+        printAdminApiError(ret);
+
+    return ret;
 }
 
 int CommandsDispatcher::execute(SetBucketCyadCommand &result) {
     const auto &policyResult = result.policyResult();
     const char *metadata = policyResult.metadata().empty() ? nullptr
                                                            : policyResult.metadata().c_str();
-    return m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin,
-                                                     result.bucketId().c_str(),
-                                                     policyResult.policyType(), metadata);
+    auto ret = m_adminApiWrapper.cynara_admin_set_bucket(m_cynaraAdmin,
+                                                         result.bucketId().c_str(),
+                                                         policyResult.policyType(), metadata);
+
+    if (ret != CYNARA_API_SUCCESS)
+        printAdminApiError(ret);
+
+    return ret;
 }
 
 int CommandsDispatcher::execute(SetPolicyCyadCommand &result) {
@@ -85,7 +101,12 @@ int CommandsDispatcher::execute(SetPolicyCyadCommand &result) {
     policies.add(result.bucketId(), result.policyResult(), result.policyKey());
     policies.seal();
 
-    return m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data());
+    auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data());
+
+    if (ret != CYNARA_API_SUCCESS)
+        printAdminApiError(ret);
+
+    return ret;
 }
 
 int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) {
@@ -93,7 +114,10 @@ int CommandsDispatcher::execute(SetPolicyBulkCyadCommand &result) {
 
     try {
         auto policies = Cynara::AdminPolicyParser::parse(input);
-        return m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data());
+        auto ret = m_adminApiWrapper.cynara_admin_set_policies(m_cynaraAdmin, policies.data());
+        if (ret != CYNARA_API_SUCCESS)
+            printAdminApiError(ret);
+        return ret;
     } catch (const BucketRecordCorruptedException &ex) {
         m_io.cerr() << ex.message();
         return CYNARA_API_INVALID_COMMANDLINE_PARAM;
@@ -106,8 +130,13 @@ int CommandsDispatcher::execute(EraseCyadCommand &result) {
     auto user = key.user().toString().c_str();
     auto privilege = key.privilege().toString().c_str();
 
-    return m_adminApiWrapper.cynara_admin_erase(m_cynaraAdmin, result.bucketId().c_str(),
-                                                result.recursive(), client, user, privilege);
+    auto ret = m_adminApiWrapper.cynara_admin_erase(m_cynaraAdmin, result.bucketId().c_str(),
+                                                    result.recursive(), client, user, privilege);
+
+    if (ret != CYNARA_API_SUCCESS)
+        printAdminApiError(ret);
+
+    return ret;
 }
 
 int CommandsDispatcher::execute(CheckCyadCommand &command) {
@@ -133,6 +162,8 @@ int CommandsDispatcher::execute(CheckCyadCommand &command) {
         }
 
         m_io.cout() << std::endl;
+    } else {
+        printAdminApiError(ret);
     }
 
     return ret;
@@ -180,6 +211,8 @@ int CommandsDispatcher::execute(ListPoliciesCyadCommand &command) {
             freePolicy(p);
         }
         free(policies);
+    } else {
+        printAdminApiError(ret);
     }
 
     return ret;
@@ -208,9 +241,28 @@ int CommandsDispatcher::execute(ListPoliciesDescCyadCommand &) {
             freePolicyDesc(p);
         }
         free(descs);
+    } else {
+        printAdminApiError(ret);
     }
 
     return ret;
 }
 
+void CommandsDispatcher::printAdminApiError(int errnum) {
+    const std::size_t buffSize = 256;
+    char buf[buffSize];
+    auto ret = m_errorApiWrapper.cynara_strerror(errnum, buf, buffSize);
+
+    m_io.cerr() << "Cynara: [" << errnum << "] ";
+
+    if (ret == CYNARA_API_SUCCESS)
+        m_io.cerr() << buf << std::endl;
+    else if (ret == CYNARA_API_INVALID_PARAM)
+        m_io.cerr() << "Unknown error (sic!)" << std::endl;
+    else if (ret == CYNARA_API_BUFFER_TOO_SHORT)
+        m_io.cerr() << "Error message too long" << std::endl;
+    else
+        m_io.cerr() << "Unknown error (sic! sic!)" << std::endl;
+}
+
 } /* namespace Cynara */
index b8b7f29..a025303 100644 (file)
@@ -24,6 +24,7 @@
 #define SRC_CYAD_COMMANDSDISPATCHER_H_
 
 #include <cyad/BaseAdminApiWrapper.h>
+#include <cyad/BaseErrorApiWrapper.h>
 #include <cyad/CommandlineParser/CyadCommand.h>
 #include <cyad/DispatcherIO.h>
 
@@ -34,7 +35,8 @@ namespace Cynara {
 
 class CommandsDispatcher {
 public:
-    CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper);
+    CommandsDispatcher(BaseDispatcherIO &io, BaseAdminApiWrapper &adminApiWrapper,
+                       BaseErrorApiWrapper &errorApiWrapper);
     virtual ~CommandsDispatcher();
 
     virtual int execute(CyadCommand &);
@@ -49,9 +51,13 @@ public:
     virtual int execute(ListPoliciesCyadCommand &);
     virtual int execute(ListPoliciesDescCyadCommand &);
 
+protected:
+    void printAdminApiError(int errnum);
+
 private:
     BaseDispatcherIO &m_io;
     BaseAdminApiWrapper &m_adminApiWrapper;
+    BaseErrorApiWrapper &m_errorApiWrapper;
     struct cynara_admin *m_cynaraAdmin;
 };
 
index 092d9a7..1589d14 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ namespace Cynara {
 
 Cyad::Cyad(int argc, char **argv) : m_parser(argc, argv), m_cynaraInitError(CYNARA_API_SUCCESS) {
     try {
-        m_dispatcher.reset(new CommandsDispatcher(m_io, m_adminApiWrapper));
+        m_dispatcher.reset(new CommandsDispatcher(m_io, m_adminApiWrapper, m_errorApiWrapper));
     } catch (const Cynara::AdminLibraryInitializationFailedException &ex) {
         m_cynaraInitError = ex.errorCode();
     }
index ba98fd8..dbb54b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 #include <cyad/CommandlineParser/CyadCommandlineParser.h>
 #include <cyad/CommandsDispatcher.h>
 #include <cyad/DispatcherIO.h>
+#include <cyad/ErrorApiWrapper.h>
 
 namespace Cynara {
 
@@ -42,6 +43,7 @@ public:
 
 private:
     AdminApiWrapper m_adminApiWrapper;
+    ErrorApiWrapper m_errorApiWrapper;
     DispatcherIO m_io;
     std::unique_ptr<CommandsDispatcher> m_dispatcher;
     CyadCommandlineParser m_parser;
diff --git a/src/cyad/ErrorApiWrapper.cpp b/src/cyad/ErrorApiWrapper.cpp
new file mode 100644 (file)
index 0000000..510e43a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+/**
+ * @file        src/cyad/ErrorApiWrapper.cpp
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ * @brief       Wrapper around cynara-error API
+ */
+
+#include <cynara-error.h>
+
+#include "ErrorApiWrapper.h"
+
+namespace Cynara {
+
+ErrorApiWrapper::ErrorApiWrapper() {}
+
+ErrorApiWrapper::~ErrorApiWrapper() {}
+
+int ErrorApiWrapper::cynara_strerror(int errnum, char *buf, size_t buflen) {
+    return ::cynara_strerror(errnum, buf, buflen);
+}
+
+} /* namespace Cynara */
diff --git a/src/cyad/ErrorApiWrapper.h b/src/cyad/ErrorApiWrapper.h
new file mode 100644 (file)
index 0000000..472630f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+/**
+ * @file        src/cyad/ErrorApiWrapper.h
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ * @brief       Wrapper around cynara-error API
+ */
+
+#ifndef SRC_CYAD_ERRORAPIWRAPPER_H_
+#define SRC_CYAD_ERRORAPIWRAPPER_H_
+
+#include "BaseErrorApiWrapper.h"
+
+namespace Cynara {
+
+class ErrorApiWrapper : public BaseErrorApiWrapper {
+public:
+    ErrorApiWrapper();
+    virtual ~ErrorApiWrapper();
+    virtual int cynara_strerror(int errnum, char *buf, size_t buflen);
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_CYAD_ERRORAPIWRAPPER_H_ */
diff --git a/test/cyad/FakeErrorApiWrapper.h b/test/cyad/FakeErrorApiWrapper.h
new file mode 100644 (file)
index 0000000..f1cc51a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+/**
+ * @file        test/cyad/FakeErrorApiWrapper.h
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ * @brief       Wrapper around cynara-error API (mock)
+ */
+
+#ifndef TEST_CYAD_FAKEERRORAPIWRAPPER_H_
+#define TEST_CYAD_FAKEERRORAPIWRAPPER_H_
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <cyad/BaseErrorApiWrapper.h>
+
+class FakeErrorApiWrapper : public Cynara::BaseErrorApiWrapper {
+public:
+    using BaseErrorApiWrapper::BaseErrorApiWrapper;
+
+    MOCK_METHOD3(cynara_strerror,
+                 int((int errnum, char *buf, size_t buflen)));
+};
+
+#endif /* TEST_CYAD_FAKEERRORAPIWRAPPER_H_ */
index 471997e..35a0ab8 100644 (file)
@@ -20,6 +20,7 @@
  * @brief       Tests for CommandsDispatcher
  */
 
+#include <cstring>
 #include <ostream>
 #include <tuple>
 #include <vector>
@@ -39,6 +40,7 @@
 
 #include "CyadCommandlineDispatcherTest.h"
 #include "FakeAdminApiWrapper.h"
+#include "FakeErrorApiWrapper.h"
 #include "helpers.h"
 
 /**
@@ -52,11 +54,12 @@ TEST_F(CyadCommandlineDispatcherTest, noApi) {
     using ::testing::Return;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::CyadCommand result;
     Cynara::HelpCyadCommand helpResult;
@@ -74,11 +77,12 @@ TEST_F(CyadCommandlineDispatcherTest, deleteBucket) {
     using ::testing::IsNull;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
     Cynara::DeleteBucketCyadCommand result("test-bucket");
 
     EXPECT_CALL(adminApi,
@@ -98,11 +102,12 @@ TEST_F(CyadCommandlineDispatcherTest, setBucket) {
     using Cynara::PolicyResult;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     typedef std::tuple<PolicyBucketId, PolicyResult> BucketData;
     typedef std::vector<BucketData> Buckets;
@@ -141,11 +146,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicy) {
     using ::testing::Return;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
     Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "" },
                                         { "client", "user", "privilege" });
 
@@ -165,11 +171,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPolicyWithMetadata) {
     using ::testing::Return;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
     Cynara::SetPolicyCyadCommand result("test-bucket", { CYNARA_ADMIN_ALLOW, "metadata" },
                                         Cynara::PolicyKey("client", "user", "privilege"));
 
@@ -189,11 +196,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulk) {
     using ::testing::Return;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
     Cynara::SetPolicyBulkCyadCommand result("-");
 
     // fake stdin ;)
@@ -216,11 +224,12 @@ TEST_F(CyadCommandlineDispatcherTest, setPoliciesBulkInputError) {
     using ::testing::Return;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
     Cynara::SetPolicyBulkCyadCommand result("-");
 
     // fake stdin ;)
@@ -237,11 +246,12 @@ TEST_F(CyadCommandlineDispatcherTest, erase) {
     using ::testing::StrEq;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::EraseCyadCommand command("", true, { "client", "user", "privilege" });
 
@@ -261,11 +271,12 @@ TEST_F(CyadCommandlineDispatcherTest, check) {
     using ::testing::StrEq;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" });
     int result = 42;
@@ -289,11 +300,12 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithMetadata) {
     using ::testing::StrEq;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" });
     int result = 42;
@@ -311,26 +323,38 @@ TEST_F(CyadCommandlineDispatcherTest, checkWithMetadata) {
 
 TEST_F(CyadCommandlineDispatcherTest, checkWithError) {
     using ::testing::_;
+    using ::testing::HasSubstr;
+    using ::testing::Invoke;
     using ::testing::NotNull;
     using ::testing::Return;
     using ::testing::StrEq;
+    using ::testing::Unused;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::CheckCyadCommand command("", true, { "client", "user", "privilege" });
 
+    auto setErrorMessage = [] (Unused, char *buf, std::size_t buflen) {
+        strncpy(buf, "Test error message", buflen);
+    };
+
     EXPECT_CALL(adminApi, cynara_admin_check(_, StrEq(""), true, StrEq("client"), StrEq("user"),
                                              StrEq("privilege"), NotNull(), NotNull()))
         .WillOnce(Return(CYNARA_API_UNKNOWN_ERROR));
 
+    // Should we expect some minimal buflen here?
+    EXPECT_CALL(errorApi, cynara_strerror(CYNARA_API_UNKNOWN_ERROR, NotNull(), _))
+        .WillOnce(DoAll(Invoke(setErrorMessage), Return(CYNARA_API_SUCCESS)));
+
     dispatcher.execute(command);
 
-    ASSERT_TRUE(m_io.coutRaw().str().empty());
+    ASSERT_THAT(m_io.cerrRaw().str(), HasSubstr("Test error message"));
 }
 
 TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) {
@@ -342,11 +366,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesNone) {
     using ::testing::StrEq;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" });
 
@@ -372,11 +397,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesTwo) {
     using ::testing::StrEq;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::ListPoliciesCyadCommand command("", { "client", "user", "privilege" });
 
@@ -404,11 +430,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescNone) {
     using ::testing::SetArgPointee;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::ListPoliciesDescCyadCommand command;
 
@@ -432,11 +459,12 @@ TEST_F(CyadCommandlineDispatcherTest, listPoliciesDescOne) {
     using ::testing::SetArgPointee;
 
     FakeAdminApiWrapper adminApi;
+    FakeErrorApiWrapper errorApi;
 
     EXPECT_CALL(adminApi, cynara_admin_initialize(_)).WillOnce(Return(CYNARA_API_SUCCESS));
     EXPECT_CALL(adminApi, cynara_admin_finish(_)).WillOnce(Return(CYNARA_API_SUCCESS));
 
-    Cynara::CommandsDispatcher dispatcher(m_io, adminApi);
+    Cynara::CommandsDispatcher dispatcher(m_io, adminApi, errorApi);
 
     Cynara::ListPoliciesDescCyadCommand command;