Bladeren bron

Add status message handling for async calls

- Add status message handling
- Implement tests
TODO: sync call fail test need interface changes
Alexey Edelev 5 jaren geleden
bovenliggende
commit
b186fb9ad7

+ 4 - 2
src/grpc/qgrpchttp2channel.cpp

@@ -88,6 +88,7 @@ const char *GrpcAcceptEncodingHeader = "grpc-accept-encoding";
 const char *AcceptEncodingHeader = "accept-encoding";
 const char *TEHeader = "te";
 const char *GrpcStatusHeader = "grpc-status";
+const char *GrpcStatusMessage = "grpc-message";
 }
 
 namespace qtprotobuf {
@@ -228,7 +229,7 @@ void QGrpcHttp2Channel::call(const QString &method, const QString &service, cons
             reply->finished();
         } else {
             reply->setData({});
-            reply->error(grpcStatus, QString()); //TODO: read error message from reply
+            reply->error(grpcStatus, QString::fromUtf8(networkReply->rawHeader(GrpcStatusMessage)));
         }
     });
 
@@ -282,9 +283,10 @@ void QGrpcHttp2Channel::subscribe(const QString &method, const QString &service,
 
     //TODO: seems this connection might be invalid in case if this destroyed.
     //Think about correct handling of this situation
-    QObject::connect(networkReply, &QNetworkReply::finished, [networkReply, this]() {
+    QObject::connect(networkReply, &QNetworkReply::finished, [networkReply, connection, this]() {
         d->activeStreamReplies.erase(networkReply);
         //TODO: implement error handling and subscription recovery here
+        QObject::disconnect(connection);
         QGrpcHttp2ChannelPrivate::abortNetworkReply(networkReply);
     });
 }

+ 69 - 0
tests/test_grpc/clienttest.cpp

@@ -262,3 +262,72 @@ TEST_F(ClientTest, HugeBlobEchoStreamTest)
     QByteArray returnDataHash = QCryptographicHash::hash(result.testBytes(), QCryptographicHash::Sha256);
     ASSERT_TRUE(returnDataHash == dataHash);
 }
+
+TEST_F(ClientTest, StatusMessageAsyncTest)
+{
+    TestServiceClient testClient;
+    testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, InsecureCredentials()));
+    SimpleStringMessage request(QString{"Some status message"});
+    QAbstractGrpcChannel::StatusCode asyncStatus = QAbstractGrpcChannel::StatusCode::Ok;
+    QEventLoop waiter;
+    QString statusMessage;
+
+    QGrpcAsyncReply* reply = testClient.testMethodStatusMessage(request);
+    QObject::connect(reply, &QGrpcAsyncReply::error, reply, [&asyncStatus, &waiter, &statusMessage](QAbstractGrpcChannel::StatusCode code, const QString &msg) {
+        asyncStatus = code;
+        statusMessage = msg;
+        waiter.quit();
+    });
+
+    QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
+    waiter.exec();
+
+    ASSERT_STREQ(statusMessage.toStdString().c_str(), request.testFieldString().toStdString().c_str());
+}
+
+TEST_F(ClientTest, StatusMessageClientAsyncTest)
+{
+    TestServiceClient testClient;
+    testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, InsecureCredentials()));
+    SimpleStringMessage request(QString{"Some status message"});
+    QAbstractGrpcChannel::StatusCode asyncStatus = QAbstractGrpcChannel::StatusCode::Ok;
+    QEventLoop waiter;
+    QString statusMessage;
+
+    QObject::connect(&testClient, &TestServiceClient::error, [&asyncStatus, &waiter, &statusMessage](QAbstractGrpcChannel::StatusCode code, const QString &msg) {
+        asyncStatus = code;
+        statusMessage = msg;
+        waiter.quit();
+    });
+
+    testClient.testMethodStatusMessage(request);
+
+    QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
+    waiter.exec();
+
+    ASSERT_STREQ(statusMessage.toStdString().c_str(), request.testFieldString().toStdString().c_str());
+}
+
+TEST_F(ClientTest, DISABLED_StatusMessageClientSyncTest)
+{
+    TestServiceClient testClient;
+    testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(m_echoServerAddress, InsecureCredentials()));
+    SimpleStringMessage request(QString{"Some status message"});
+    QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
+    QAbstractGrpcChannel::StatusCode asyncStatus = QAbstractGrpcChannel::StatusCode::Ok;
+    QEventLoop waiter;
+    QString statusMessage;
+
+    QObject::connect(&testClient, &TestServiceClient::error, [&asyncStatus, &waiter, &statusMessage](QAbstractGrpcChannel::StatusCode code, const QString &msg) {
+        asyncStatus = code;
+        statusMessage = msg;
+        waiter.quit();
+    });
+
+    testClient.testMethodStatusMessage(request, ret);
+    QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
+    waiter.exec();
+
+    ASSERT_STREQ(statusMessage.toStdString().c_str(), request.testFieldString().toStdString().c_str());
+    delete ret;
+}

+ 7 - 0
tests/test_grpc/echoserver/main.cpp

@@ -56,6 +56,13 @@ public:
         writer->Write(msg);
         return ::grpc::Status();
     }
+
+    ::grpc::Status testMethodStatusMessage(::grpc::ServerContext*,
+                                                   const ::qtprotobufnamespace::tests::SimpleStringMessage* request,
+                                                   ::qtprotobufnamespace::tests::SimpleStringMessage*) override
+    {
+        return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, request->testfieldstring());
+    }
 };
 
 int main(int, char *[])

+ 1 - 0
tests/test_grpc/proto/testservice.proto

@@ -10,4 +10,5 @@ service TestService {
   rpc testMethodClientStream(stream SimpleStringMessage) returns (SimpleStringMessage) {}
   rpc testMethodBiStream(stream SimpleStringMessage) returns (stream SimpleStringMessage) {}
   rpc testMethodBlobServerStream(BlobMessage) returns (stream BlobMessage) {}
+  rpc testMethodStatusMessage(SimpleStringMessage) returns (SimpleStringMessage) {}
 }