Browse Source

Complete migration to QGrpcStatus

- Change interface for gRPC client sync call
- Add and update tests
Alexey Edelev 5 years ago
parent
commit
ee6992c914

+ 2 - 2
src/generator/templates.cpp

@@ -182,7 +182,7 @@ const char *Templates::MapSerializationRegisterTemplate = "QtProtobuf::QProtobuf
 const char *Templates::ClassDefinitionTemplate = "\nclass $classname$ : public $parent_class$\n"
                                                  "{\n";
 const char *Templates::QObjectMacro = "Q_OBJECT";
-const char *Templates::ClientMethodDeclarationSyncTemplate = "Q_INVOKABLE bool $method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$);\n";
+const char *Templates::ClientMethodDeclarationSyncTemplate = "Q_INVOKABLE QtProtobuf::QGrpcStatus $method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$);\n";
 const char *Templates::ClientMethodDeclarationAsyncTemplate = "Q_INVOKABLE QtProtobuf::QGrpcAsyncReply *$method_name$(const $param_type$ &$param_name$);\n";
 const char *Templates::ClientMethodDeclarationAsync2Template = "Q_INVOKABLE void $method_name$(const $param_type$ &$param_name$, const QObject *context, const std::function<void(QtProtobuf::QGrpcAsyncReply *)> &callback);\n";
 const char *Templates::ServerMethodDeclarationTemplate = "Q_INVOKABLE virtual $return_type$ $method_name$(const $param_type$ &$param_name$) = 0;\n";
@@ -191,7 +191,7 @@ const char *Templates::ServerMethodDeclarationTemplate = "Q_INVOKABLE virtual $r
 const char *Templates::ConstructorDefinitionSyncTemplate = "\n$classname$::$classname$() : $parent_class$(\"$service_name$\")\n"
                                                            "{\n"
                                                            "}\n";
-const char *Templates::ClientMethodDefinitionSyncTemplate = "\nbool $classname$::$method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$)\n"
+const char *Templates::ClientMethodDefinitionSyncTemplate = "\nQtProtobuf::QGrpcStatus $classname$::$method_name$(const $param_type$ &$param_name$, const QPointer<$return_type$> &$return_name$)\n"
                                                             "{\n"
                                                             "    return call(\"$method_name$\", $param_name$, $return_name$);\n"
                                                             "}\n";

+ 5 - 1
src/grpc/qabstractgrpcclient.cpp

