Refactor tst_grpc_client_no_channel test

Rename the test to tst_grpc_client_deadline. Use GrpcClientTestBase
as the test base. Add WithChannelDeadline channel to GrpcClientTestBase.

Pick-to: 6.6 6.7
Change-Id: I6125f68f40b26ba645a97721641123d01a5387b2
Reviewed-by: Tatiana Borisova <tatiana.borisova@qt.io>
This commit is contained in:
Alexey Edelev 2024-01-06 18:55:10 +01:00
parent 5189fddaed
commit bc424839f1
6 changed files with 92 additions and 168 deletions

View File

@ -4,7 +4,7 @@ add_subdirectory(shared)
add_subdirectory(interceptor)
add_subdirectory(unattached_channel)
add_subdirectory(no_channel)
add_subdirectory(deadline)
add_subdirectory(unarycall)
add_subdirectory(serverstream)
add_subdirectory(clientstream)

View File

@ -3,19 +3,21 @@
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16)
project(tst_grpc_client_no_channel LANGUAGES CXX)
project(tst_grpc_client_deadline LANGUAGES CXX)
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
include("../shared/test_server/CMakeLists.txt")
include("../shared/client_service/CMakeLists.txt")
include("../shared/client_test_common/CMakeLists.txt")
endif()
if(NOT TARGET grpc_testserver)
return()
endif()
qt_internal_add_test(tst_grpc_client_no_channel
qt_internal_add_test(tst_grpc_client_deadline
SOURCES
tst_grpc_client_no_channel.cpp
tst_grpc_client_deadline.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/../../shared
DEFINES
@ -25,6 +27,7 @@ qt_internal_add_test(tst_grpc_client_no_channel
Qt::Core
Qt::Grpc
tst_grpc_client_qtgrpc_gen
tst_grpc_client_test_common
)
add_dependencies(tst_grpc_client_no_channel grpc_testserver)
add_dependencies(tst_grpc_client_deadline grpc_testserver)

View File

@ -0,0 +1,70 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QSignalSpy>
#include <QTest>
#include <QtGrpc/QGrpcCallOptions>
#include <QtGrpc/QGrpcCallReply>
#include <QtGrpc/QGrpcChannelOptions>
#include <chrono>
#include <grpcclienttestbase.h>
#include <message_latency_defs.h>
#include "testservice_client.grpc.qpb.h"
using namespace Qt::Literals::StringLiterals;
using namespace qtgrpc::tests;
class QtGrpcClientDeadlineTest : public GrpcClientTestBase
{
Q_OBJECT
public:
QtGrpcClientDeadlineTest() : GrpcClientTestBase(Channels(Channel::WithChannelDeadline)) { }
private slots:
void ChannelAndCallDeadlineTest_data();
void ChannelAndCallDeadlineTest();
};
void QtGrpcClientDeadlineTest::ChannelAndCallDeadlineTest_data()
{
QTest::addColumn<double>("minTimeout");
QTest::addColumn<double>("maxTimeout");
QTest::addRow("0.0") << double(0) << double(0.6);
QTest::addRow("0.25") << double(0.25) << double(0.6);
}
void QtGrpcClientDeadlineTest::ChannelAndCallDeadlineTest()
{
QFETCH(double, minTimeout);
QFETCH(double, maxTimeout);
const auto minTimeoutDuration = std::chrono::milliseconds(static_cast<int64_t>(MessageLatency
* minTimeout));
const auto maxTimeoutDuration = std::chrono::milliseconds(static_cast<int64_t>(MessageLatency
* maxTimeout));
QGrpcCallOptions callOpts;
callOpts.withDeadline(minTimeoutDuration);
SimpleStringMessage request;
request.setTestFieldString("sleep");
QSignalSpy clientErrorSpy(client().get(), &TestService::Client::errorOccurred);
QVERIFY(clientErrorSpy.isValid());
std::shared_ptr<QGrpcCallReply> reply;
reply = client()->testMethod(request, callOpts);
QSignalSpy callFinishedSpy(reply.get(), &QGrpcCallReply::finished);
QVERIFY(callFinishedSpy.isValid());
// Still waiting for a timeout
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 0, minTimeoutDuration.count());
// Time window to receive the timout
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 1,
maxTimeoutDuration.count() + MessageLatencyThreshold);
const auto code = qvariant_cast<QGrpcStatus>(clientErrorSpy.at(0).first()).code();
// Really low timeout can trigger before service becomes available
QVERIFY(code == QGrpcStatus::StatusCode::Cancelled
|| code == QGrpcStatus::StatusCode::Unavailable);
}
QTEST_MAIN(QtGrpcClientDeadlineTest)
#include "tst_grpc_client_deadline.moc"

View File

@ -1,162 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGrpcCallReply>
#if QT_CONFIG(native_grpc)
# include <QGrpcChannel>
#endif
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QGrpcHttp2Channel>
#include <QSignalSpy>
#include <QTest>
#include <QtGrpc/QGrpcCallOptions>
#include <QtGrpc/QGrpcChannelOptions>
#include <memory>
#if QT_CONFIG(native_grpc)
# include <grpcpp/security/credentials.h>
#endif
#include "testservice_client.grpc.qpb.h"
#include <message_latency_defs.h>
#include <server_proc_runner.h>
using namespace Qt::Literals::StringLiterals;
using namespace qtgrpc::tests;
namespace {
class ChannelFactory
{
public:
enum ChannelType {
HTTP2,
GRPC_SOCKET,
GRPC_HTTP,
};
ChannelFactory(ChannelType type) : type(type) { }
std::shared_ptr<QAbstractGrpcChannel> create(const QGrpcChannelOptions &options) const
{
switch (type) {
case HTTP2:
return std::make_shared<QGrpcHttp2Channel>(options);
#if QT_CONFIG(native_grpc)
case GRPC_SOCKET:
case GRPC_HTTP:
return std::make_shared<QGrpcChannel>(options,
QGrpcChannel::InsecureChannelCredentials);
#endif
}
return nullptr;
}
QUrl getUrl() const
{
switch (type) {
case HTTP2:
return QUrl("http://localhost:50051", QUrl::StrictMode);
#if QT_CONFIG(native_grpc)
case GRPC_SOCKET:
return QUrl("unix:///tmp/qtgrpc_test.sock");
case GRPC_HTTP:
return QUrl("localhost:50051");
#endif
}
return QUrl();
}
private:
ChannelType type;
};
} // namespace
class QtGrpcClientNoChannelTest : public QObject
{
Q_OBJECT
private slots:
void createClient(const QGrpcChannelOptions &channelOptions)
{
client = std::make_shared<TestService::Client>();
auto channel = channelFactory->create(channelOptions);
QVERIFY2(channel, "Channel could not been created.");
client->attachChannel(std::move(channel));
}
void initTestCase_data()
{
QTest::addColumn<std::shared_ptr<ChannelFactory>>("factory");
QTest::newRow("Http2Client") << std::make_shared<ChannelFactory>(ChannelFactory::HTTP2);
#if QT_CONFIG(native_grpc)
# ifndef Q_OS_WINDOWS
QTest::newRow("GrpcSocket")
<< std::make_shared<ChannelFactory>(ChannelFactory::GRPC_SOCKET);
# endif
QTest::newRow("GrpcHttp") << std::make_shared<ChannelFactory>(ChannelFactory::GRPC_HTTP);
#endif
}
void initTestCase() { qRegisterProtobufTypes(); }
void init()
{
if (serverProc.state() != QProcess::ProcessState::Running) {
qInfo() << "Restarting server";
serverProc.restart();
QVERIFY2(serverProc.state() == QProcess::ProcessState::Running,
"Precondition failed - Server cannot be started.");
}
QFETCH_GLOBAL(std::shared_ptr<ChannelFactory>, factory);
channelFactory = std::move(factory);
}
void ChannelAndCallDeadlineTest();
private:
ServerProcRunner serverProc{ QFINDTESTDATA(TEST_GRPC_SERVER_PATH) };
std::shared_ptr<ChannelFactory> channelFactory;
std::shared_ptr<TestService::Client> client;
};
void QtGrpcClientNoChannelTest::ChannelAndCallDeadlineTest()
{
constexpr auto channelTimeout = std::chrono::milliseconds(static_cast<int64_t>(MessageLatency
* 0.25));
constexpr auto callTimeout = std::chrono::milliseconds(static_cast<int64_t>(MessageLatency
* 0.6));
QGrpcChannelOptions channelOpts(channelFactory->getUrl());
channelOpts.withDeadline(channelTimeout);
createClient(channelOpts);
QGrpcCallOptions callOpts;
callOpts.withDeadline(callTimeout);
auto executeTest = [this](uint64_t minTimeout, uint64_t maxTimeout,
std::optional<QGrpcCallOptions> callOptions = std::nullopt) {
SimpleStringMessage request;
request.setTestFieldString("sleep");
QSignalSpy clientErrorSpy(client.get(), &TestService::Client::errorOccurred);
QVERIFY(clientErrorSpy.isValid());
std::shared_ptr<QGrpcCallReply> reply;
if (callOptions)
reply = client->testMethod(request, *callOptions);
else
reply = client->testMethod(request);
QSignalSpy callFinishedSpy(reply.get(), &QGrpcCallReply::finished);
QVERIFY(callFinishedSpy.isValid());
// Still waiting for a timeout
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 0, minTimeout);
// Time window to receive the timout
QTRY_COMPARE_EQ_WITH_TIMEOUT(clientErrorSpy.count(), 1, maxTimeout);
const auto code = qvariant_cast<QGrpcStatus>(clientErrorSpy.at(0).first()).code();
// Really low timeout can trigger before service becomes available
QVERIFY(code == QGrpcStatus::StatusCode::Cancelled
|| code == QGrpcStatus::StatusCode::Unavailable);
};
executeTest(0, channelTimeout.count() + MessageLatencyThreshold);
executeTest(channelTimeout.count(), callTimeout.count() + MessageLatencyThreshold, callOpts);
}
QTEST_MAIN(QtGrpcClientNoChannelTest)
#include "tst_grpc_client_no_channel.moc"

View File

@ -5,6 +5,7 @@
#include <QtGrpc/QGrpcChannelOptions>
#include <QtNetwork/qtnetwork-config.h>
#include <message_latency_defs.h>
void GrpcClientTestBase::initTestCase_data()
{
@ -68,6 +69,17 @@ void GrpcClientTestBase::initTestCase_data()
# endif
}
#endif
if (m_channels.testFlag(Channel::WithChannelDeadline)) {
constexpr auto
channelTimeout = std::chrono::milliseconds(static_cast<int64_t>(MessageLatency * 0.25));
QTest::newRow("Http2ClientDeadline")
<< QFlags{ Channel::Qt, Channel::WithChannelDeadline }
<< std::shared_ptr<
QAbstractGrpcChannel>(new QGrpcHttp2Channel(QGrpcChannelOptions{
QUrl("http://localhost:50051", QUrl::StrictMode) }
.withDeadline(channelTimeout)));
}
}
void GrpcClientTestBase::init()

View File

@ -26,7 +26,8 @@ protected:
Qt = 0x1,
Native = 0x2,
Ssl = 0x4,
SslNoCredentials = 0x8
SslNoCredentials = 0x8,
WithChannelDeadline = 0x10,
};
Q_DECLARE_FLAGS(Channels, Channel)