Test QNetworkAccessCache insertions with varying expiry times

The insertions are sorted by when they expire. So, we test the various
orders to insert entries.

Fixes: QTBUG-95959
Change-Id: I1e8d7f4c77dce5eae3d4bfa5101f296c3eea1961
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Mårten Nordheim 2021-08-27 10:36:46 +02:00
parent ca69e5aeef
commit 4757b93b0e

View File

@ -453,6 +453,8 @@ private Q_SLOTS:
void httpAbort();
void closeClientSideConnectionEagerlyQtbug20726();
void varyingCacheExpiry_data();
void varyingCacheExpiry();
void dontInsertPartialContentIntoTheCache();
@ -7988,6 +7990,110 @@ void tst_QNetworkReply::closeClientSideConnectionEagerlyQtbug20726()
QCOMPARE(serverNotEagerClientClose2.client->state(), QTcpSocket::ConnectedState);
}
void tst_QNetworkReply::varyingCacheExpiry_data()
{
QTest::addColumn<int>("firstExpiry");
QTest::addColumn<int>("secondExpiry");
QTest::addColumn<int>("thirdExpiry");
QTest::addColumn<int>("fourthExpiry");
// The datatags signify the Keep-Alive time-outs of the successive requests:
QTest::newRow("1-2-3-4") << 1 << 2 << 3 << 4;
QTest::newRow("4-1-2-3") << 4 << 1 << 2 << 3;
QTest::newRow("3-4-1-2") << 3 << 4 << 1 << 2;
QTest::newRow("2-3-4-1") << 2 << 3 << 4 << 1;
QTest::newRow("1-2-2-1") << 1 << 2 << 2 << 1;
}
// Test creating a few requests with various expiry timeouts.
// We do this because the internal QNetworkAccessCache inserts them in sorted
// order, so make sure it gets it right.
void tst_QNetworkReply::varyingCacheExpiry()
{
// Local QNAM instance because there may be leftover entries from other
// tests. Which wouldn't be a big deal, it would just get in the way of our
// pattern
QNetworkAccessManager qnam;
QFETCH(int, firstExpiry);
QFETCH(int, secondExpiry);
QFETCH(int, thirdExpiry);
QFETCH(int, fourthExpiry);
int expiryTimes[4] = {
firstExpiry,
secondExpiry,
thirdExpiry,
fourthExpiry,
};
// We need multiple servers because we want to have multiple connections
// in the QNetworkAccessCache, not to just reuse one connection from the
// cache.
MiniHttpServer servers[4] = {
{ httpEmpty200Response },
{ httpEmpty200Response },
{ httpEmpty200Response },
{ httpEmpty200Response },
};
for (MiniHttpServer &server : servers)
server.doClose = false;
QUrl urls[4] = {
u"http://localhost"_qs,
u"http://localhost"_qs,
u"http://localhost"_qs,
u"http://localhost"_qs,
};
for (int i = 0; i < std::size(urls); ++i)
urls[i].setPort(servers[i].serverPort());
// After the initial request is completed the connection is kept alive
// (Keep-Alive). Internally they are added to a sorted linked-list based on
// expiry. So, set the requests to be torn down at varying timeouts.
QNetworkRequest requests[4] = {
QNetworkRequest(urls[0]),
QNetworkRequest(urls[1]),
QNetworkRequest(urls[2]),
QNetworkRequest(urls[3]),
};
for (int i = 0; i < 4; ++i) {
requests[i].setAttribute(QNetworkRequest::Http2AllowedAttribute,
QVariant::fromValue(false));
requests[i].setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute,
expiryTimes[i]);
}
// The server just uses a normal TCP socket and prints out this error when the client
// disconnects:
for (int i = 0; i < 4; ++i) {
QTest::ignoreMessage(QtDebugMsg,
"slotError QAbstractSocket::RemoteHostClosedError "
"\"The remote host closed the connection\"");
}
// Start each request and wait for it to finish before starting the next
// one, we must do this because the connections are only added to the expiry
// list once finished
for (const auto &request : requests) {
QNetworkReplyPtr reply(qnam.get(request));
QCOMPARE(waitForFinish(reply), Success);
}
int lastExpiry = *std::max_element(std::begin(expiryTimes), std::end(expiryTimes));
auto allServersDisconnected = [&servers]() {
auto socketDisconnected = [](const MiniHttpServer &s) {
return s.client->state() == QAbstractSocket::UnconnectedState;
};
return std::all_of(std::begin(servers), std::end(servers), socketDisconnected);
};
// At least +5 seconds due to CI. Completes much faster locally
bool success = QTest::qWaitFor(allServersDisconnected, lastExpiry * 1000 + 5000);
QVERIFY(success);
}
void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
{
QByteArray reply206 =