summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis Oberst <dennis.oberst@qt.io>2024-04-15 13:01:07 +0200
committerDennis Oberst <dennis.oberst@qt.io>2024-04-18 11:14:09 +0200
commit57b875c33bc054fda4c729a063a71ca1ca7cc04e (patch)
tree1d362feabde056146412e9b827358e5ed809305a
parent636b70f93de03dce6ad81fd1d9b27e8a3c43bec8 (diff)
QGrpcOperation: handle failed deserialization directly
Originally motivated by Axivion(SV3), which nagged about the const errorOccurred signal; this patch removes signal emission for failed deserialization in the read() functions. Immediately handling this can lead to better user code as an fallback mechanism can avoid further execution of unneeded logic. This patch makes the errorOcurred signal non-const and changes the signature of the read methods to either return an optional or bool to signal failure immediately. Users can then retrieve the error through 'deserializationError()' or 'deserializationErrorString()'. This can be seen in the generated QML integration code, which uses those to still emit the 'errorOcurred' signal on deserialization failure. Change-Id: Ie6761753145536a42d5dd5bf1eac18afa555581a Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
-rw-r--r--examples/grpc/chat/client/simplechatengine.cpp4
-rw-r--r--examples/grpc/vehicle/navithread.cpp10
-rw-r--r--examples/grpc/vehicle/vehiclethread.cpp13
-rw-r--r--src/grpc/doc/src/qtgrpc-client-service-methods.qdoc25
-rw-r--r--src/grpc/doc/src/qtgrpcclientinterceptor-caching.qdoc8
-rw-r--r--src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc10
-rw-r--r--src/grpc/qgrpcoperation.cpp89
-rw-r--r--src/grpc/qgrpcoperation.h17
-rw-r--r--src/tools/qtgrpcgen/grpctemplates.cpp10
-rw-r--r--tests/auto/grpc/client/bidirstream/tst_grpc_client_bidirstream.cpp7
-rw-r--r--tests/auto/grpc/client/clientstream/tst_grpc_client_clientstream.cpp9
-rw-r--r--tests/auto/grpc/client/serverstream/tst_grpc_client_serverstream.cpp71
-rw-r--r--tests/auto/grpc/client/unarycall/tst_grpc_client_unarycall.cpp46
-rw-r--r--tests/auto/grpcgen/data/expected_result/qml/qmltestservice_client.grpc.qpb.cpp10
14 files changed, 164 insertions, 165 deletions
diff --git a/examples/grpc/chat/client/simplechatengine.cpp b/examples/grpc/chat/client/simplechatengine.cpp
index d092b0a..5774ad3 100644
--- a/examples/grpc/chat/client/simplechatengine.cpp
+++ b/examples/grpc/chat/client/simplechatengine.cpp
@@ -82,8 +82,8 @@ void SimpleChatEngine::login(const QString &name, const QString &password)
emit userNameChanged();
}
setState(Connected);
- m_messages.append(
- stream->read<qtgrpc::examples::chat::ChatMessages>().messages());
+ if (const auto msg = stream->read<qtgrpc::examples::chat::ChatMessages>())
+ m_messages.append(msg->messages());
});
// ![1]
}
diff --git a/examples/grpc/vehicle/navithread.cpp b/examples/grpc/vehicle/navithread.cpp
index 48f5a59..1669dc0 100644
--- a/examples/grpc/vehicle/navithread.cpp
+++ b/examples/grpc/vehicle/navithread.cpp
@@ -30,10 +30,12 @@ void NaviThread::run()
Empty request;
m_stream = m_client->streamGetNaviStream(request);
connect(m_stream.get(), &QGrpcServerStream::messageReceived, this, [this] {
- DistanceMsg result = m_stream->read<DistanceMsg>();
- emit totalDistanceChanged(result.totalDistance());
- emit remainingDistanceChanged(result.remainingDistance());
- emit directionChanged(result.direction());
+ const auto result = m_stream->read<DistanceMsg>();
+ if (!result)
+ return;
+ emit totalDistanceChanged(result->totalDistance());
+ emit remainingDistanceChanged(result->remainingDistance());
+ emit directionChanged(result->direction());
});
connect(m_stream.get(), &QGrpcServerStream::errorOccurred, this,
diff --git a/examples/grpc/vehicle/vehiclethread.cpp b/examples/grpc/vehicle/vehiclethread.cpp
index a5b0e69..f3c733c 100644
--- a/examples/grpc/vehicle/vehiclethread.cpp
+++ b/examples/grpc/vehicle/vehiclethread.cpp
@@ -36,16 +36,15 @@ void VehicleThread::run()
});
connect(replyFuel.get(), &QGrpcCallReply::finished, [replyFuel, this] {
- FuelLevelMsg fuelLvl = replyFuel->read<FuelLevelMsg>();
- emit fuelLevelChanged(fuelLvl.fuelLevel());
+ if (const auto fuelLvl = replyFuel->read<FuelLevelMsg>())
+ emit fuelLevelChanged(fuelLvl->fuelLevel());
});
Empty speedRequest;
m_streamSpeed = m_client->streamGetSpeedStream(speedRequest);
connect(m_streamSpeed.get(), &QGrpcServerStream::messageReceived, this, [this] {
- SpeedMsg speedResponse;
- speedResponse = m_streamSpeed->read<SpeedMsg>();
- emit speedChanged(speedResponse.speed());
+ if (const auto speedResponse = m_streamSpeed->read<SpeedMsg>())
+ emit speedChanged(speedResponse->speed());
});
connect(m_streamSpeed.get(), &QGrpcServerStream::errorOccurred, this,
@@ -62,8 +61,8 @@ void VehicleThread::run()
Empty gearRequest;
m_streamGear = m_client->streamGetGearStream(gearRequest);
connect(m_streamGear.get(), &QGrpcServerStream::messageReceived, this, [this] {
- GearMsg gearResponse = m_streamGear->read<GearMsg>();
- emit rpmChanged(gearResponse.rpm());
+ if (const auto gearResponse = m_streamGear->read<GearMsg>())
+ emit rpmChanged(gearResponse->rpm());
});
connect(m_streamGear.get(), &QGrpcServerStream::errorOccurred, this,
diff --git a/src/grpc/doc/src/qtgrpc-client-service-methods.qdoc b/src/grpc/doc/src/qtgrpc-client-service-methods.qdoc
index a695f8d..11138d1 100644
--- a/src/grpc/doc/src/qtgrpc-client-service-methods.qdoc
+++ b/src/grpc/doc/src/qtgrpc-client-service-methods.qdoc
@@ -125,8 +125,9 @@ it, call the \c PingPong method:
auto reply = cl.PingPong(request,{});
QObject::connect(reply.get(), &QGrpcCallReply::finished, reply.get(),
[requestTime, replyPtr = reply.get()]() {
- auto response = replyPtr->read<ping::pong::Pong>();
- qDebug() << "Ping-Pong time difference" << response.time() - requestTime;
+ if (const auto response = replyPtr->read<ping::pong::Pong>())
+ qDebug() << "Ping-Pong time difference" << response->time() - requestTime;
+ qDebug() << "Failed deserialization";
});
QObject::connect(reply.get(), &QGrpcCallReply::errorOccurred, stream.get()
@@ -153,8 +154,8 @@ an argument to the callback function that is used in the call:
\code
...
cl.PingPong(request, &a, [requestTime](std::shared_ptr<QGrpcCallReply> reply) {
- auto response = reply->read<ping::pong::Pong>();
- qDebug() << "Ping and Pong time difference" << response.time() - requestTime;
+ if (const auto response = reply->read<ping::pong::Pong>())
+ qDebug() << "Ping and Pong time difference" << response->time() - requestTime;
});
\endcode
This variant makes a connection to the \l{QGrpcCallReply::finished} signal
@@ -182,9 +183,10 @@ the method that returns the pointer to \l QGrpcServerStream:
\code
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, stream.get(),
[streamPtr = stream.get(), requestTime]() {
- auto response = streamPtr->read<ping::pong::Pong>();
- qDebug() << "Ping-Pong next response time difference"
- << response.time() - requestTime;
+ if (const auto response = streamPtr->read<ping::pong::Pong>()) {
+ qDebug() << "Ping-Pong next response time difference"
+ << response->time() - requestTime;
+ }
});
QObject::connect(stream.get(), &QGrpcServerStream::errorOccurred, stream.get()
@@ -232,8 +234,9 @@ To send multiple requests to the server, use the
QObject::connect(stream.get(), &QGrpcServerStream::finished, stream.get(),
[streamPtr = stream.get(), &timer]{
- auto response = streamPtr->read<ping::pong::Pong>();
- qDebug() << "Slowest Ping time: " << response.time();
+ if (const auto response = streamPtr->read<ping::pong::Pong>()) {
+ qDebug() << "Slowest Ping time: " << response->time();
+ }
timer.stop();
});
@@ -277,8 +280,8 @@ breaking the connection session:
QObject::connect(stream.get(), &QGrpcBidirStream::messageReceived, stream.get(),
[streamPtr = stream.get(), &timer, &maxPingPongTime, &requestTime]{
- auto response = streamPtr->read<ping::pong::Pong>();
- maxPingPongTime = std::max(maxPingPongTime, response.time() - requestTime);
+ if (const auto response = streamPtr->read<ping::pong::Pong>())
+ maxPingPongTime = std::max(maxPingPongTime, response->time() - requestTime);
});
QObject::connect(stream.get(), &QGrpcBidirStream::finished, stream.get(),
diff --git a/src/grpc/doc/src/qtgrpcclientinterceptor-caching.qdoc b/src/grpc/doc/src/qtgrpcclientinterceptor-caching.qdoc
index ea3ccde..6d2de37 100644
--- a/src/grpc/doc/src/qtgrpcclientinterceptor-caching.qdoc
+++ b/src/grpc/doc/src/qtgrpcclientinterceptor-caching.qdoc
@@ -55,8 +55,8 @@ protected:
// Intercept the response
QObject::connect(response.get(), &QGrpcCallReply::finished, this,
[operation, response] {
- SimpleStringMessage mess = response->read<SimpleStringMessage>();
- cache.insert(operation->method(), operation->service(), mess.testFieldString());
+ if (const auto mess = response->read<SimpleStringMessage>())
+ cache.insert(operation->method(), operation->service(), mess->testFieldString());
});
// Deserialize the request
SimpleStringMessage deserializedArg;
@@ -88,8 +88,8 @@ protected:
// Intercept the response
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this,
[operation, stream] {
- SimpleStringMessage mess = stream->read<SimpleStringMessage>();
- cache.insert_or_append(operation->method(), operation->service(), mess.testFieldString());
+ if (const auto mess = stream->read<SimpleStringMessage>())
+ cache.insert_or_append(operation->method(), operation->service(), mess->testFieldString());
});
QObject::connect(stream.get(), &QGrpcServerStream::finished, this,
[operation] {
diff --git a/src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc b/src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc
index 936db77..45ab2a2 100644
--- a/src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc
+++ b/src/grpc/doc/src/qtgrpcclientinterceptor-logging.qdoc
@@ -55,8 +55,10 @@ protected:
auto responsePtr = response.get();
QObject::connect(responsePtr, &QGrpcServerStream::messageReceived, responsePtr,
[responsePtr]{
- SimpleStringMessage mess = responsePtr->read<SimpleStringMessage>();
- qDebug() << "Response received:" << mess.testFieldString();
+ const auto mess = responsePtr->read<SimpleStringMessage>();
+ if (!mess)
+ qDebug() << "Failed deserialization";
+ qDebug() << "Response received:" << mess->testFieldString();
});
}
@@ -67,8 +69,8 @@ protected:
// Intercept the response
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this,
[stream] {
- SimpleStringMessage mess = stream->read<SimpleStringMessage>();
- qDebug() << "Response received:" << mess.testFieldString();
+ if (const auto mess = responsePtr->read<SimpleStringMessage>())
+ qDebug() << "Response received:" << mess->testFieldString();
});
// Log incoming and outgoing requests here
diff --git a/src/grpc/qgrpcoperation.cpp b/src/grpc/qgrpcoperation.cpp
index b35ea1f..0da120d 100644
--- a/src/grpc/qgrpcoperation.cpp
+++ b/src/grpc/qgrpcoperation.cpp
@@ -2,15 +2,13 @@
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include "qgrpcoperation.h"
-
-#include "qtgrpcglobal_p.h"
-#include "qgrpcchanneloperation.h"
-
-#include <QtCore/qatomic.h>
#include <QtCore/private/qobject_p.h>
-#include <QtCore/qpointer.h>
+#include <QtCore/qatomic.h>
#include <QtCore/qeventloop.h>
+#include <QtCore/qpointer.h>
+#include <QtGrpc/private/qtgrpcglobal_p.h>
+#include <QtGrpc/qgrpcchanneloperation.h>
+#include <QtGrpc/qgrpcoperation.h>
QT_BEGIN_NAMESPACE
@@ -24,14 +22,17 @@ using namespace Qt::StringLiterals;
*/
/*!
- \fn template <typename T> T QGrpcOperation::read() const
+ \fn template <typename T> std::optional<T> QGrpcOperation::read() const
+
+ Reads a message from a raw byte array stored within this QGrpcOperation
+ instance.
+
+ Returns an optional deserialized message. On failure, \c {std::nullopt} is
+ returned.
- Reads message from raw byte array stored in QGrpcOperation.
+ The error can be retrieved using \l deserializationError.
- Returns a deserialized message or, on failure, a default-constructed
- message.
- If deserialization is not successful the \l QGrpcOperation::errorOccurred
- signal is emitted.
+ \sa read, deserializationError, deserializationErrorString
*/
/*!
@@ -44,12 +45,9 @@ using namespace Qt::StringLiterals;
*/
/*!
- \fn void QGrpcOperation::errorOccurred(const QGrpcStatus &status) const
+ \fn void QGrpcOperation::errorOccurred(const QGrpcStatus &status)
- This signal indicates the error occurred during serialization.
-
- This signal is emitted when error with \a status occurs in channel
- or during serialization.
+ This signal is emitted when an error with \a status occurs in the channel.
\sa QAbstractGrpcClient::errorOccurred
*/
@@ -112,25 +110,23 @@ QByteArray QGrpcOperation::data() const noexcept
/*!
\since 6.8
- Reads a message from a raw byte array stored in QGrpcOperation.
-
- The function writes a deserialized value to \a message pointer.
+ Reads a message from a raw byte array which is stored within this
+ QGrpcOperation instance.
- If deserialization is not successful the \l QGrpcOperation::errorOccurred
- signal is emitted.
+ The function writes the deserialized value to the \a message pointer.
- \note This function has slower message deserialization compared to its
- template counterpart.
+ If the deserialization is successful, this function returns \c true.
+ Otherwise, it returns \c false, and the error can be retrieved with \l
+ deserializationError.
+ \sa read, deserializationError, deserializationErrorString
*/
-void QGrpcOperation::read(QProtobufMessage *message) const
+bool QGrpcOperation::read(QProtobufMessage *message) const
{
Q_ASSERT_X(message != nullptr, "QGrpcOperation::read",
"Can't read to nullptr QProtobufMessage");
- if (auto ser = serializer(); ser) {
- if (!ser->deserialize(message, data()))
- emit errorOccurred(deserializationError());
- }
+ const auto ser = d_func()->channelOperation->serializer();
+ return ser && ser->deserialize(message, data());
}
/*!
@@ -222,39 +218,6 @@ bool QGrpcOperation::isFinished() const noexcept
return d_func()->isFinished.loadRelaxed();
}
-QGrpcStatus QGrpcOperation::deserializationError() const
-{
- QGrpcStatus status;
- switch (serializer()->deserializationError()) {
- case QAbstractProtobufSerializer::InvalidHeaderError: {
- const QString errStr = tr("Response deserialization failed: invalid field found.");
- status = QGrpcStatus{ QGrpcStatus::InvalidArgument, errStr };
- qGrpcWarning() << errStr;
- emit errorOccurred(status);
- } break;
- case QAbstractProtobufSerializer::NoDeserializerError: {
- const QString errStr = tr("No deserializer was found for a given type.");
- status = QGrpcStatus{ QGrpcStatus::InvalidArgument, errStr };
- qGrpcWarning() << errStr;
- emit errorOccurred(status);
- } break;
- case QAbstractProtobufSerializer::UnexpectedEndOfStreamError: {
- const QString errStr = tr("Invalid size of received buffer.");
- status = QGrpcStatus{ QGrpcStatus::OutOfRange, errStr };
- qGrpcWarning() << errStr;
- emit errorOccurred(status);
- } break;
- case QAbstractProtobufSerializer::NoError:
- Q_FALLTHROUGH();
- default:
- const QString errStr = tr("Deserializing failed, but no error was set.");
- status = QGrpcStatus{ QGrpcStatus::InvalidArgument, errStr };
- qGrpcWarning() << errStr;
- emit errorOccurred(status);
- }
- return status;
-}
-
QT_END_NAMESPACE
#include "moc_qgrpcoperation.cpp"
diff --git a/src/grpc/qgrpcoperation.h b/src/grpc/qgrpcoperation.h
index b7f8bd4..4ba05d4 100644
--- a/src/grpc/qgrpcoperation.h
+++ b/src/grpc/qgrpcoperation.h
@@ -24,17 +24,14 @@ public:
~QGrpcOperation() override;
template <typename T>
- T read() const
+ std::optional<T> read() const
{
T value;
- if (auto ser = serializer(); ser) {
- if (!ser->deserialize(&value, data()))
- errorOccurred(deserializationError());
- }
- return value;
+ const auto ser = serializer();
+ return ser && ser->deserialize(&value, data()) ? std::optional<T>(value) : std::nullopt;
}
- void read(QProtobufMessage *message) const;
+ bool read(QProtobufMessage *message) const;
[[nodiscard]] QAbstractProtobufSerializer::DeserializationError deserializationError() const;
[[nodiscard]] QString deserializationErrorString() const;
@@ -47,7 +44,7 @@ public:
Q_SIGNALS:
void finished();
- void errorOccurred(const QGrpcStatus &status) const;
+ void errorOccurred(const QGrpcStatus &status);
protected:
explicit QGrpcOperation(std::shared_ptr<QGrpcChannelOperation> channelOperation,
@@ -58,11 +55,9 @@ protected:
private:
Q_DISABLE_COPY_MOVE(QGrpcOperation)
+ Q_DECLARE_PRIVATE(QGrpcOperation)
[[nodiscard]] QByteArray data() const noexcept;
- [[nodiscard]] QGrpcStatus deserializationError() const;
-
- Q_DECLARE_PRIVATE(QGrpcOperation)
};
QT_END_NAMESPACE
diff --git a/src/tools/qtgrpcgen/grpctemplates.cpp b/src/tools/qtgrpcgen/grpctemplates.cpp
index d6aa4dc..307cc92 100644
--- a/src/tools/qtgrpcgen/grpctemplates.cpp
+++ b/src/tools/qtgrpcgen/grpctemplates.cpp
@@ -107,8 +107,14 @@ const char *GrpcTemplates::ClientMethodDefinitionQmlTemplate()
" std::shared_ptr<QGrpcCallReply> reply = call(\"$method_name$\"_L1, "
"$param_name$, options);\n"
" reply->subscribe(jsEngine, [reply, callback, jsEngine]() {\n"
- " auto result = reply->read<$return_type$>();\n"
- " callback.call(QJSValueList{jsEngine->toScriptValue(result)});\n"
+ " if (const auto result = reply->read<$return_type$>()) {\n"
+ " callback.call(QJSValueList{jsEngine->toScriptValue(*result)});\n"
+ " return;\n"
+ " }\n"
+ " QGrpcStatus::StatusCode code = QGrpcStatus::StatusCode::InvalidArgument;\n"
+ " if (reply->deserializationError() == QAbstractProtobufSerializer::UnexpectedEndOfStreamError)\n"
+ " code = QGrpcStatus::StatusCode::OutOfRange;\n"
+ " emit reply->errorOccurred(QGrpcStatus{ code, reply->deserializationErrorString() });\n"
" }, [errorCallback, jsEngine](const QGrpcStatus &status) {\n"
" errorCallback.call(QJSValueList{jsEngine->toScriptValue(status)});\n"
" });\n"
diff --git a/tests/auto/grpc/client/bidirstream/tst_grpc_client_bidirstream.cpp b/tests/auto/grpc/client/bidirstream/tst_grpc_client_bidirstream.cpp
index d6c2c74..f43550f 100644
--- a/tests/auto/grpc/client/bidirstream/tst_grpc_client_bidirstream.cpp
+++ b/tests/auto/grpc/client/bidirstream/tst_grpc_client_bidirstream.cpp
@@ -39,9 +39,10 @@ void QtGrpcClientBidirStreamTest::Valid()
int i = 0;
QObject::connect(stream.get(), &QGrpcBidirStream::messageReceived, this,
[stream, &request, &fullResponse, &i]() {
- SimpleStringMessage rsp = stream->read<SimpleStringMessage>();
- fullResponse += rsp.testFieldString() + QString::number(++i);
- stream->sendMessage(request);
+ if (const auto rsp = stream->read<SimpleStringMessage>()) {
+ fullResponse += rsp->testFieldString() + QString::number(++i);
+ stream->sendMessage(request);
+ }
});
QSignalSpy streamFinishedSpy(stream.get(), &QGrpcServerStream::finished);
diff --git a/tests/auto/grpc/client/clientstream/tst_grpc_client_clientstream.cpp b/tests/auto/grpc/client/clientstream/tst_grpc_client_clientstream.cpp
index b489b81..c5459c1 100644
--- a/tests/auto/grpc/client/clientstream/tst_grpc_client_clientstream.cpp
+++ b/tests/auto/grpc/client/clientstream/tst_grpc_client_clientstream.cpp
@@ -55,8 +55,8 @@ void QtGrpcClientClientStreamTest::Valid()
MessageLatencyWithThreshold * ExpectedMessageCount);
QCOMPARE(streamErrorSpy.count(), 0);
- SimpleStringMessage result = stream->read<SimpleStringMessage>();
- QCOMPARE_EQ(result.testFieldString(), "Stream1Stream2Stream3Stream4");
+ const auto result = stream->read<SimpleStringMessage>();
+ QCOMPARE_EQ(result->testFieldString(), "Stream1Stream2Stream3Stream4");
}
void QtGrpcClientClientStreamTest::SequentialSend()
@@ -83,8 +83,9 @@ void QtGrpcClientClientStreamTest::SequentialSend()
MessageLatencyWithThreshold * ExpectedMessageCount);
QCOMPARE(streamErrorSpy.count(), 0);
- SimpleStringMessage result = stream->read<SimpleStringMessage>();
- QCOMPARE_EQ(result.testFieldString(), "Stream1Stream2Stream3Stream4");
+ const auto result = stream->read<SimpleStringMessage>();
+ QVERIFY(result.has_value());
+ QCOMPARE_EQ(result->testFieldString(), "Stream1Stream2Stream3Stream4");
}
QTEST_MAIN(QtGrpcClientClientStreamTest)
diff --git a/tests/auto/grpc/client/serverstream/tst_grpc_client_serverstream.cpp b/tests/auto/grpc/client/serverstream/tst_grpc_client_serverstream.cpp
index 26b7a99..645ca25 100644
--- a/tests/auto/grpc/client/serverstream/tst_grpc_client_serverstream.cpp
+++ b/tests/auto/grpc/client/serverstream/tst_grpc_client_serverstream.cpp
@@ -67,8 +67,9 @@ void QtGrpcClientServerStreamTest::Valid()
QVERIFY(streamFinishedSpy.isValid());
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&result, stream] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamFinishedSpy.count(), 1,
@@ -96,8 +97,9 @@ void QtGrpcClientServerStreamTest::Cancel()
int i = 0;
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
if (++i == ExpectedMessageCount)
stream->cancel();
});
@@ -130,8 +132,9 @@ void QtGrpcClientServerStreamTest::DeferredCancel()
int i = 0;
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
if (++i == ExpectedMessageCount)
QTimer::singleShot(MessageLatencyThreshold, stream.get(), &QGrpcServerStream::cancel);
});
@@ -162,8 +165,9 @@ void QtGrpcClientServerStreamTest::HugeBlob()
QVERIFY(streamErrorSpy.isValid());
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&result, stream] {
- BlobMessage ret = stream->read<BlobMessage>();
- result.setTestBytes(ret.testBytes());
+ const auto ret = stream->read<BlobMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestBytes(ret->testBytes());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamFinishedSpy.count(), 1, MessageLatencyWithThreshold);
@@ -200,7 +204,11 @@ void QtGrpcClientServerStreamTest::GetAsyncReply()
request.setTestFieldString("Hello Qt!");
reply = client()->testMethod(request);
- reply->subscribe(this, [reply, &result] { result = reply->read<SimpleStringMessage>(); });
+ reply->subscribe(this, [reply, &result] {
+ const auto ret = reply->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result = *ret;
+ });
QTRY_COMPARE_WITH_TIMEOUT(result.testFieldString(), request.testFieldString(),
MessageLatencyWithThreshold);
@@ -209,9 +217,15 @@ void QtGrpcClientServerStreamTest::GetAsyncReply()
request.setTestFieldString("Hello Qt1!");
reply = client()->testMethod(request);
- reply->subscribe(
- this, [reply, &result] { result = reply->read<SimpleStringMessage>(); },
- [] { QVERIFY(false); });
+ reply->subscribe(this, [reply, &result] {
+ const auto ret = reply->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result = *ret;
+ },
+ [] {
+ QVERIFY(false);
+ }
+ );
QTRY_COMPARE_WITH_TIMEOUT(result.testFieldString(), request.testFieldString(),
MessageLatencyWithThreshold);
@@ -238,8 +252,9 @@ void QtGrpcClientServerStreamTest::MultipleStreams()
QVERIFY(steamMessageRecievedSpy.isValid());
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&result, stream] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamFinishedSpy.count(), 1,
@@ -320,9 +335,10 @@ void QtGrpcClientServerStreamTest::InThread()
auto stream = client()->streamTestMethodServerStream(request);
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, &waiter,
[&result, &i, &waiter, stream] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
result.setTestFieldString(result.testFieldString()
- + ret.testFieldString());
+ + ret->testFieldString());
if (++i == 4)
waiter.quit();
});
@@ -398,8 +414,9 @@ void QtGrpcClientServerStreamTest::Deadline()
SimpleStringMessage result;
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&result, stream] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
if (timeout.count() < MessageLatency * ExpectedMessageCount) {
@@ -455,8 +472,9 @@ void QtGrpcClientServerStreamTest::Interceptor()
QSignalSpy streamFinishedSpy(stream.get(), &QGrpcServerStream::finished);
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&result, stream] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamFinishedSpy.count(), 1,
@@ -490,8 +508,8 @@ void QtGrpcClientServerStreamTest::CancelledInterceptor()
QVERIFY(streamErrorSpy.isValid());
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamErrorSpy.count(), 1, MessageLatencyWithThreshold);
@@ -511,9 +529,9 @@ void QtGrpcClientServerStreamTest::InterceptResponse()
QLatin1StringView) {
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this,
[&serverResponse, stream] {
- SimpleStringMessage mess = stream->read<SimpleStringMessage>();
+ const auto mess = stream->read<SimpleStringMessage>();
serverResponse.setTestFieldString(serverResponse.testFieldString()
- + mess.testFieldString());
+ + mess->testFieldString());
});
continuation(std::move(stream), operation);
};
@@ -539,8 +557,9 @@ void QtGrpcClientServerStreamTest::InterceptResponse()
SimpleStringMessage result;
QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, this, [&] {
- SimpleStringMessage ret = stream->read<SimpleStringMessage>();
- result.setTestFieldString(result.testFieldString() + ret.testFieldString());
+ const auto ret = stream->read<SimpleStringMessage>();
+ QVERIFY(ret.has_value());
+ result.setTestFieldString(result.testFieldString() + ret->testFieldString());
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(streamFinishedSpy.count(), 1,
diff --git a/tests/auto/grpc/client/unarycall/tst_grpc_client_unarycall.cpp b/tests/auto/grpc/client/unarycall/tst_grpc_client_unarycall.cpp
index 0c71299..5a1f1f2 100644
--- a/tests/auto/grpc/client/unarycall/tst_grpc_client_unarycall.cpp
+++ b/tests/auto/grpc/client/unarycall/tst_grpc_client_unarycall.cpp
@@ -60,8 +60,8 @@ private slots:
void QtGrpcClientUnaryCallTest::AsyncWithSubscribe()
{
SimpleStringMessage request;
- SimpleStringMessage result;
request.setTestFieldString("Hello Qt!");
+ std::optional<SimpleStringMessage> result;
bool waitForReply = false;
std::shared_ptr<QGrpcCallReply> reply = client()->testMethod(request);
@@ -71,12 +71,13 @@ void QtGrpcClientUnaryCallTest::AsyncWithSubscribe()
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(waitForReply, true, MessageLatency);
- QCOMPARE_EQ(result.testFieldString(), "Hello Qt!");
+ QVERIFY(result.has_value());
+ QCOMPARE_EQ(result->testFieldString(), "Hello Qt!");
}
void QtGrpcClientUnaryCallTest::AsyncWithLambda()
{
- SimpleStringMessage result;
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
SimpleStringMessage request;
request.setTestFieldString("Hello Qt!");
bool waitForReply = false;
@@ -87,18 +88,19 @@ void QtGrpcClientUnaryCallTest::AsyncWithLambda()
});
QTRY_COMPARE_EQ_WITH_TIMEOUT(waitForReply, true, MessageLatency);
- QCOMPARE_EQ(result.testFieldString(), "Hello Qt!");
+ QVERIFY(result.has_value());
+ QCOMPARE_EQ(result->testFieldString(), "Hello Qt!");
}
void QtGrpcClientUnaryCallTest::ImmediateCancel()
{
- SimpleStringMessage result;
SimpleStringMessage request;
request.setTestFieldString("sleep");
std::shared_ptr<QGrpcCallReply> reply = client()->testMethod(request);
- result.setTestFieldString("Result not changed by echo");
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
+ result->setTestFieldString("Result not changed by echo");
QObject::connect(reply.get(), &QGrpcCallReply::finished, this,
[&result, reply] { result = reply->read<SimpleStringMessage>(); });
@@ -116,7 +118,7 @@ void QtGrpcClientUnaryCallTest::ImmediateCancel()
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 1, FailTimeout);
QTRY_COMPARE_EQ_WITH_TIMEOUT(replyFinishedSpy.count(), 0, FailTimeout);
- QCOMPARE_EQ(result.testFieldString(), "Result not changed by echo");
+ QCOMPARE_EQ(result->testFieldString(), "Result not changed by echo");
QCOMPARE_EQ(qvariant_cast<QGrpcStatus>(clientErrorSpy.at(0).first()).code(),
QGrpcStatus::Cancelled);
}
@@ -126,8 +128,8 @@ void QtGrpcClientUnaryCallTest::DeferredCancel()
SimpleStringMessage request;
request.setTestFieldString("sleep");
- SimpleStringMessage result;
- result.setTestFieldString("Result not changed by echo");
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
+ result->setTestFieldString("Result not changed by echo");
std::shared_ptr<QGrpcCallReply> reply = client()->testMethod(request);
QObject::connect(reply.get(), &QGrpcCallReply::finished, this, [reply, &result] {
@@ -141,7 +143,7 @@ void QtGrpcClientUnaryCallTest::DeferredCancel()
QTimer::singleShot(MessageLatencyThreshold, reply.get(), &QGrpcCallReply::cancel);
QTRY_COMPARE_EQ_WITH_TIMEOUT(replyErrorSpy.count(), 1, FailTimeout);
- QCOMPARE_EQ(result.testFieldString(), "Result not changed by echo");
+ QCOMPARE_EQ(result->testFieldString(), "Result not changed by echo");
}
void QtGrpcClientUnaryCallTest::AsyncClientStatusMessage()
@@ -200,12 +202,12 @@ void QtGrpcClientUnaryCallTest::InThread()
void QtGrpcClientUnaryCallTest::AsyncInThread()
{
SimpleStringMessage request;
- SimpleStringMessage result;
request.setTestFieldString("Hello Qt from thread!");
QSignalSpy clientErrorSpy(client().get(), &TestService::Client::errorOccurred);
QVERIFY(clientErrorSpy.isValid());
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
const std::unique_ptr<QThread> thread(QThread::create([&] {
QEventLoop waiter;
std::shared_ptr<QGrpcCallReply> reply = client()->testMethod(request);
@@ -219,7 +221,7 @@ void QtGrpcClientUnaryCallTest::AsyncInThread()
thread->start();
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 1, FailTimeout);
- QTRY_VERIFY(result.testFieldString().isEmpty());
+ QTRY_VERIFY(result.has_value());
QTRY_VERIFY(
qvariant_cast<QGrpcStatus>(clientErrorSpy.at(0).first())
.message()
@@ -293,7 +295,7 @@ void QtGrpcClientUnaryCallTest::Deadline()
|| code == QGrpcStatus::StatusCode::Unavailable);
} else if (timeout.count() >= MessageLatencyWithThreshold) {
QTRY_COMPARE_EQ_WITH_TIMEOUT(callFinishedSpy.count(), 1, MessageLatencyWithThreshold);
- QCOMPARE(reply->read<SimpleStringMessage>().testFieldString(), request.testFieldString());
+ QCOMPARE(reply->read<SimpleStringMessage>()->testFieldString(), request.testFieldString());
} else {
// Because we're can't be sure about the result,
// cancel the call, that might affect other tests.
@@ -348,13 +350,13 @@ void QtGrpcClientUnaryCallTest::CancelledInterceptor()
channel->addInterceptorManager(manager);
client()->attachChannel(channel);
- SimpleStringMessage result;
SimpleStringMessage request;
request.setTestFieldString("sleep");
std::shared_ptr<QGrpcCallReply> reply = client()->testMethod(request);
- result.setTestFieldString("Result not changed by echo");
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
+ result->setTestFieldString("Result not changed by echo");
QObject::connect(reply.get(), &QGrpcCallReply::finished, this,
[&result, reply] { result = reply->read<SimpleStringMessage>(); });
@@ -370,12 +372,12 @@ void QtGrpcClientUnaryCallTest::CancelledInterceptor()
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 1, FailTimeout);
QTRY_COMPARE_EQ_WITH_TIMEOUT(replyFinishedSpy.count(), 0, FailTimeout);
- QCOMPARE_EQ(result.testFieldString(), "Result not changed by echo");
+ QCOMPARE_EQ(result->testFieldString(), "Result not changed by echo");
}
void QtGrpcClientUnaryCallTest::InterceptResponse()
{
- SimpleStringMessage serverResponse;
+ std::optional<SimpleStringMessage> serverResponse = SimpleStringMessage();
auto interceptFunc =
[this, &serverResponse](std::shared_ptr<QGrpcChannelOperation> operation,
std::shared_ptr<QGrpcCallReply> response,
@@ -395,15 +397,15 @@ void QtGrpcClientUnaryCallTest::InterceptResponse()
client()->attachChannel(channel);
SimpleStringMessage request;
- SimpleStringMessage result;
request.setTestFieldString("Hello Qt!");
+ std::optional<SimpleStringMessage> result;
client()->testMethod(request, client().get(), [&result](std::shared_ptr<QGrpcCallReply> reply) {
result = reply->read<SimpleStringMessage>();
});
- QTRY_COMPARE_EQ_WITH_TIMEOUT(serverResponse.testFieldString(),
+ QTRY_COMPARE_EQ_WITH_TIMEOUT(serverResponse->testFieldString(),
"Hello Qt!", MessageLatencyWithThreshold);
- QCOMPARE_EQ(result.testFieldString(), "Hello Qt!");
+ QCOMPARE_EQ(result->testFieldString(), "Hello Qt!");
}
void QtGrpcClientUnaryCallTest::CacheIntercept()
@@ -431,13 +433,13 @@ void QtGrpcClientUnaryCallTest::CacheIntercept()
client()->attachChannel(channel);
SimpleStringMessage request;
- SimpleStringMessage result;
+ std::optional<SimpleStringMessage> result = SimpleStringMessage();
request.setTestFieldString("Hello Qt!");
client()->testMethod(request, client().get(), [&result](std::shared_ptr<QGrpcCallReply> reply) {
result = reply->read<SimpleStringMessage>();
});
- QTRY_COMPARE_EQ_WITH_TIMEOUT(result.testFieldString(),
+ QTRY_COMPARE_EQ_WITH_TIMEOUT(result->testFieldString(),
"inter1", MessageLatencyWithThreshold);
}
diff --git a/tests/auto/grpcgen/data/expected_result/qml/qmltestservice_client.grpc.qpb.cpp b/tests/auto/grpcgen/data/expected_result/qml/qmltestservice_client.grpc.qpb.cpp
index 15874b3..4c7ee9d 100644
--- a/tests/auto/grpcgen/data/expected_result/qml/qmltestservice_client.grpc.qpb.cpp
+++ b/tests/auto/grpcgen/data/expected_result/qml/qmltestservice_client.grpc.qpb.cpp
@@ -27,8 +27,14 @@ void QmlClient::testMethod(const qtgrpc::tests::SimpleStringMessage &arg, const
std::shared_ptr<QGrpcCallReply> reply = call("testMethod"_L1, arg, options);
reply->subscribe(jsEngine, [reply, callback, jsEngine]() {
- auto result = reply->read<qtgrpc::tests::SimpleStringMessage>();
- callback.call(QJSValueList{jsEngine->toScriptValue(result)});
+ if (const auto result = reply->read<qtgrpc::tests::SimpleStringMessage>()) {
+ callback.call(QJSValueList{jsEngine->toScriptValue(*result)});
+ return;
+ }
+ QGrpcStatus::StatusCode code = QGrpcStatus::StatusCode::InvalidArgument;
+ if (reply->deserializationError() == QAbstractProtobufSerializer::UnexpectedEndOfStreamError)
+ code = QGrpcStatus::StatusCode::OutOfRange;
+ emit reply->errorOccurred(QGrpcStatus{ code, reply->deserializationErrorString() });
}, [errorCallback, jsEngine](const QGrpcStatus &status) {
errorCallback.call(QJSValueList{jsEngine->toScriptValue(status)});
});