clienttest.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
  5. *
  6. * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy of this
  9. * software and associated documentation files (the "Software"), to deal in the Software
  10. * without restriction, including without limitation the rights to use, copy, modify,
  11. * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
  12. * to permit persons to whom the Software is furnished to do so, subject to the following
  13. * conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in all copies
  16. * or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  19. * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  20. * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  21. * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  22. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #include "testservice_grpc.qpb.h"
  26. #include <QGrpcHttp2Channel>
  27. #ifdef QT_PROTOBUF_NATIVE_GRPC_CHANNEL
  28. #include <QGrpcChannel>
  29. #endif
  30. #include <QGrpcCredentials>
  31. #include <QGrpcInsecureCallCredentials>
  32. #include <QGrpcInsecureChannelCredentials>
  33. #include <QTimer>
  34. #include <QFile>
  35. #include <QCryptographicHash>
  36. #include <QThread>
  37. #include <QCoreApplication>
  38. #include <QProcess>
  39. #include <QProtobufSerializer>
  40. #include <QDebug>
  41. #include <QSignalSpy>
  42. #include <QtTest/QtTest>
  43. using namespace qtprotobufnamespace::tests;
  44. typedef TestServiceClient* createTestServiceClientFunc();
  45. const QUrl EchoServerAddress("http://localhost:50051", QUrl::StrictMode);
  46. class QtGrpcClientTest : public QObject
  47. {
  48. Q_OBJECT
  49. public:
  50. QtGrpcClientTest(QObject *parent = nullptr) : QObject(parent)
  51. {
  52. qRegisterProtobufTypes();
  53. m_serverProcess.setProgram(QT_GRPC_SERVER_EXECUTABLE);
  54. m_serverProcess.start();
  55. m_serverProcess.waitForStarted();
  56. connect(&m_serverProcess, &QProcess::readyReadStandardError, &m_serverStarupWaiter, [this]{
  57. if (m_serverStarupWaiter.isRunning())
  58. m_serverStarupWaiter.quit();
  59. });
  60. connect(&m_serverProcess, &QProcess::readyReadStandardOutput, &m_serverStarupWaiter, [this]{
  61. if (m_serverStarupWaiter.isRunning())
  62. m_serverStarupWaiter.quit();
  63. });
  64. connect(&m_serverProcess, &QProcess::readyReadStandardError, this, [this]{
  65. qDebug() << ":" << "SERVER_ERROR" << m_serverProcess.readAllStandardError();
  66. });
  67. connect(&m_serverProcess, &QProcess::readyReadStandardOutput, this, [this]{
  68. qDebug() << ":" << "SERVER_MESSAGE" << m_serverProcess.readAllStandardOutput();
  69. });
  70. m_serverStarupWaiter.exec();
  71. qDebug() << "Server started";
  72. }
  73. virtual ~QtGrpcClientTest()
  74. {
  75. m_serverProcess.terminate();
  76. if(!m_serverProcess.waitForFinished(5000)) {
  77. m_serverProcess.kill();
  78. }
  79. }
  80. static TestServiceClient *createHttp2Client() {
  81. auto *c = new TestServiceClient();
  82. c->attachChannel(std::make_shared<QGrpcHttp2Channel>(EchoServerAddress, QGrpcInsecureChannelCredentials() | QGrpcInsecureCallCredentials()));
  83. return c;
  84. }
  85. #ifdef QT_PROTOBUF_NATIVE_GRPC_CHANNEL
  86. static TestServiceClient * createGrpcSocketClient() {
  87. auto *c = new TestServiceClient();
  88. c->attachChannel(std::make_shared<QGrpcChannel>(QtGrpcClientTest::m_echoServerSocket, grpc::InsecureChannelCredentials()));
  89. return c;
  90. }
  91. static TestServiceClient * createGrpcHttpClient() {
  92. auto *c = new TestServiceClient();
  93. c->attachChannel(std::make_shared<QGrpcChannel>(QtGrpcClientTest::EchoServerAddressNative, grpc::InsecureChannelCredentials()));
  94. return c;
  95. }
  96. static const QString m_echoServerSocket;
  97. static const QString EchoServerAddressNative;
  98. #endif
  99. static createTestServiceClientFunc *clientCreators[];
  100. private slots:
  101. void CheckMethodsGeneration();
  102. void StringEchoTest();
  103. void StringEchoAsyncTest();
  104. void StringEchoAsync2Test();
  105. void StringEchoImmediateAsyncAbortTest();
  106. void StringEchoDeferredAsyncAbortTest();
  107. void StringEchoStreamTest();
  108. void StringEchoStreamAbortTest();
  109. void StringEchoStreamAbortByTimerTest();
  110. void StringEchoStreamTestRet();
  111. void HugeBlobEchoStreamTest();
  112. void StatusMessageAsyncTest();
  113. void StatusMessageClientAsyncTest();
  114. void StatusMessageClientSyncTest();
  115. void StatusMessageClientSyncTestReturnedStatus();
  116. void ClientSyncTestUnattachedChannel();
  117. void ClientSyncTestUnattachedChannelSignal();
  118. void AsyncReplyStreamTest();
  119. void MultipleStreamsTest();
  120. void MultipleStreamsCancelTest();
  121. void NonCompatibleArgRetTest();
  122. void StringEchoThreadTest();
  123. void StringEchoAsyncThreadTest();
  124. void StringEchoStreamThreadTest();
  125. void AttachChannelThreadTest();
  126. void StreamCancelWhileErrorTimeoutTest();
  127. protected:
  128. QProcess m_serverProcess;
  129. QEventLoop m_serverStarupWaiter;
  130. };
  131. #ifdef QT_PROTOBUF_NATIVE_GRPC_CHANNEL
  132. const QString QtGrpcClientTest::EchoServerAddressNative("localhost:50051");
  133. const QString QtGrpcClientTest::m_echoServerSocket("unix:///tmp/test.sock");
  134. #endif
  135. createTestServiceClientFunc* QtGrpcClientTest::clientCreators[]{
  136. QtGrpcClientTest::createHttp2Client,
  137. #ifdef QT_PROTOBUF_NATIVE_GRPC_CHANNEL
  138. QtGrpcClientTest::createGrpcHttpClient,
  139. QtGrpcClientTest::createGrpcSocketClient,
  140. #endif
  141. };
  142. void QtGrpcClientTest::CheckMethodsGeneration()
  143. {
  144. //Dummy compile time check of functions generation and interface compatibility
  145. // TestServiceClient testClient;
  146. // testClient.attachChannel(std::make_shared<QGrpcHttp2Channel>(QUrl(), QGrpcInsecureChannelCredentials() | QGrpcInsecureCallCredentials()));
  147. // SimpleStringMessage request;
  148. // QPointer<SimpleStringMessage> result(new SimpleStringMessage);
  149. // testClient.testMethod(request, result);
  150. // testClient.testMethod(request);
  151. // testClient.testMethod(request, &testClient, [](QGrpcCallReplyShared) {});
  152. // delete result;
  153. }
  154. void QtGrpcClientTest::StringEchoTest()
  155. {
  156. auto testClient = createHttp2Client();
  157. SimpleStringMessage request;
  158. QPointer<SimpleStringMessage> result(new SimpleStringMessage);
  159. request.setTestFieldString(QStringLiteral("Hello Qt!"));
  160. QCOMPARE(testClient->testMethod(request, result), QGrpcStatus::Ok);
  161. QCOMPARE(result->testFieldString(), QStringLiteral("Hello Qt!"));
  162. delete result;
  163. testClient->deleteLater();
  164. }
  165. void QtGrpcClientTest::StringEchoAsyncTest()
  166. {
  167. auto testClient = createHttp2Client();
  168. SimpleStringMessage request;
  169. SimpleStringMessage result;
  170. request.setTestFieldString(QStringLiteral("Hello Qt!"));
  171. QGrpcCallReplyShared reply = testClient->testMethod(request);
  172. QSignalSpy waiter(reply.get(), &QGrpcCallReply::finished);
  173. waiter.wait();
  174. result = reply->read<SimpleStringMessage>();
  175. reply->deleteLater();
  176. QCOMPARE(result.testFieldString(), QStringLiteral("Hello Qt!"));
  177. testClient->deleteLater();
  178. }
  179. void QtGrpcClientTest::StringEchoAsync2Test()
  180. {
  181. auto testClient = createHttp2Client();
  182. SimpleStringMessage result;
  183. SimpleStringMessage request;
  184. request.setTestFieldString(QStringLiteral("Hello Qt!"));
  185. QEventLoop waiter;
  186. testClient->testMethod(request, this, [&result, &waiter](QGrpcCallReplyShared reply) {
  187. result = reply->read<SimpleStringMessage>();
  188. waiter.quit();
  189. });
  190. waiter.exec();
  191. QCOMPARE(result.testFieldString(), QStringLiteral("Hello Qt!"));
  192. testClient->deleteLater();
  193. }
  194. void QtGrpcClientTest::StringEchoImmediateAsyncAbortTest()
  195. {
  196. auto testClient = createHttp2Client();
  197. SimpleStringMessage result;
  198. SimpleStringMessage request;
  199. request.setTestFieldString("sleep");
  200. QEventLoop waiter;
  201. QGrpcCallReplyShared reply = testClient->testMethod(request);
  202. result.setTestFieldString("Result not changed by echo");
  203. QObject::connect(reply.get(), &QGrpcCallReply::finished, this, [&waiter, &result, reply]() {
  204. result = reply->read<SimpleStringMessage>();
  205. reply->deleteLater();
  206. waiter.quit();
  207. });
  208. QGrpcStatus::StatusCode asyncStatus = QGrpcStatus::StatusCode::Ok;
  209. QObject::connect(reply.get(), &QGrpcCallReply::error, [&asyncStatus](const QGrpcStatus &status) {
  210. asyncStatus = status.code();
  211. });
  212. QGrpcStatus::StatusCode clientStatus = QGrpcStatus::StatusCode::Ok;
  213. QObject::connect(testClient, &TestServiceClient::error, [&clientStatus](const QGrpcStatus &status) {
  214. clientStatus = status.code();
  215. qDebug() << status.code() << ":" << status.message();
  216. });
  217. QTimer::singleShot(5000, &waiter, &QEventLoop::quit);
  218. reply->abort();
  219. waiter.exec();
  220. QCOMPARE(clientStatus, QGrpcStatus::StatusCode::Aborted);
  221. QCOMPARE(asyncStatus, QGrpcStatus::StatusCode::Aborted);
  222. QCOMPARE(result.testFieldString(), QStringLiteral("Result not changed by echo"));
  223. testClient->deleteLater();
  224. }
  225. void QtGrpcClientTest::StringEchoDeferredAsyncAbortTest()
  226. {
  227. auto testClient = createHttp2Client();
  228. SimpleStringMessage result;
  229. SimpleStringMessage request;
  230. request.setTestFieldString("sleep");
  231. QEventLoop waiter;
  232. QGrpcCallReplyShared reply = testClient->testMethod(request);
  233. result.setTestFieldString("Result not changed by echo");
  234. bool errorCalled = false;
  235. reply = testClient->testMethod(request);
  236. QObject::connect(reply.get(), &QGrpcCallReply::finished, this, [reply, &result, &waiter]() {
  237. result = reply->read<SimpleStringMessage>();
  238. waiter.quit();
  239. });
  240. QObject::connect(reply.get(), &QGrpcCallReply::error, [&errorCalled]() {
  241. errorCalled = true;
  242. });
  243. QTimer::singleShot(500, reply.get(), &QGrpcCallReply::abort);
  244. QTimer::singleShot(5000, &waiter, &QEventLoop::quit);
  245. waiter.exec();
  246. QCOMPARE(result.testFieldString(), QStringLiteral("Result not changed by echo"));
  247. QVERIFY(errorCalled);
  248. testClient->deleteLater();
  249. }
  250. void QtGrpcClientTest::StringEchoStreamTest()
  251. {
  252. auto testClient = createHttp2Client();
  253. SimpleStringMessage result;
  254. SimpleStringMessage request;
  255. request.setTestFieldString("Stream");
  256. QEventLoop waiter;
  257. int i = 0;
  258. auto stream = testClient->streamTestMethodServerStream(request);
  259. QObject::connect(stream.get(), &QGrpcStream::messageReceived, this, [&result, &i, &waiter, stream]() {
  260. SimpleStringMessage ret = stream->read<SimpleStringMessage>();
  261. ++i;
  262. result.setTestFieldString(result.testFieldString() + ret.testFieldString());
  263. if (i == 4) {
  264. waiter.quit();
  265. }
  266. });
  267. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  268. waiter.exec();
  269. QCOMPARE(i, 4);
  270. QCOMPARE(result.testFieldString(), QStringLiteral("Stream1Stream2Stream3Stream4"));
  271. testClient->deleteLater();
  272. }
  273. void QtGrpcClientTest::StringEchoStreamAbortTest()
  274. {
  275. auto testClient = createHttp2Client();
  276. SimpleStringMessage result;
  277. SimpleStringMessage request;
  278. request.setTestFieldString("Stream");
  279. QEventLoop waiter;
  280. int i = 0;
  281. auto stream = testClient->streamTestMethodServerStream(request);
  282. QObject::connect(stream.get(), &QGrpcStream::messageReceived, this, [&result, &i, &waiter, stream]() {
  283. SimpleStringMessage ret = stream->read<SimpleStringMessage>();
  284. ++i;
  285. result.setTestFieldString(result.testFieldString() + ret.testFieldString());
  286. if (i == 3) {
  287. stream->abort();
  288. QTimer::singleShot(4000, &waiter, &QEventLoop::quit);
  289. }
  290. });
  291. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  292. waiter.exec();
  293. QCOMPARE(i, 3);
  294. QCOMPARE(result.testFieldString(), QStringLiteral("Stream1Stream2Stream3"));
  295. testClient->deleteLater();
  296. }
  297. void QtGrpcClientTest::StringEchoStreamAbortByTimerTest()
  298. {
  299. auto testClient = createHttp2Client();
  300. SimpleStringMessage result;
  301. SimpleStringMessage request;
  302. request.setTestFieldString("Stream");
  303. QEventLoop waiter;
  304. int i = 0;
  305. auto stream = testClient->streamTestMethodServerStream(request);
  306. QTimer::singleShot(3500, stream.get(), [stream]() {
  307. stream->abort();
  308. });
  309. bool isFinished = false;
  310. QObject::connect(stream.get(), &QGrpcStream::finished, [&isFinished]() {
  311. isFinished = true;
  312. });
  313. bool isError = false;
  314. QObject::connect(stream.get(), &QGrpcStream::error, [&isError]() {
  315. isError = true;
  316. });
  317. QObject::connect(stream.get(), &QGrpcStream::messageReceived, this, [&result, &i, stream]() {
  318. SimpleStringMessage ret = stream->read<SimpleStringMessage>();
  319. ++i;
  320. result.setTestFieldString(result.testFieldString() + ret.testFieldString());
  321. });
  322. QTimer::singleShot(5000, &waiter, &QEventLoop::quit);
  323. waiter.exec();
  324. QCOMPARE(i, 3);
  325. QCOMPARE(result.testFieldString(), QStringLiteral("Stream1Stream2Stream3"));
  326. QVERIFY(isFinished);
  327. QVERIFY(!isError);
  328. testClient->deleteLater();
  329. }
  330. void QtGrpcClientTest::StringEchoStreamTestRet()
  331. {
  332. auto testClient = createHttp2Client();
  333. SimpleStringMessage request;
  334. QPointer<SimpleStringMessage> result(new SimpleStringMessage);
  335. request.setTestFieldString("Stream");
  336. QEventLoop waiter;
  337. testClient->streamTestMethodServerStream(request, result);
  338. int i = 0;
  339. QObject::connect(result.data(), &SimpleStringMessage::testFieldStringChanged, this, [&i]() {
  340. i++;
  341. });
  342. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  343. waiter.exec();
  344. QCOMPARE(i, 4);
  345. QCOMPARE(result->testFieldString(), QStringLiteral("Stream4"));
  346. delete result;
  347. testClient->deleteLater();
  348. }
  349. void QtGrpcClientTest::HugeBlobEchoStreamTest()
  350. {
  351. auto testClient = createHttp2Client();
  352. BlobMessage result;
  353. BlobMessage request;
  354. QFile testFile("testfile");
  355. QVERIFY(testFile.open(QFile::ReadOnly));
  356. request.setTestBytes(testFile.readAll());
  357. QByteArray dataHash = QCryptographicHash::hash(request.testBytes(), QCryptographicHash::Sha256);
  358. QEventLoop waiter;
  359. auto stream = testClient->streamTestMethodBlobServerStream(request);
  360. QObject::connect(stream.get(), &QGrpcStream::messageReceived, this, [&result, &waiter, stream]() {
  361. BlobMessage ret = stream->read<BlobMessage>();
  362. result.setTestBytes(ret.testBytes());
  363. waiter.quit();
  364. });
  365. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  366. waiter.exec();
  367. QByteArray returnDataHash = QCryptographicHash::hash(result.testBytes(), QCryptographicHash::Sha256);
  368. QVERIFY(returnDataHash == dataHash);
  369. testClient->deleteLater();
  370. }
  371. void QtGrpcClientTest::StatusMessageAsyncTest()
  372. {
  373. auto testClient = createHttp2Client();
  374. SimpleStringMessage request(QString{"Some status message"});
  375. QGrpcStatus::StatusCode asyncStatus = QGrpcStatus::StatusCode::Ok;
  376. QEventLoop waiter;
  377. QString statusMessage;
  378. QGrpcCallReplyShared reply = testClient->testMethodStatusMessage(request);
  379. QObject::connect(reply.get(), &QGrpcCallReply::error, [&asyncStatus, &waiter, &statusMessage](const QGrpcStatus &status) {
  380. asyncStatus = status.code();
  381. statusMessage = status.message();
  382. waiter.quit();
  383. });
  384. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  385. waiter.exec();
  386. QCOMPARE(statusMessage, request.testFieldString());
  387. testClient->deleteLater();
  388. }
  389. void QtGrpcClientTest::StatusMessageClientAsyncTest()
  390. {
  391. auto testClient = createHttp2Client();
  392. SimpleStringMessage request(QString{"Some status message"});
  393. QGrpcStatus::StatusCode asyncStatus = QGrpcStatus::StatusCode::Ok;
  394. QEventLoop waiter;
  395. QString statusMessage;
  396. QObject::connect(testClient, &TestServiceClient::error, [&asyncStatus, &waiter, &statusMessage](const QGrpcStatus &status) {
  397. asyncStatus = status.code();
  398. statusMessage = status.message();
  399. waiter.quit();
  400. });
  401. testClient->testMethodStatusMessage(request);
  402. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  403. waiter.exec();
  404. QCOMPARE(statusMessage, request.testFieldString());
  405. testClient->deleteLater();
  406. }
  407. void QtGrpcClientTest::StatusMessageClientSyncTest()
  408. {
  409. auto testClient = createHttp2Client();
  410. SimpleStringMessage request(QString{"Some status message"});
  411. QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
  412. QGrpcStatus::StatusCode asyncStatus = QGrpcStatus::StatusCode::Ok;
  413. QEventLoop waiter;
  414. QString statusMessage;
  415. QObject::connect(testClient, &TestServiceClient::error, [&asyncStatus, &waiter, &statusMessage](const QGrpcStatus &status) {
  416. asyncStatus = status.code();
  417. statusMessage = status.message();
  418. waiter.quit();
  419. });
  420. testClient->testMethodStatusMessage(request, ret);
  421. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  422. waiter.exec();
  423. QCOMPARE(statusMessage, request.testFieldString());
  424. delete ret;
  425. testClient->deleteLater();
  426. }
  427. void QtGrpcClientTest::StatusMessageClientSyncTestReturnedStatus()
  428. {
  429. auto testClient = createHttp2Client();
  430. SimpleStringMessage request(QString{"Some status message"});
  431. QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
  432. QEventLoop waiter;
  433. QString statusMessage;
  434. QGrpcStatus status = testClient->testMethodStatusMessage(request, ret);
  435. QCOMPARE(status.message(), request.testFieldString());
  436. delete ret;
  437. testClient->deleteLater();
  438. }
  439. void QtGrpcClientTest::ClientSyncTestUnattachedChannel()
  440. {
  441. TestServiceClient testClient;
  442. SimpleStringMessage request(QString{"Some status message"});
  443. QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
  444. QEventLoop waiter;
  445. QGrpcStatus status = testClient.testMethodStatusMessage(request, ret);
  446. QCOMPARE(status.code(), QGrpcStatus::Unknown);
  447. QCOMPARE("Serializing failed. Serializer is not ready", status.message());
  448. delete ret;
  449. }
  450. void QtGrpcClientTest::ClientSyncTestUnattachedChannelSignal()
  451. {
  452. TestServiceClient testClient;
  453. SimpleStringMessage request(QString{"Some status message"});
  454. QPointer<SimpleStringMessage> ret(new SimpleStringMessage);
  455. QGrpcStatus asyncStatus(QGrpcStatus::StatusCode::Ok);
  456. QEventLoop waiter;
  457. QObject::connect(&testClient, &TestServiceClient::error, [&asyncStatus, &waiter](const QGrpcStatus &status) {
  458. asyncStatus = status;
  459. waiter.quit();
  460. });
  461. testClient.testMethodStatusMessage(request, ret);
  462. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  463. waiter.exec();
  464. QCOMPARE(asyncStatus, QGrpcStatus::Unknown);
  465. QCOMPARE("Serializing failed. Serializer is not ready", asyncStatus.message());
  466. delete ret;
  467. }
  468. void QtGrpcClientTest::AsyncReplyStreamTest()
  469. {
  470. auto testClient = createHttp2Client();
  471. QTimer callTimeout;
  472. SimpleStringMessage request(QString{"Some status message"});
  473. QGrpcStatus::StatusCode asyncStatus = QGrpcStatus::StatusCode::Ok;
  474. QEventLoop waiter;
  475. QString statusMessage;
  476. QObject::connect(&callTimeout, &QTimer::timeout, &waiter, &QEventLoop::quit);
  477. callTimeout.setInterval(5000);
  478. auto reply = testClient->testMethodStatusMessage(request);
  479. reply->subscribe(this, []() {
  480. QVERIFY(false);
  481. },
  482. [&asyncStatus, &waiter, &statusMessage](const QGrpcStatus &status) {
  483. asyncStatus = status.code();
  484. statusMessage = status.message();
  485. waiter.quit();
  486. });
  487. callTimeout.start();
  488. waiter.exec();
  489. callTimeout.stop();
  490. QCOMPARE(statusMessage, request.testFieldString());
  491. SimpleStringMessage result;
  492. request.setTestFieldString(QStringLiteral("Hello Qt!"));
  493. reply = testClient->testMethod(request);
  494. reply->subscribe(this, [reply, &result, &waiter]() {
  495. result = reply->read<SimpleStringMessage>();
  496. waiter.quit();
  497. });
  498. callTimeout.start();
  499. waiter.exec();
  500. callTimeout.stop();
  501. QCOMPARE(result.testFieldString(), request.testFieldString());
  502. result.setTestFieldString("");
  503. request.setTestFieldString("Hello Qt1!");
  504. reply = testClient->testMethod(request);
  505. reply->subscribe(this, [reply, &result, &waiter]() {
  506. result = reply->read<SimpleStringMessage>();
  507. waiter.quit();
  508. }, []() {
  509. QVERIFY(false);
  510. });
  511. callTimeout.start();
  512. waiter.exec();
  513. callTimeout.stop();
  514. QCOMPARE(result.testFieldString(), request.testFieldString());
  515. testClient->deleteLater();
  516. }
  517. void QtGrpcClientTest::MultipleStreamsTest()
  518. {
  519. auto testClient = createHttp2Client();
  520. SimpleStringMessage result;
  521. SimpleStringMessage request;
  522. QEventLoop waiter;
  523. request.setTestFieldString("Stream");
  524. auto stream = testClient->streamTestMethodServerStream(request);
  525. auto streamNext = testClient->streamTestMethodServerStream(request);
  526. QCOMPARE(stream, streamNext);
  527. int i = 0;
  528. QObject::connect(stream.get(), &QGrpcStream::messageReceived, this, [&result, &i, stream]() {
  529. SimpleStringMessage ret = stream->read<SimpleStringMessage>();
  530. ++i;
  531. result.setTestFieldString(result.testFieldString() + ret.testFieldString());
  532. });
  533. QTimer::singleShot(10000, &waiter, &QEventLoop::quit);
  534. waiter.exec();
  535. QCOMPARE(i, 4);
  536. QCOMPARE(result.testFieldString(), QStringLiteral("Stream1Stream2Stream3Stream4"));
  537. testClient->deleteLater();
  538. }
  539. void QtGrpcClientTest::MultipleStreamsCancelTest()
  540. {
  541. auto testClient = createHttp2Client();
  542. SimpleStringMessage result;
  543. SimpleStringMessage request;
  544. request.setTestFieldString("Stream");
  545. auto stream = testClient->streamTestMethodServerStream(request);
  546. auto streamNext = testClient->streamTestMethodServerStream(request);
  547. QCOMPARE(stream, streamNext);
  548. bool isFinished = false;
  549. QObject::connect(stream.get(), &QGrpcStream::finished, [&isFinished]() {
  550. isFinished = true;
  551. });
  552. bool isFinishedNext = false;
  553. QObject::connect(streamNext.get(), &QGrpcStream::finished, [&isFinishedNext]() {
  554. isFinishedNext = true;
  555. });
  556. streamNext->abort();
  557. QVERIFY(isFinished);
  558. QVERIFY(isFinishedNext);
  559. stream = testClient->streamTestMethodServerStream(request);
  560. if(stream == streamNext) {
  561. QFAIL("streamNext points to the same memory. New stream handler is not created.");
  562. }
  563. streamNext = testClient->streamTestMethodServerStream(request);
  564. QCOMPARE(stream, streamNext);
  565. isFinished = false;
  566. QObject::connect(stream.get(), &QGrpcStream::finished, [&isFinished]() {
  567. isFinished = true;
  568. });
  569. isFinishedNext = false;
  570. QObject::connect(streamNext.get(), &QGrpcStream::finished, [&isFinishedNext]() {
  571. isFinishedNext = true;
  572. });
  573. stream->abort();
  574. QVERIFY(isFinished);
  575. QVERIFY(isFinishedNext);
  576. testClient->deleteLater();
  577. }
  578. void QtGrpcClientTest::NonCompatibleArgRetTest()
  579. {
  580. auto testClient = createHttp2Client();
  581. SimpleIntMessage request(2048);
  582. QPointer<SimpleStringMessage> result(new SimpleStringMessage);
  583. QVERIFY(testClient->testMethodNonCompatibleArgRet(request, result) == QGrpcStatus::Ok);
  584. QCOMPARE(result->testFieldString(), QStringLiteral("2048"));
  585. delete result;
  586. testClient->deleteLater();
  587. }
  588. void QtGrpcClientTest::StringEchoThreadTest()
  589. {
  590. auto testClient = createHttp2Client();
  591. SimpleStringMessage request;
  592. QPointer<SimpleStringMessage> result(new SimpleStringMessage);
  593. request.setTestFieldString("Hello Qt from thread!");
  594. bool ok = false;
  595. std::shared_ptr<QThread> thread(QThread::create([&](){
  596. ok = testClient->testMethod(request, result) == QGrpcStatus::Ok;
  597. }));
  598. thread->start();
  599. QEventLoop wait;
  600. QTimer::singleShot(2000, &wait, &QEventLoop::quit);
  601. wait.exec();
  602. QVERIFY(ok);
  603. QCOMPARE(result->testFieldString(), QStringLiteral("Hello Qt from thread!"));
  604. delete result;
  605. //Delete result pointer in between call operations
  606. result = new SimpleStringMessage();
  607. ok = false;
  608. thread.reset(QThread::create([&](){
  609. ok = testClient->testMethod(request, result) == QGrpcStatus::Ok;
  610. }));
  611. thread->start();
  612. delete result;
  613. QTimer::singleShot(2000, &wait, &QEventLoop::quit);
  614. wait.exec();
  615. QVERIFY(!ok);
  616. testClient->deleteLater();
  617. }
  618. void QtGrpcClientTest::StringEchoAsyncThreadTest()
  619. {
  620. auto testClient = createHttp2Client();
  621. SimpleStringMessage request;
  622. SimpleStringMessage result;
  623. request.setTestFieldString("Hello Qt from thread!");
  624. bool threadsOk = true;
  625. bool replyDestroyed = true;
  626. std::shared_ptr<QThread> thread(QThread::create([&](){
  627. QEventLoop waiter;
  628. QThread *validThread = QThread::currentThread();
  629. QGrpcCallReplyShared reply = testClient->testMethod(request);
  630. QObject::connect(reply.get(), &QObject::destroyed, [&replyDestroyed]{replyDestroyed = true;});
  631. QObject::connect(reply.get(), &QGrpcCallReply::finished, &waiter, [reply, &result, &waiter, &threadsOk, validThread]() {
  632. threadsOk &= reply->thread() != QThread::currentThread();
  633. threadsOk &= validThread == QThread::currentThread();
  634. result = reply->read<SimpleStringMessage>();
  635. waiter.quit();
  636. });
  637. threadsOk &= reply->thread() != QThread::currentThread();
  638. waiter.exec();
  639. }));
  640. thread->start();
  641. QEventLoop wait;
  642. QTimer::singleShot(2000, &wait, &QEventLoop::quit);
  643. wait.exec();
  644. QVERIFY(replyDestroyed);
  645. QVERIFY(threadsOk);
  646. QCOMPARE(result.testFieldString(), QStringLiteral("Hello Qt from thread!"));
  647. testClient->deleteLater();
  648. }
  649. void QtGrpcClientTest::StringEchoStreamThreadTest()
  650. {
  651. auto testClient = createHttp2Client();
  652. SimpleStringMessage result;
  653. SimpleStringMessage request;
  654. request.setTestFieldString("Stream");
  655. int i = 0;
  656. bool threadsOk = true;
  657. std::shared_ptr<QThread> thread(QThread::create([&](){
  658. QEventLoop waiter;
  659. QThread *validThread = QThread::currentThread();
  660. auto stream = testClient->streamTestMethodServerStream(request);
  661. QObject::connect(stream.get(), &QGrpcStream::messageReceived, &waiter, [&result, &i, &waiter, stream, &threadsOk, validThread]() {
  662. SimpleStringMessage ret = stream->read<SimpleStringMessage>();
  663. result.setTestFieldString(result.testFieldString() + ret.testFieldString());
  664. ++i;
  665. if (i == 4) {
  666. waiter.quit();
  667. }
  668. threadsOk &= stream->thread() != QThread::currentThread();
  669. threadsOk &= validThread == QThread::currentThread();
  670. });
  671. threadsOk &= stream->thread() != QThread::currentThread();
  672. QTimer::singleShot(20000, &waiter, &QEventLoop::quit);
  673. waiter.exec();
  674. }));
  675. thread->start();
  676. QEventLoop wait;
  677. QObject::connect(thread.get(), &QThread::finished, &wait, [&wait]{ wait.quit(); });
  678. QTimer::singleShot(20000, &wait, &QEventLoop::quit);
  679. wait.exec();
  680. QVERIFY(threadsOk);
  681. QCOMPARE(i, 4);
  682. QCOMPARE(result.testFieldString(), QStringLiteral("Stream1Stream2Stream3Stream4"));
  683. testClient->deleteLater();
  684. }
  685. void QtGrpcClientTest::AttachChannelThreadTest()
  686. {
  687. std::shared_ptr<QGrpcHttp2Channel> channel;
  688. std::shared_ptr<QThread> thread(QThread::create([&](){
  689. channel = std::make_shared<QGrpcHttp2Channel>(EchoServerAddress, QGrpcInsecureCallCredentials() | QGrpcInsecureChannelCredentials());
  690. }));
  691. thread->start();
  692. QThread::msleep(1000);
  693. TestServiceClient testClient;
  694. QVERIFY_THROWS_EXCEPTION(std::runtime_error, testClient.attachChannel(channel));
  695. }
  696. void QtGrpcClientTest::StreamCancelWhileErrorTimeoutTest()
  697. {
  698. auto *testClient = createHttp2Client();;
  699. SimpleStringMessage result;
  700. SimpleStringMessage request;
  701. request.setTestFieldString("Stream");
  702. QEventLoop waiter;
  703. bool ok = false;
  704. auto stream = testClient->streamTestMethodServerStream(request);
  705. QObject::connect(stream.get(), &QGrpcStream::finished, this, [&ok, &waiter]() {
  706. ok = true;
  707. waiter.quit();
  708. });
  709. stream->abort();
  710. stream.reset();
  711. QTimer::singleShot(5000, &waiter, &QEventLoop::quit);
  712. waiter.exec();
  713. QVERIFY(ok);
  714. }
  715. QTEST_MAIN(QtGrpcClientTest)
  716. #include "clienttest.moc"