Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * |
| 9 | * Copyright (C) 2013 Dominik Riebeling |
| 10 | * |
| 11 | * This program is free software; you can redistribute it and/or |
| 12 | * modify it under the terms of the GNU General Public License |
| 13 | * as published by the Free Software Foundation; either version 2 |
| 14 | * of the License, or (at your option) any later version. |
| 15 | * |
| 16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 17 | * KIND, either express or implied. |
| 18 | * |
| 19 | ****************************************************************************/ |
| 20 | |
| 21 | #include <QtTest/QtTest> |
| 22 | #include <QtCore/QObject> |
| 23 | #include "httpget.h" |
| 24 | |
| 25 | #define TEST_USER_AGENT "TestAgent/2.3" |
| 26 | #define TEST_HTTP_TIMEOUT 1000 |
| 27 | #define TEST_BINARY_BLOB "\x01\x10\x20\x30\x40\x50\x60\x70" \ |
| 28 | "\x80\x90\xff\xee\xdd\xcc\xbb\xaa" |
| 29 | |
| 30 | // HttpDaemon is the the class that implements the simple HTTP server. |
| 31 | class HttpDaemon : public QTcpServer |
| 32 | { |
| 33 | Q_OBJECT |
| 34 | public: |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 35 | HttpDaemon(quint16 port = 0, QObject* parent = 0) : QTcpServer(parent) |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 36 | { |
| 37 | listen(QHostAddress::Any, port); |
| 38 | } |
| 39 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 40 | quint16 port(void) { return this->serverPort(); } |
| 41 | |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 42 | #if QT_VERSION < 0x050000 |
| 43 | void incomingConnection(int socket) |
| 44 | #else |
| 45 | // Qt 5 uses a different prototype for this function! |
| 46 | void incomingConnection(qintptr socket) |
| 47 | #endif |
| 48 | { |
| 49 | // When a new client connects, the server constructs a QTcpSocket and all |
| 50 | // communication with the client is done over this QTcpSocket. QTcpSocket |
| 51 | // works asynchronously, this means that all the communication is done |
| 52 | // in the two slots readClient() and discardClient(). |
| 53 | QTcpSocket* s = new QTcpSocket(this); |
| 54 | connect(s, SIGNAL(readyRead()), this, SLOT(readClient())); |
| 55 | connect(s, SIGNAL(disconnected()), this, SLOT(discardClient())); |
| 56 | s->setSocketDescriptor(socket); |
| 57 | } |
| 58 | QList<QString> lastRequestData(void) |
| 59 | { |
| 60 | return m_lastRequestData; |
| 61 | } |
| 62 | void setResponsesToSend(QList<QByteArray> response) |
| 63 | { |
| 64 | m_requestNumber = 0; |
| 65 | m_responsesToSend = response; |
| 66 | } |
| 67 | void reset(void) |
| 68 | { |
| 69 | m_requestNumber = 0; |
| 70 | m_lastRequestData.clear(); |
| 71 | QString now = |
| 72 | QDateTime::currentDateTime().toString("ddd, d MMM yyyy hh:mm:ss"); |
| 73 | m_defaultResponse = QByteArray( |
| 74 | "HTTP/1.1 404 Not Found\r\n" |
| 75 | "Date: " + now.toLatin1() + "\r\n" |
| 76 | "Last-Modified: " + now.toLatin1() + "\r\n" |
| 77 | "Connection: close\r\n" |
| 78 | "\r\n"); |
| 79 | } |
| 80 | |
| 81 | private slots: |
| 82 | void readClient() |
| 83 | { |
| 84 | // This slot is called when the client sent data to the server. |
| 85 | QTcpSocket* socket = (QTcpSocket*)sender(); |
| 86 | // read whole request |
| 87 | QString request; |
| 88 | while(socket->canReadLine()) { |
| 89 | QString line = socket->readLine(); |
| 90 | request.append(line); |
| 91 | if(request.endsWith("\r\n\r\n")) { |
| 92 | m_lastRequestData.append(request); |
| 93 | |
| 94 | if(m_requestNumber < m_responsesToSend.size()) |
| 95 | socket->write(m_responsesToSend.at(m_requestNumber)); |
| 96 | else |
| 97 | socket->write(m_defaultResponse); |
| 98 | socket->close(); |
| 99 | m_requestNumber++; |
| 100 | } |
| 101 | if (socket->state() == QTcpSocket::UnconnectedState) |
| 102 | delete socket; |
| 103 | } |
| 104 | } |
| 105 | void discardClient() |
| 106 | { |
| 107 | QTcpSocket* socket = (QTcpSocket*)sender(); |
| 108 | socket->deleteLater(); |
| 109 | } |
| 110 | |
| 111 | private: |
| 112 | int m_requestNumber; |
| 113 | QList<QByteArray> m_responsesToSend; |
| 114 | QList<QString> m_lastRequestData; |
| 115 | QByteArray m_defaultResponse; |
| 116 | }; |
| 117 | |
| 118 | |
| 119 | class TestHttpGet : public QObject |
| 120 | { |
| 121 | Q_OBJECT |
| 122 | private slots: |
Dominik Riebeling | d24a9ea | 2015-12-18 23:05:13 +0100 | [diff] [blame] | 123 | void testFileUrlRequest(void); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 124 | void testCachedRequest(void); |
| 125 | void testUncachedRepeatedRequest(void); |
| 126 | void testUncachedMovedRequest(void); |
| 127 | void testUserAgent(void); |
| 128 | void testResponseCode(void); |
| 129 | void testContentToBuffer(void); |
| 130 | void testContentToFile(void); |
| 131 | void testNoServer(void); |
| 132 | void testServerTimestamp(void); |
| 133 | void testMovedQuery(void); |
| 134 | void init(void); |
| 135 | void cleanup(void); |
| 136 | |
| 137 | public slots: |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 138 | void waitTimeout(void) |
| 139 | { |
| 140 | m_waitTimeoutOccured = true; |
| 141 | } |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 142 | QDir temporaryFolder(void) |
| 143 | { |
| 144 | // Qt unfortunately doesn't support creating temporary folders so |
| 145 | // we need to do that ourselves. |
| 146 | QString tempdir; |
| 147 | for(int i = 0; i < 100000; i++) { |
| 148 | tempdir = QDir::tempPath() + QString("/qttest-temp-%1").arg(i); |
| 149 | if(!QFileInfo(tempdir).exists()) break; |
| 150 | } |
| 151 | QDir().mkpath(tempdir); |
| 152 | return QDir(tempdir); |
| 153 | } |
| 154 | void rmTree(QString folder) |
| 155 | { |
| 156 | // no function in Qt to recursively delete a folder :( |
| 157 | QDir dir(folder); |
| 158 | Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot |
| 159 | | QDir::System | QDir::Hidden | QDir::AllDirs |
| 160 | | QDir::Files, QDir::DirsFirst)) { |
| 161 | if(info.isDir()) rmTree(info.absoluteFilePath()); |
| 162 | else QFile::remove(info.absoluteFilePath()); |
| 163 | } |
| 164 | dir.rmdir(folder); |
| 165 | } |
| 166 | private: |
| 167 | HttpDaemon *m_daemon; |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 168 | QByteArray m_port; |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 169 | bool m_waitTimeoutOccured; |
| 170 | QString m_now; |
| 171 | QDir m_cachedir; |
Dominik Riebeling | 7d7359a | 2015-12-20 11:10:18 +0100 | [diff] [blame] | 172 | HttpGet *m_getter; |
| 173 | QSignalSpy *m_doneSpy; |
| 174 | QSignalSpy *m_progressSpy; |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 175 | }; |
| 176 | |
| 177 | |
| 178 | void TestHttpGet::init(void) |
| 179 | { |
| 180 | m_now = QDateTime::currentDateTime().toString("ddd, d MMM yyyy hh:mm:ss"); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 181 | m_daemon = new HttpDaemon(0, this); // use port 0 to auto-pick |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 182 | m_daemon->reset(); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 183 | m_port = QString("%1").arg(m_daemon->port()).toLatin1(); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 184 | m_cachedir = temporaryFolder(); |
| 185 | m_getter = new HttpGet(this); |
| 186 | m_doneSpy = new QSignalSpy(m_getter, SIGNAL(done(bool))); |
Dominik Riebeling | 7d7359a | 2015-12-20 11:10:18 +0100 | [diff] [blame] | 187 | m_progressSpy = new QSignalSpy(m_getter, SIGNAL(dataReadProgress(int, int))); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 188 | m_waitTimeoutOccured = false; |
| 189 | } |
| 190 | |
| 191 | void TestHttpGet::cleanup(void) |
| 192 | { |
| 193 | rmTree(m_cachedir.absolutePath()); |
| 194 | if(m_getter) { |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 195 | m_getter->abort(); delete m_getter; m_getter = NULL; |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 196 | } |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 197 | if(m_daemon) { delete m_daemon; m_daemon = NULL; } |
| 198 | if(m_doneSpy) { delete m_doneSpy; m_doneSpy = NULL; } |
Dominik Riebeling | 7d7359a | 2015-12-20 11:10:18 +0100 | [diff] [blame] | 199 | if(m_progressSpy) { delete m_progressSpy; m_progressSpy = NULL; } |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 200 | } |
| 201 | |
Dominik Riebeling | d24a9ea | 2015-12-18 23:05:13 +0100 | [diff] [blame] | 202 | void TestHttpGet::testFileUrlRequest(void) |
| 203 | { |
| 204 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 205 | |
| 206 | QString teststring = "The quick brown fox jumps over the lazy dog."; |
| 207 | QTemporaryFile datafile; |
| 208 | datafile.open(); |
| 209 | datafile.write(teststring.toLatin1()); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 210 | m_getter->getFile(QUrl("file://" + datafile.fileName())); |
Dominik Riebeling | d24a9ea | 2015-12-18 23:05:13 +0100 | [diff] [blame] | 211 | datafile.close(); |
| 212 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 213 | QCoreApplication::processEvents(); |
| 214 | |
| 215 | QCOMPARE(m_doneSpy->count(), 1); |
| 216 | QCOMPARE(m_waitTimeoutOccured, false); |
| 217 | QCOMPARE(m_daemon->lastRequestData().size(), 0); |
| 218 | QCOMPARE(m_getter->readAll(), teststring.toLatin1()); |
| 219 | QCOMPARE(m_getter->httpResponse(), 200); |
Dominik Riebeling | 7d7359a | 2015-12-20 11:10:18 +0100 | [diff] [blame] | 220 | QCOMPARE(m_progressSpy->at(0).at(0).toInt(), 0); |
Dominik Riebeling | d24a9ea | 2015-12-18 23:05:13 +0100 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 224 | /* On uncached requests, HttpGet is supposed to sent a GET request only. |
| 225 | */ |
| 226 | void TestHttpGet::testUncachedRepeatedRequest(void) |
| 227 | { |
| 228 | QList<QByteArray> responses; |
| 229 | responses << QByteArray( |
| 230 | "HTTP/1.1 200 OK\r\n" |
| 231 | "Date: " + m_now.toLatin1() + "\r\n" |
| 232 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 233 | "\r\n\r\n"); |
| 234 | responses << QByteArray( |
| 235 | "HTTP/1.1 200 OK\r\n" |
| 236 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 237 | "Date: " + m_now.toLatin1() + "\r\n" |
| 238 | "\r\n" |
| 239 | "<html></html>\r\n\r\n"); |
| 240 | m_daemon->setResponsesToSend(responses); |
| 241 | |
| 242 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 243 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 244 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 245 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 246 | QCoreApplication::processEvents(); |
| 247 | |
| 248 | QCOMPARE(m_doneSpy->count(), 1); |
| 249 | QCOMPARE(m_waitTimeoutOccured, false); |
| 250 | QCOMPARE(m_daemon->lastRequestData().size(), 1); |
| 251 | QCOMPARE(m_daemon->lastRequestData().at(0).startsWith("GET"), true); |
| 252 | |
| 253 | // request second time |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 254 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 255 | while(m_doneSpy->count() < 2 && m_waitTimeoutOccured == false) |
| 256 | QCoreApplication::processEvents(); |
| 257 | QCOMPARE(m_doneSpy->count(), 2); |
| 258 | QCOMPARE(m_waitTimeoutOccured, false); |
| 259 | QCOMPARE(m_daemon->lastRequestData().size(), 2); |
| 260 | QCOMPARE(m_daemon->lastRequestData().at(1).startsWith("GET"), true); |
| 261 | QCOMPARE(m_getter->httpResponse(), 200); |
| 262 | } |
| 263 | |
| 264 | /* With enabled cache HttpGet is supposed to check the server file using a HEAD |
| 265 | * request first, then request the file using GET if the server file is newer |
| 266 | * than the cached one (or the file does not exist in the cache) |
| 267 | */ |
| 268 | void TestHttpGet::testCachedRequest(void) |
| 269 | { |
| 270 | QList<QByteArray> responses; |
| 271 | responses << QByteArray( |
| 272 | "HTTP/1.1 302 Found\r\n" |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 273 | "Location: http://localhost:" + m_port + "/test2.txt\r\n" |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 274 | "Date: " + m_now.toLatin1() + "\r\n" |
| 275 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 276 | "\r\n"); |
| 277 | responses << QByteArray( |
| 278 | "HTTP/1.1 200 OK\r\n" |
| 279 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 280 | "Date: " + m_now.toLatin1() + "\r\n" |
| 281 | "\r\n" |
| 282 | "<html></html>\r\n\r\n"); |
| 283 | responses << QByteArray( |
| 284 | "HTTP/1.1 200 OK\r\n" |
| 285 | "Last-Modified: 1 Jan 2000 00:00:00\r\n" |
| 286 | "Date: " + m_now.toLatin1() + "\r\n" |
| 287 | "\r\n"); |
| 288 | m_daemon->setResponsesToSend(responses); |
| 289 | |
| 290 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 291 | |
| 292 | m_getter->setCache(m_cachedir); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 293 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 294 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 295 | QCoreApplication::processEvents(); |
| 296 | |
| 297 | QList<QString> requests = m_daemon->lastRequestData(); |
| 298 | QCOMPARE(m_doneSpy->count(), 1); |
| 299 | QCOMPARE(m_doneSpy->at(0).at(0).toBool(), false); |
| 300 | QCOMPARE(m_waitTimeoutOccured, false); |
| 301 | QCOMPARE(requests.size(), 2); |
| 302 | QCOMPARE(requests.at(0).startsWith("GET"), true); |
| 303 | QCOMPARE(requests.at(1).startsWith("GET"), true); |
| 304 | QCOMPARE(m_getter->httpResponse(), 200); |
| 305 | |
| 306 | // request real file, this time the response should come from cache. |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 307 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test2.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 308 | while(m_doneSpy->count() < 2 && m_waitTimeoutOccured == false) |
| 309 | QCoreApplication::processEvents(); |
| 310 | QCOMPARE(m_doneSpy->count(), 2); // 2 requests, 2 times done() |
| 311 | QCOMPARE(m_doneSpy->at(1).at(0).toBool(), false); |
| 312 | QCOMPARE(m_waitTimeoutOccured, false); |
| 313 | QCOMPARE(m_daemon->lastRequestData().size(), 3); |
| 314 | // redirect will not cache as the redirection target file. |
| 315 | QCOMPARE(m_daemon->lastRequestData().at(2).startsWith("GET"), true); |
| 316 | QCOMPARE(m_getter->httpResponse(), 200); |
| 317 | } |
| 318 | |
| 319 | /* When a custom user agent is set all requests are supposed to contain it. |
| 320 | * Enable cache to make HttpGet performs a HEAD request. Answer with 302, so |
| 321 | * HttpGet follows and sends another HEAD request before finally doing a GET. |
| 322 | */ |
| 323 | void TestHttpGet::testUserAgent(void) |
| 324 | { |
| 325 | QList<QByteArray> responses; |
| 326 | responses << QByteArray( |
| 327 | "HTTP/1.1 200 OK\r\n" |
| 328 | "Date: " + m_now.toLatin1() + "\r\n" |
| 329 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 330 | "\r\n\r\n"); |
| 331 | responses << QByteArray( |
| 332 | "HTTP/1.1 200 OK\r\n" |
| 333 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 334 | "Date: " + m_now.toLatin1() + "\r\n" |
| 335 | "\r\n" |
| 336 | "<html></html>\r\n\r\n"); |
| 337 | m_daemon->setResponsesToSend(responses); |
| 338 | |
| 339 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 340 | |
| 341 | m_getter->setGlobalUserAgent(TEST_USER_AGENT); |
| 342 | m_getter->setCache(m_cachedir); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 343 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 344 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 345 | QCoreApplication::processEvents(); |
| 346 | |
| 347 | QList<QString> requests = m_daemon->lastRequestData(); |
| 348 | QCOMPARE(m_doneSpy->count(), 1); |
| 349 | QCOMPARE(m_waitTimeoutOccured, false); |
| 350 | QCOMPARE(requests.size(), 1); |
| 351 | QCOMPARE(requests.at(0).startsWith("GET"), true); |
| 352 | |
| 353 | for(int i = 0; i < requests.size(); ++i) { |
| 354 | QRegExp rx("User-Agent:[\t ]+([a-zA-Z0-9\\./]+)"); |
| 355 | bool userAgentFound = rx.indexIn(requests.at(i)) > 0 ? true : false; |
| 356 | QCOMPARE(userAgentFound, true); |
| 357 | QString userAgentString = rx.cap(1); |
| 358 | QCOMPARE(userAgentString, QString(TEST_USER_AGENT)); |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | void TestHttpGet::testUncachedMovedRequest(void) |
| 363 | { |
| 364 | QList<QByteArray> responses; |
| 365 | responses << QByteArray( |
| 366 | "HTTP/1.1 302 Found\r\n" |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 367 | "Location: http://localhost:" + m_port + "/test2.txt\r\n" |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 368 | "Date: " + m_now.toLatin1() + "\r\n" |
| 369 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 370 | "\r\n"); |
| 371 | responses << QByteArray( |
| 372 | "HTTP/1.1 200 OK\r\n" |
| 373 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 374 | "Date: " + m_now.toLatin1() + "\r\n" |
| 375 | "\r\n" |
| 376 | "<html></html>\r\n\r\n"); |
| 377 | m_daemon->setResponsesToSend(responses); |
| 378 | |
| 379 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 380 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 381 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.php?var=1&b=foo")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 382 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 383 | QCoreApplication::processEvents(); |
| 384 | |
| 385 | QCOMPARE(m_doneSpy->count(), 1); |
| 386 | QCOMPARE(m_waitTimeoutOccured, false); |
| 387 | QCOMPARE(m_daemon->lastRequestData().size(), 2); |
| 388 | QCOMPARE(m_daemon->lastRequestData().at(0).startsWith("GET"), true); |
| 389 | QCOMPARE(m_daemon->lastRequestData().at(1).startsWith("GET"), true); |
| 390 | } |
| 391 | |
| 392 | void TestHttpGet::testResponseCode(void) |
| 393 | { |
| 394 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 395 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 396 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 397 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 398 | QCoreApplication::processEvents(); |
| 399 | |
| 400 | QCOMPARE(m_doneSpy->count(), 1); |
| 401 | QCOMPARE(m_doneSpy->at(0).at(0).toBool(), true); |
| 402 | QCOMPARE(m_waitTimeoutOccured, false); |
| 403 | QCOMPARE(m_daemon->lastRequestData().size(), 1); |
| 404 | QCOMPARE(m_daemon->lastRequestData().at(0).startsWith("GET"), true); |
| 405 | QCOMPARE(m_getter->httpResponse(), 404); |
| 406 | } |
| 407 | |
| 408 | void TestHttpGet::testContentToBuffer(void) |
| 409 | { |
| 410 | QList<QByteArray> responses; |
| 411 | responses << QByteArray( |
| 412 | "HTTP/1.1 200 OK\r\n" |
| 413 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 414 | "Date: " + m_now.toLatin1() + "\r\n" |
| 415 | "\r\n" |
| 416 | TEST_BINARY_BLOB); |
| 417 | m_daemon->setResponsesToSend(responses); |
| 418 | |
| 419 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 420 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 421 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 422 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 423 | QCoreApplication::processEvents(); |
| 424 | |
| 425 | QCOMPARE(m_doneSpy->count(), 1); |
| 426 | QCOMPARE(m_waitTimeoutOccured, false); |
| 427 | QCOMPARE(m_getter->readAll(), QByteArray(TEST_BINARY_BLOB)); |
| 428 | // sizeof(TEST_BINARY_BLOB) will include an additional terminating NULL. |
| 429 | QCOMPARE((unsigned long)m_getter->readAll().size(), sizeof(TEST_BINARY_BLOB) - 1); |
Dominik Riebeling | 7d7359a | 2015-12-20 11:10:18 +0100 | [diff] [blame] | 430 | QCOMPARE(m_progressSpy->at(m_progressSpy->count() - 1).at(0).toInt(), (int)sizeof(TEST_BINARY_BLOB) - 1); |
| 431 | QCOMPARE(m_progressSpy->at(m_progressSpy->count() - 1).at(1).toInt(), (int)sizeof(TEST_BINARY_BLOB) - 1); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 432 | } |
| 433 | |
| 434 | void TestHttpGet::testContentToFile(void) |
| 435 | { |
| 436 | QTemporaryFile tf(this); |
| 437 | QList<QByteArray> responses; |
| 438 | responses << QByteArray( |
| 439 | "HTTP/1.1 200 OK\r\n" |
| 440 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 441 | "Date: " + m_now.toLatin1() + "\r\n" |
| 442 | "\r\n" |
| 443 | TEST_BINARY_BLOB); |
| 444 | m_daemon->setResponsesToSend(responses); |
| 445 | |
| 446 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 447 | |
| 448 | m_getter->setFile(&tf); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 449 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 450 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 451 | QCoreApplication::processEvents(); |
| 452 | |
| 453 | QCOMPARE(m_doneSpy->count(), 1); |
| 454 | QCOMPARE(m_waitTimeoutOccured, false); |
| 455 | |
| 456 | tf.open(); |
| 457 | QByteArray data = tf.readAll(); |
| 458 | QCOMPARE(data, QByteArray(TEST_BINARY_BLOB)); |
| 459 | QCOMPARE((unsigned long)data.size(), sizeof(TEST_BINARY_BLOB) - 1); |
| 460 | tf.close(); |
| 461 | } |
| 462 | |
| 463 | void TestHttpGet::testNoServer(void) |
| 464 | { |
| 465 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 466 | m_getter->getFile(QUrl("http://localhost:53/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 467 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 468 | QCoreApplication::processEvents(); |
| 469 | |
| 470 | QCOMPARE(m_doneSpy->count(), 1); |
| 471 | QCOMPARE(m_doneSpy->at(0).at(0).toBool(), true); |
| 472 | QCOMPARE(m_waitTimeoutOccured, false); |
| 473 | } |
| 474 | |
| 475 | void TestHttpGet::testServerTimestamp(void) |
| 476 | { |
| 477 | QList<QByteArray> responses; |
| 478 | responses << QByteArray( |
| 479 | "HTTP/1.1 200 OK\r\n" |
| 480 | "Last-Modified: Wed, 20 Jan 2010 10:20:30\r\n" // RFC 822 |
| 481 | "Date: Wed, 20 Jan 2010 10:20:30\r\n" |
| 482 | "\r\n" |
| 483 | "\r\n"); |
| 484 | responses << QByteArray( |
| 485 | "HTTP/1.1 200 OK\r\n" |
| 486 | "Last-Modified: Sat Feb 19 09:08:07 2011\r\n" // asctime |
| 487 | "Date: Sat Feb 19 09:08:07 2011\r\n" |
| 488 | "\r\n" |
| 489 | "\r\n"); |
| 490 | |
| 491 | QList<QDateTime> times; |
| 492 | times << QDateTime::fromString("2010-01-20T11:20:30", Qt::ISODate); |
| 493 | times << QDateTime::fromString("2011-02-19T10:08:07", Qt::ISODate); |
| 494 | |
| 495 | m_daemon->setResponsesToSend(responses); |
| 496 | |
| 497 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 498 | |
| 499 | int count = m_doneSpy->count(); |
| 500 | for(int i = 0; i < responses.size(); ++i) { |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 501 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.txt")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 502 | while(m_doneSpy->count() == count && m_waitTimeoutOccured == false) |
| 503 | QCoreApplication::processEvents(); |
| 504 | count = m_doneSpy->count(); |
| 505 | QCOMPARE(m_getter->timestamp(), times.at(i)); |
| 506 | } |
| 507 | } |
| 508 | |
| 509 | void TestHttpGet::testMovedQuery(void) |
| 510 | { |
| 511 | QList<QByteArray> responses; |
| 512 | responses << QByteArray( |
| 513 | "HTTP/1.1 302 Found\r\n" |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 514 | "Location: http://localhost:" + m_port + "/test2.php\r\n" |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 515 | "Date: " + m_now.toLatin1() + "\r\n" |
| 516 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 517 | "\r\n"); |
| 518 | responses << QByteArray( |
| 519 | "HTTP/1.1 200 OK\r\n" |
| 520 | "Last-Modified: " + m_now.toLatin1() + "\r\n" |
| 521 | "Date: " + m_now.toLatin1() + "\r\n" |
| 522 | "\r\n" |
| 523 | "<html></html>\r\n\r\n"); |
| 524 | m_daemon->setResponsesToSend(responses); |
| 525 | |
| 526 | QTimer::singleShot(TEST_HTTP_TIMEOUT, this, SLOT(waitTimeout(void))); |
| 527 | |
Dominik Riebeling | 7e7fd0c | 2015-12-18 23:15:13 +0100 | [diff] [blame] | 528 | m_getter->getFile(QUrl("http://localhost:" + m_port + "/test1.php?var=1&b=foo")); |
Dominik Riebeling | e96df43 | 2013-01-27 10:40:09 +0100 | [diff] [blame] | 529 | while(m_doneSpy->count() == 0 && m_waitTimeoutOccured == false) |
| 530 | QCoreApplication::processEvents(); |
| 531 | |
| 532 | QCOMPARE(m_doneSpy->count(), 1); |
| 533 | QCOMPARE(m_waitTimeoutOccured, false); |
| 534 | QCOMPARE(m_getter->httpResponse(), 200); |
| 535 | QCOMPARE(m_daemon->lastRequestData().size(), 2); |
| 536 | QCOMPARE(m_daemon->lastRequestData().at(0).startsWith("GET"), true); |
| 537 | QCOMPARE(m_daemon->lastRequestData().at(1).startsWith("GET"), true); |
| 538 | // current implementation keeps order of query items. |
| 539 | QCOMPARE((bool)m_daemon->lastRequestData().at(1).contains("/test2.php?var=1&b=foo"), true); |
| 540 | } |
| 541 | |
| 542 | QTEST_MAIN(TestHttpGet) |
| 543 | |
| 544 | // this include is needed because we don't use a separate header file for the |
| 545 | // test class. It also needs to be at the end. |
| 546 | #include "test-httpget.moc" |
| 547 | |