1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QTemporaryDir> |
30 | #include <QtTest/QtTest> |
31 | #include <QtNetwork/QtNetwork> |
32 | #include "../../../network-settings.h" |
33 | |
34 | #ifndef QT_NO_BEARERMANAGEMENT |
35 | #include <QtNetwork/qnetworkconfigmanager.h> |
36 | #include <QtNetwork/qnetworkconfiguration.h> |
37 | #include <QtNetwork/qnetworksession.h> |
38 | #endif |
39 | |
40 | #include <algorithm> |
41 | |
42 | #define TESTFILE QLatin1String("http://") + QtNetworkSettings::httpServerName() + QLatin1String("/qtest/cgi-bin/") |
43 | |
44 | class tst_QAbstractNetworkCache : public QObject |
45 | { |
46 | Q_OBJECT |
47 | |
48 | public: |
49 | tst_QAbstractNetworkCache(); |
50 | virtual ~tst_QAbstractNetworkCache(); |
51 | |
52 | private slots: |
53 | void initTestCase(); |
54 | void expires_data(); |
55 | void expires(); |
56 | void expiresSynchronous_data(); |
57 | void expiresSynchronous(); |
58 | |
59 | void lastModified_data(); |
60 | void lastModified(); |
61 | void lastModifiedSynchronous_data(); |
62 | void lastModifiedSynchronous(); |
63 | |
64 | void etag_data(); |
65 | void etag(); |
66 | void etagSynchronous_data(); |
67 | void etagSynchronous(); |
68 | |
69 | void cacheControl_data(); |
70 | void cacheControl(); |
71 | void cacheControlSynchronous_data(); |
72 | void cacheControlSynchronous(); |
73 | |
74 | void deleteCache(); |
75 | |
76 | private: |
77 | void runTest(); |
78 | void checkSynchronous(); |
79 | |
80 | #ifndef QT_NO_BEARERMANAGEMENT |
81 | QNetworkConfigurationManager *netConfMan; |
82 | QNetworkConfiguration networkConfiguration; |
83 | QScopedPointer<QNetworkSession> networkSession; |
84 | #endif |
85 | }; |
86 | |
87 | class NetworkDiskCache : public QNetworkDiskCache |
88 | { |
89 | Q_OBJECT |
90 | public: |
91 | NetworkDiskCache(QObject *parent = 0) |
92 | : QNetworkDiskCache(parent) |
93 | , tempDir(QDir::tempPath() + QLatin1String("/tst_qabstractnetworkcache.XXXXXX" )) |
94 | , gotData(false) |
95 | { |
96 | setCacheDirectory(tempDir.path()); |
97 | clear(); |
98 | } |
99 | |
100 | QIODevice *data(const QUrl &url) |
101 | { |
102 | gotData = true; |
103 | return QNetworkDiskCache::data(url); |
104 | } |
105 | |
106 | QTemporaryDir tempDir; |
107 | bool gotData; |
108 | }; |
109 | |
110 | |
111 | tst_QAbstractNetworkCache::tst_QAbstractNetworkCache() |
112 | { |
113 | QCoreApplication::setOrganizationName(QLatin1String("QtProject" )); |
114 | QCoreApplication::setApplicationName(QLatin1String("autotest_qabstractnetworkcache" )); |
115 | QCoreApplication::setApplicationVersion(QLatin1String("1.0" )); |
116 | } |
117 | |
118 | tst_QAbstractNetworkCache::~tst_QAbstractNetworkCache() |
119 | { |
120 | } |
121 | |
122 | static bool AlwaysTrue = true; |
123 | static bool AlwaysFalse = false; |
124 | |
125 | Q_DECLARE_METATYPE(QNetworkRequest::CacheLoadControl) |
126 | |
127 | |
128 | void tst_QAbstractNetworkCache::initTestCase() |
129 | { |
130 | #if defined(QT_TEST_SERVER) |
131 | QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); |
132 | #else |
133 | if (!QtNetworkSettings::verifyTestNetworkSettings()) |
134 | QSKIP("No network test server available" ); |
135 | #endif |
136 | |
137 | #ifndef QT_NO_BEARERMANAGEMENT |
138 | netConfMan = new QNetworkConfigurationManager(this); |
139 | networkConfiguration = netConfMan->defaultConfiguration(); |
140 | networkSession.reset(other: new QNetworkSession(networkConfiguration)); |
141 | if (!networkSession->isOpen()) { |
142 | networkSession->open(); |
143 | QVERIFY(networkSession->waitForOpened(30000)); |
144 | } |
145 | #endif |
146 | } |
147 | |
148 | |
149 | void tst_QAbstractNetworkCache::expires_data() |
150 | { |
151 | QTest::addColumn<QNetworkRequest::CacheLoadControl>(name: "cacheLoadControl" ); |
152 | QTest::addColumn<QString>(name: "url" ); |
153 | QTest::addColumn<bool>(name: "fetchFromCache" ); |
154 | |
155 | QTest::newRow(dataTag: "304-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires304.cgi" << AlwaysFalse; |
156 | QTest::newRow(dataTag: "304-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_expires304.cgi" << true; |
157 | QTest::newRow(dataTag: "304-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_expires304.cgi" << AlwaysTrue; |
158 | QTest::newRow(dataTag: "304-3" ) << QNetworkRequest::PreferCache << "httpcachetest_expires304.cgi" << true; |
159 | |
160 | QTest::newRow(dataTag: "500-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires500.cgi" << AlwaysFalse; |
161 | QTest::newRow(dataTag: "500-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_expires500.cgi" << true; |
162 | QTest::newRow(dataTag: "500-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_expires500.cgi" << AlwaysTrue; |
163 | QTest::newRow(dataTag: "500-3" ) << QNetworkRequest::PreferCache << "httpcachetest_expires500.cgi" << true; |
164 | |
165 | QTest::newRow(dataTag: "200-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires200.cgi" << AlwaysFalse; |
166 | QTest::newRow(dataTag: "200-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_expires200.cgi" << false; |
167 | QTest::newRow(dataTag: "200-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_expires200.cgi" << AlwaysTrue; |
168 | QTest::newRow(dataTag: "200-3" ) << QNetworkRequest::PreferCache << "httpcachetest_expires200.cgi" << false; |
169 | } |
170 | |
171 | void tst_QAbstractNetworkCache::expires() |
172 | { |
173 | runTest(); |
174 | } |
175 | |
176 | void tst_QAbstractNetworkCache::expiresSynchronous_data() |
177 | { |
178 | expires_data(); |
179 | } |
180 | |
181 | void tst_QAbstractNetworkCache::expiresSynchronous() |
182 | { |
183 | checkSynchronous(); |
184 | } |
185 | |
186 | void tst_QAbstractNetworkCache::lastModified_data() |
187 | { |
188 | QTest::addColumn<QNetworkRequest::CacheLoadControl>(name: "cacheLoadControl" ); |
189 | QTest::addColumn<QString>(name: "url" ); |
190 | QTest::addColumn<bool>(name: "fetchFromCache" ); |
191 | |
192 | QTest::newRow(dataTag: "304-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified304.cgi" << AlwaysFalse; |
193 | QTest::newRow(dataTag: "304-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified304.cgi" << true; |
194 | QTest::newRow(dataTag: "304-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified304.cgi" << AlwaysTrue; |
195 | QTest::newRow(dataTag: "304-3" ) << QNetworkRequest::PreferCache << "httpcachetest_lastModified304.cgi" << true; |
196 | |
197 | QTest::newRow(dataTag: "200-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified200.cgi" << AlwaysFalse; |
198 | QTest::newRow(dataTag: "200-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified200.cgi" << true; |
199 | QTest::newRow(dataTag: "200-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified200.cgi" << AlwaysTrue; |
200 | QTest::newRow(dataTag: "200-3" ) << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << true; |
201 | } |
202 | |
203 | void tst_QAbstractNetworkCache::lastModified() |
204 | { |
205 | runTest(); |
206 | } |
207 | |
208 | void tst_QAbstractNetworkCache::lastModifiedSynchronous_data() |
209 | { |
210 | tst_QAbstractNetworkCache::lastModified_data(); |
211 | } |
212 | |
213 | void tst_QAbstractNetworkCache::lastModifiedSynchronous() |
214 | { |
215 | checkSynchronous(); |
216 | } |
217 | |
218 | void tst_QAbstractNetworkCache::etag_data() |
219 | { |
220 | QTest::addColumn<QNetworkRequest::CacheLoadControl>(name: "cacheLoadControl" ); |
221 | QTest::addColumn<QString>(name: "url" ); |
222 | QTest::addColumn<bool>(name: "fetchFromCache" ); |
223 | |
224 | QTest::newRow(dataTag: "304-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag304.cgi" << AlwaysFalse; |
225 | QTest::newRow(dataTag: "304-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_etag304.cgi" << true; |
226 | QTest::newRow(dataTag: "304-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_etag304.cgi" << AlwaysTrue; |
227 | QTest::newRow(dataTag: "304-3" ) << QNetworkRequest::PreferCache << "httpcachetest_etag304.cgi" << true; |
228 | |
229 | QTest::newRow(dataTag: "200-0" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag200.cgi" << AlwaysFalse; |
230 | QTest::newRow(dataTag: "200-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_etag200.cgi" << false; |
231 | QTest::newRow(dataTag: "200-2" ) << QNetworkRequest::AlwaysCache << "httpcachetest_etag200.cgi" << AlwaysTrue; |
232 | QTest::newRow(dataTag: "200-3" ) << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << false; |
233 | } |
234 | |
235 | void tst_QAbstractNetworkCache::etag() |
236 | { |
237 | runTest(); |
238 | } |
239 | |
240 | void tst_QAbstractNetworkCache::etagSynchronous_data() |
241 | { |
242 | tst_QAbstractNetworkCache::etag_data(); |
243 | } |
244 | |
245 | void tst_QAbstractNetworkCache::etagSynchronous() |
246 | { |
247 | checkSynchronous(); |
248 | } |
249 | |
250 | void tst_QAbstractNetworkCache::cacheControl_data() |
251 | { |
252 | QTest::addColumn<QNetworkRequest::CacheLoadControl>(name: "cacheLoadControl" ); |
253 | QTest::addColumn<QString>(name: "url" ); |
254 | QTest::addColumn<bool>(name: "fetchFromCache" ); |
255 | QTest::newRow(dataTag: "200-0" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=-1" << true; |
256 | QTest::newRow(dataTag: "200-1" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol-expire.cgi" << false; |
257 | |
258 | QTest::newRow(dataTag: "200-2" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << AlwaysFalse; |
259 | QTest::newRow(dataTag: "200-3" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << true; |
260 | QTest::newRow(dataTag: "200-4" ) << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?no-cache" << false; |
261 | QTest::newRow(dataTag: "200-5" ) << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?no-cache" << true; |
262 | |
263 | QTest::newRow(dataTag: "200-6" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?no-store" << AlwaysFalse; |
264 | QTest::newRow(dataTag: "200-7" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?no-store" << false; |
265 | QTest::newRow(dataTag: "200-8" ) << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?no-store" << false; |
266 | QTest::newRow(dataTag: "200-9" ) << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?no-store" << false; |
267 | |
268 | QTest::newRow(dataTag: "304-0" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000" << true; |
269 | |
270 | QTest::newRow(dataTag: "304-1" ) << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << AlwaysFalse; |
271 | QTest::newRow(dataTag: "304-2" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true; |
272 | QTest::newRow(dataTag: "304-3" ) << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << false; |
273 | QTest::newRow(dataTag: "304-4" ) << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true; |
274 | |
275 | QTest::newRow(dataTag: "304-2b" ) << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; |
276 | QTest::newRow(dataTag: "304-4b" ) << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; |
277 | } |
278 | |
279 | void tst_QAbstractNetworkCache::cacheControl() |
280 | { |
281 | runTest(); |
282 | } |
283 | |
284 | void tst_QAbstractNetworkCache::cacheControlSynchronous_data() |
285 | { |
286 | tst_QAbstractNetworkCache::cacheControl_data(); |
287 | } |
288 | |
289 | void tst_QAbstractNetworkCache::cacheControlSynchronous() |
290 | { |
291 | checkSynchronous(); |
292 | } |
293 | |
294 | void tst_QAbstractNetworkCache::runTest() |
295 | { |
296 | QFETCH(QNetworkRequest::CacheLoadControl, cacheLoadControl); |
297 | QFETCH(QString, url); |
298 | QFETCH(bool, fetchFromCache); |
299 | |
300 | QNetworkAccessManager manager; |
301 | NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); |
302 | QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); |
303 | manager.setCache(diskCache); |
304 | QCOMPARE(diskCache->gotData, false); |
305 | |
306 | QUrl realUrl = url.contains(s: "://" ) ? url : TESTFILE + url; |
307 | QNetworkRequest request(realUrl); |
308 | |
309 | // prime the cache |
310 | QNetworkReply *reply = manager.get(request); |
311 | QSignalSpy downloaded1(reply, SIGNAL(finished())); |
312 | QTRY_COMPARE(downloaded1.count(), 1); |
313 | QCOMPARE(diskCache->gotData, false); |
314 | QByteArray goodData = reply->readAll(); |
315 | |
316 | request.setAttribute(code: QNetworkRequest::CacheLoadControlAttribute, value: cacheLoadControl); |
317 | |
318 | // should be in the cache now |
319 | QNetworkReply *reply2 = manager.get(request); |
320 | QSignalSpy downloaded2(reply2, SIGNAL(finished())); |
321 | QTRY_COMPARE(downloaded2.count(), 1); |
322 | |
323 | QByteArray secondData = reply2->readAll(); |
324 | if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) { |
325 | QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError); |
326 | QCOMPARE(secondData, QByteArray()); |
327 | } else { |
328 | QCOMPARE(reply2->error(), QNetworkReply::NoError); |
329 | QCOMPARE(QString(secondData), QString(goodData)); |
330 | QCOMPARE(secondData, goodData); |
331 | QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); |
332 | } |
333 | |
334 | if (fetchFromCache) { |
335 | QList<QByteArray> = reply->rawHeaderList(); |
336 | QList<QByteArray> = reply2->rawHeaderList(); |
337 | std::sort(first: rawHeaderList.begin(), last: rawHeaderList.end()); |
338 | std::sort(first: rawHeaderList2.begin(), last: rawHeaderList2.end()); |
339 | } |
340 | QCOMPARE(diskCache->gotData, fetchFromCache); |
341 | } |
342 | |
343 | void tst_QAbstractNetworkCache::checkSynchronous() |
344 | { |
345 | QSKIP("not working yet, see QTBUG-15221" ); |
346 | |
347 | QFETCH(QNetworkRequest::CacheLoadControl, cacheLoadControl); |
348 | QFETCH(QString, url); |
349 | QFETCH(bool, fetchFromCache); |
350 | |
351 | QNetworkAccessManager manager; |
352 | NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); |
353 | QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); |
354 | manager.setCache(diskCache); |
355 | QCOMPARE(diskCache->gotData, false); |
356 | |
357 | QUrl realUrl = url.contains(s: "://" ) ? url : TESTFILE + url; |
358 | QNetworkRequest request(realUrl); |
359 | |
360 | request.setAttribute( |
361 | code: QNetworkRequest::SynchronousRequestAttribute, |
362 | value: true); |
363 | |
364 | // prime the cache |
365 | QNetworkReply *reply = manager.get(request); |
366 | QVERIFY(reply->isFinished()); // synchronous |
367 | QCOMPARE(diskCache->gotData, false); |
368 | QByteArray goodData = reply->readAll(); |
369 | |
370 | request.setAttribute(code: QNetworkRequest::CacheLoadControlAttribute, value: cacheLoadControl); |
371 | |
372 | // should be in the cache now |
373 | QNetworkReply *reply2 = manager.get(request); |
374 | QVERIFY(reply2->isFinished()); // synchronous |
375 | |
376 | QByteArray secondData = reply2->readAll(); |
377 | if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) { |
378 | QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError); |
379 | QCOMPARE(secondData, QByteArray()); |
380 | } else { |
381 | if (reply2->error() != QNetworkReply::NoError) |
382 | qDebug() << reply2->errorString(); |
383 | QCOMPARE(reply2->error(), QNetworkReply::NoError); |
384 | QCOMPARE(QString(secondData), QString(goodData)); |
385 | QCOMPARE(secondData, goodData); |
386 | QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); |
387 | } |
388 | |
389 | if (fetchFromCache) { |
390 | QList<QByteArray> = reply->rawHeaderList(); |
391 | QList<QByteArray> = reply2->rawHeaderList(); |
392 | std::sort(first: rawHeaderList.begin(), last: rawHeaderList.end()); |
393 | std::sort(first: rawHeaderList2.begin(), last: rawHeaderList2.end()); |
394 | } |
395 | QCOMPARE(diskCache->gotData, fetchFromCache); |
396 | } |
397 | |
398 | void tst_QAbstractNetworkCache::deleteCache() |
399 | { |
400 | QNetworkAccessManager manager; |
401 | NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); |
402 | QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); |
403 | manager.setCache(diskCache); |
404 | |
405 | QString url = "httpcachetest_cachecontrol.cgi?max-age=1000" ; |
406 | QNetworkRequest request(QUrl(TESTFILE + url)); |
407 | QNetworkReply *reply = manager.get(request); |
408 | QSignalSpy downloaded1(reply, SIGNAL(finished())); |
409 | manager.setCache(0); |
410 | QTRY_COMPARE(downloaded1.count(), 1); |
411 | } |
412 | |
413 | |
414 | QTEST_MAIN(tst_QAbstractNetworkCache) |
415 | #include "tst_qabstractnetworkcache.moc" |
416 | |
417 | |