mirror of https://github.com/qt/qtgrpc.git
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>
This commit is contained in:
parent
636b70f93d
commit
57b875c33b
|
|
@ -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]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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] {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 message from raw byte array stored in QGrpcOperation.
|
||||
Reads a message from a raw byte array stored within this QGrpcOperation
|
||||
instance.
|
||||
|
||||
Returns a deserialized message or, on failure, a default-constructed
|
||||
message.
|
||||
If deserialization is not successful the \l QGrpcOperation::errorOccurred
|
||||
signal is emitted.
|
||||
Returns an optional deserialized message. On failure, \c {std::nullopt} is
|
||||
returned.
|
||||
|
||||
The error can be retrieved using \l deserializationError.
|
||||
|
||||
\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.
|
||||
Reads a message from a raw byte array which is stored within this
|
||||
QGrpcOperation instance.
|
||||
|
||||
The function writes a deserialized value to \a message pointer.
|
||||
The function writes the deserialized value to the \a message pointer.
|
||||
|
||||
If deserialization is not successful the \l QGrpcOperation::errorOccurred
|
||||
signal is emitted.
|
||||
|
||||
\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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue