QtGrpcClientUnaryCallTest: improve test logic for metadata()

Extend the testcase to cover both, initial and trailing metadata. This
also shows the current problems with having a QHash metadata and also
the missing separation between initial and trailing metadata.

Pick-to: 6.10 6.9 6.8
Change-Id: I880846ae06e8db338cdb3629dafdff430cab3edb
Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
Dennis Oberst 2025-07-07 18:32:31 +02:00
parent 2816a2203f
commit 542efe69ec
2 changed files with 62 additions and 39 deletions

View File

@ -13,6 +13,7 @@
#include <grpc++/grpc++.h> #include <grpc++/grpc++.h>
#include <memory> #include <memory>
#include <charconv>
namespace { namespace {
@ -226,21 +227,45 @@ Status TestServiceServiceImpl::testMethodNonCompatibleArgRet(grpc::ServerContext
Status TestServiceServiceImpl::testMetadata(grpc::ServerContext *ctx, const Empty *, Status TestServiceServiceImpl::testMetadata(grpc::ServerContext *ctx, const Empty *,
qtgrpc::tests::Empty *) qtgrpc::tests::Empty *)
{ {
std::string client_return_header; const auto &md = ctx->client_metadata();
for (const auto &header : ctx->client_metadata()) { auto initial = md.find("request_initial");
if (header.first == "client_header") { uint initialCount = 0;
ctx->AddTrailingMetadata("server_header", if (initial != md.end()) {
std::string(header.second.data(), header.second.size())); std::string v (initial->second.begin(), initial->second.end());
} else if (header.first == "client_return_header") { auto result = std::from_chars(v.data(), v.data() + v.size(), initialCount);
if (client_return_header.empty()) if (result.ec != std::errc())
client_return_header = std::string(header.second.data(), header.second.size()); return { grpc::StatusCode::ABORTED, "conversion failed initial" };
else
client_return_header = "invalid_value";
}
} }
ctx->AddTrailingMetadata("client_return_header", client_return_header); auto trailing = md.find("request_trailing");
return Status(); uint trailingCount = 0;
if (trailing != md.end()) {
std::string v (trailing->second.begin(), trailing->second.end());
auto result = std::from_chars(v.data(), v.data() + v.size(), trailingCount);
if (result.ec != std::errc())
return { grpc::StatusCode::ABORTED, "conversion failed trailing" };
}
auto sum = md.equal_range("request_sum");
uint sumCount = 0;
while (sum.first != sum.second) {
uint temp = 0;
std::string v (sum.first->second.begin(), sum.first->second.end());
auto result = std::from_chars(v.data(), v.data() + v.size(), temp);
if (result.ec != std::errc())
return { grpc::StatusCode::ABORTED, "conversion failed sum" };
sumCount += temp;
++sum.first;
}
for (auto i = 0u; i < initialCount; ++i)
ctx->AddInitialMetadata("response_initial", std::to_string(i));
for (auto i = 0u; i < trailingCount; ++i)
ctx->AddTrailingMetadata("response_trailing", std::to_string(i));
if (sumCount > 0)
ctx->AddTrailingMetadata("response_sum", std::to_string(sumCount));
return Status::OK;
} }
grpc::Status TestServiceServiceImpl::testMethodClientStream( grpc::Status TestServiceServiceImpl::testMethodClientStream(

View File

@ -142,37 +142,35 @@ void QtGrpcClientUnaryCallTest::asyncStatusMessage()
void QtGrpcClientUnaryCallTest::metadata() void QtGrpcClientUnaryCallTest::metadata()
{ {
QGrpcCallOptions opt; QGrpcCallOptions opt;
opt.setMetadata({ QHash<QByteArray, QByteArray> clientMd{
{ "client_header", "1" }, { "request_initial", "3" },
{ "client_return_header", "valid_value" } { "request_trailing", "2" },
}); { "request_sum", "20" },
{ "request_sum", "10" }
};
QT_IGNORE_DEPRECATIONS(opt.setMetadata(clientMd);)
auto reply = client()->testMetadata({}, opt); auto reply = client()->testMetadata({}, opt);
QSignalSpy replyFinishedSpy(reply.get(), &QGrpcCallReply::finished);
QVERIFY(replyFinishedSpy.isValid());
QHash<QByteArray, QByteArray> metadata; QTRY_COMPARE_EQ_WITH_TIMEOUT(replyFinishedSpy.count(), 1, FailTimeout);
QEventLoop waiter; const auto &args = replyFinishedSpy.first();
QCOMPARE_EQ(args.count(), 1);
QVERIFY(args.first().value<QGrpcStatus>().isOk());
connect( const auto &md = reply->metadata();
reply.get(), &QGrpcOperation::finished, this, auto initialIt = md.equal_range("response_initial");
[&reply, &metadata, &waiter](const QGrpcStatus &) { QCOMPARE_EQ(std::distance(initialIt.first, initialIt.second), 1);
metadata = reply->metadata(); QCOMPARE_EQ(initialIt.first.value(), "2");
waiter.quit();
},
Qt::SingleShotConnection);
waiter.exec(); auto trailingIt = md.equal_range("response_trailing");
QCOMPARE_EQ(std::distance(trailingIt.first, trailingIt.second), 1);
QCOMPARE_EQ(trailingIt.first.value(), "1");
int serverHeaderCount = 0; auto sumIt = md.equal_range("response_sum");
QByteArray clientReturnHeader; QCOMPARE_EQ(std::distance(sumIt.first, sumIt.second), 1);
for (const auto &[key, value] : reply->metadata().asKeyValueRange()) { auto sum = sumIt.first.value();
if (key == "server_header") { QVERIFY(sum == "20"_ba || sum == "10"_ba);
QCOMPARE_EQ(QString::fromLatin1(value), QString::number(++serverHeaderCount));
} else if (key == "client_return_header") {
clientReturnHeader = value;
}
}
QCOMPARE_EQ(serverHeaderCount, 1);
QCOMPARE_EQ(clientReturnHeader, "valid_value"_ba);
} }
QTEST_MAIN(QtGrpcClientUnaryCallTest) QTEST_MAIN(QtGrpcClientUnaryCallTest)