@@ -60,7 +60,11 @@ QGrpcStatus QAbstractGrpcClient::call(const QString &method, const QByteArray &a
     if (d->channel) {
         callStatus = d->channel->call(method, d->service, arg, ret);
     } else {
-        error({QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")});
+        callStatus = QGrpcStatus{QGrpcStatus::Unknown, QLatin1String("No channel(s) attached.")};
+    }
+
+    if (callStatus != QGrpcStatus::Ok) {
+        error(callStatus);
     }
 
     return callStatus;

+ 20 - 13
src/grpc/qabstractgrpcclient.h

@@ -79,19 +79,22 @@ protected:
      * \param[out] ret A pointer to memory with protobuf message to write an gRPC reply to
      */
     template<typename A, typename R>
-    bool call(const QString &method, const A &arg, const QPointer<R> &ret) {
+    QGrpcStatus call(const QString &method, const A &arg, const QPointer<R> &ret) {
+        QGrpcStatus status{QGrpcStatus::Ok};
         if (ret.isNull()) {
             static const QString errorString("Unable to call method: %1. Pointer to return data is null");
-            error({QGrpcStatus::InvalidArgument, errorString.arg(method)});
+            status = QGrpcStatus{QGrpcStatus::InvalidArgument, errorString.arg(method)};
+            error(status);
             qProtoCritical() << errorString.arg(method);
-            return false;
+            return status;
         }
 
         QByteArray retData;
-        if (call(method, arg.serialize(), retData) == QGrpcStatus::StatusCode::Ok) {
+        status = call(method, arg.serialize(), retData);
+        if (status == QGrpcStatus::StatusCode::Ok) {
             return tryDeserialize(*ret, retData);
         }
-        return false;
+        return status;
     }
 
     /*!
@@ -175,24 +178,28 @@ private:
      * \brief Deserialization helper
      */
     template<typename R>
-    bool tryDeserialize(R &ret, const QByteArray &retData) {
+    QGrpcStatus tryDeserialize(R &ret, const QByteArray &retData) {
+        QGrpcStatus status{QGrpcStatus::Ok};
         try {
             ret.deserialize(retData);
         } catch (std::invalid_argument &) {
             static const QLatin1String invalidArgumentErrorMessage("Response deserialization failed invalid field found");
-            error({QGrpcStatus::InvalidArgument, invalidArgumentErrorMessage});
+            status = {QGrpcStatus::InvalidArgument, invalidArgumentErrorMessage};
+            error(status);
             qProtoCritical() << invalidArgumentErrorMessage;
-            return false;
+            return status;
         } catch (std::out_of_range &) {
             static const QLatin1String outOfRangeErrorMessage("Invalid size of received buffer");
-            error({QGrpcStatus::OutOfRange, outOfRangeErrorMessage});
+            status = {QGrpcStatus::OutOfRange, outOfRangeErrorMessage};
+            error(status);
             qProtoCritical() << outOfRangeErrorMessage;
-            return false;
+            return status;
         } catch (...) {
-            error({QGrpcStatus::Internal, QLatin1String("Unknown exception caught during deserialization")});
-            return false;
+            status = {QGrpcStatus::Internal, QLatin1String("Unknown exception caught during deserialization")};
+            error(status);
+            return status;
         }
-        return true;
+        return status;
     }
 
     Q_DISABLE_COPY(QAbstractGrpcClient)

+ 9 - 0
src/grpc/qgrpcstatus.cpp

@@ -82,6 +82,11 @@ bool QGrpcStatus::operator ==(StatusCode code) const
     return d->m_code == code;
 }
 
+bool QGrpcStatus::operator !=(StatusCode code) const
+{
+    return d->m_code != code;
+}
+
 bool QGrpcStatus::operator ==(const QGrpcStatus &other) const
 {
     return d->m_code == other.d->m_code;
@@ -93,3 +98,7 @@ bool operator ==(QtProtobuf::QGrpcStatus::StatusCode code, const QtProtobuf::QGr
 {
     return status == code;
 }
+bool operator !=(QtProtobuf::QGrpcStatus::StatusCode code, const QtProtobuf::QGrpcStatus &status)
+{
+    return status != code;
+}

+ 7 - 5
src/grpc/qgrpcstatus.h

@@ -33,7 +33,9 @@ namespace QtProtobuf {
 
 /*!
  * \ingroup QtGrpc
- * \brief The QGrpcStatus class
+ * \brief The QGrpcStatus class contains information about last gRPC operation. In case of error in call/subscription
+ *        processing QGrpcStatus will contain code any of non-Ok QGrpcStatus::StatusCode.
+ *        This class combines QGrpcStatus::StatusCode and message returned from channel or QGrpc framework.
  */
 class QGrpcStatus final {
 public:
@@ -67,18 +69,17 @@ public:
     ~QGrpcStatus();
 
     /*!
-     * \brief code
-     * \return
+     * \brief code getter for QGrpcStatus::StatusCode stored in QGrpcStatus
      */
     StatusCode code() const;
 
     /*!
-     * \brief message
-     * \return
+     * \brief message getter for status message stored in QGrpcStatus
      */
     QString message() const;
 
     bool operator ==(StatusCode code) const;
+    bool operator !=(StatusCode code) const;
     bool operator ==(const QGrpcStatus &other) const;
 
     QGrpcStatus(const QGrpcStatus &other);
@@ -94,3 +95,4 @@ private:
 }
 
 bool operator ==(QtProtobuf::QGrpcStatus::StatusCode code, const QtProtobuf::QGrpcStatus &status);
+bool operator !=(QtProtobuf::QGrpcStatus::StatusCode code, const QtProtobuf::QGrpcStatus &status);

+ 55 - 2
tests/test_grpc/clienttest.cpp

@@ -73,7 +73,7 @@ TEST_F(ClientTest, StringEchoTest)
     SimpleStringMessage request;
     QPointer<SimpleStringMessage> result(new SimpleStringMessage);
     request.setTestFieldString("Hello beach!");
-    ASSERT_TRUE(testClient.testMethod(request, result));
+    ASSERT_TRUE(testClient.testMethod(request, result) == QGrpcStatus::Ok);
     ASSERT_STREQ(result->testFieldString().toStdString().c_str(), "Hello beach!");
     delete result;
 }
@@ -308,7 +308,7 @@ TEST_F(ClientTest, StatusMessageClientAsyncTest)
     ASSERT_STREQ(statusMessage.toStdString().c_str(), request.testFieldString().toStdString().c_str());
 }
 
-TEST_F(ClientTest, DISABLED_StatusMessageClientSyncTest)
+TEST_F(ClientTest, StatusMessageClientSyncTest)
 {
     TestServiceClient testClient;
     testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, InsecureCredentials()));
@@ -331,3 +331,56 @@ TEST_F(ClientTest, DISABLED_StatusMessageClientSyncTest)
     ASSERT_STREQ(statusMessage.toStdString().c_str(), request.testFieldString().toStdString().c_str());
     delete ret;
 }
+
+TEST_F(ClientTest, StatusMessageClientSyncTestReturnedStatus)
+{
+    TestServiceClient testClient;
+    testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, InsecureCredentials()));
+    SimpleStringMessage request(QString{"Some status message"});
+    QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
+    QEventLoop waiter;
+    QString statusMessage;
+
+    QGrpcStatus status = testClient.testMethodStatusMessage(request, ret);
+
+    ASSERT_STREQ(status.message().toStdString().c_str(), request.testFieldString().toStdString().c_str());
+    delete ret;
+}
+
+
+TEST_F(ClientTest, ClientSyncTestUnattachedChannel)
+{
+    TestServiceClient testClient;
+    SimpleStringMessage request(QString{"Some status message"});
+    QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
+    QEventLoop waiter;
+
+    QGrpcStatus status = testClient.testMethodStatusMessage(request, ret);
+
+    ASSERT_EQ(status.code(), QGrpcStatus::Unknown);
+    ASSERT_STREQ("No channel(s) attached.", status.message().toStdString().c_str());
+    delete ret;
+}
+
+TEST_F(ClientTest, ClientSyncTestUnattachedChannelSignal)
+{
+    TestServiceClient testClient;
+    SimpleStringMessage request(QString{"Some status message"});
+    QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
+    QGrpcStatus asyncStatus(QGrpcStatus::StatusCode::Ok);
+    QEventLoop waiter;
+
+    QObject::connect(&testClient, &TestServiceClient::error, [&asyncStatus, &waiter](const QGrpcStatus &status) {
+        asyncStatus = status;
+        waiter.quit();
+    });
+
+    testClient.testMethodStatusMessage(request, ret);
+    QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
+    waiter.exec();
+
+    ASSERT_EQ(asyncStatus, QGrpcStatus::Unknown);
+    ASSERT_STREQ("No channel(s) attached.", asyncStatus.message().toStdString().c_str());
+    delete ret;
+}
+

+ 1 - 1
tests/test_grpc/sslclienttest.cpp

@@ -65,5 +65,5 @@ TEST_F(ClientTest, IncorrectSecureCredentialsTest)
     testClient.attachChannel(std::make_shared<QtProtobuf::QGrpcHttp2Channel>(QUrl("https://localhost:60051", QUrl::StrictMode), QtProtobuf::SslCredentials(conf)));
 
     std::unique_ptr<SimpleStringMessage> result = std::make_unique<SimpleStringMessage>();
-    EXPECT_FALSE(testClient.testMethod(SimpleStringMessage{"Hello beach!"}, result.get()));
+    EXPECT_FALSE(testClient.testMethod(SimpleStringMessage{"Hello beach!"}, result.get()) == QGrpcStatus::Ok);
 }