From 0184a2144b8299a9d9de6e616a74cea39e2f2e28 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Wed, 11 Nov 2009 10:04:31 +1000
Subject: Generalize TestHTTPServer

---
 tests/auto/declarative/shared/testhttpserver.cpp   | 298 +++++++++++++++++++++
 tests/auto/declarative/shared/testhttpserver.h     |  87 ++++++
 .../declarative/xmlhttprequest/testhttpserver.cpp  | 154 -----------
 .../declarative/xmlhttprequest/testhttpserver.h    |  75 ------
 .../declarative/xmlhttprequest/xmlhttprequest.pro  |   5 +-
 5 files changed, 388 insertions(+), 231 deletions(-)
 create mode 100644 tests/auto/declarative/shared/testhttpserver.cpp
 create mode 100644 tests/auto/declarative/shared/testhttpserver.h
 delete mode 100644 tests/auto/declarative/xmlhttprequest/testhttpserver.cpp
 delete mode 100644 tests/auto/declarative/xmlhttprequest/testhttpserver.h

diff --git a/tests/auto/declarative/shared/testhttpserver.cpp b/tests/auto/declarative/shared/testhttpserver.cpp
new file mode 100644
index 0000000..c7b7f25
--- /dev/null
+++ b/tests/auto/declarative/shared/testhttpserver.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testhttpserver.h"
+#include <QTcpSocket>
+#include <QDebug>
+#include <QFile>
+#include <QTimer>
+
+/*!
+\internal
+\class TestHTTPServer
+\brief provides a very, very basic HTTP server for testing.
+
+Inside the test case, an instance of TestHTTPServer should be created, with the
+appropriate port to listen on.  The server will listen on the localhost interface.
+
+Directories to serve can then be added to server, which will be added as "roots".
+Each root can be added as a Normal, Delay or Disconnect root.  Requests for files
+within a Normal root are returned immediately.  Request for files within a Delay
+root are delayed for 500ms, and then served.  Requests for files within a Disconnect
+directory cause the server to disconnect immediately.  A request for a file that isn't
+found in any root will return a 404 error.
+
+If you have the following directory structure:
+
+\code
+disconnect/disconnectTest.qml
+files/main.qml
+files/Button.qml
+files/content/WebView.qml
+slowFiles/slowMain.qml
+\endcode
+it can be added like this:
+\code
+TestHTTPServer server(14445);
+server.serveDirectory("disconnect", TestHTTPServer::Disconnect);
+server.serveDirectory("files");
+server.serveDirectory("slowFiles", TestHTTPServer::Delay);
+\endcode
+
+The following request urls will then result in the appropriate action:
+\table
+\header \o URL \o Action
+\row \o http://localhost:14445/disconnectTest.qml \o Disconnection
+\row \o http://localhost:14445/main.qml \o main.qml returned immediately
+\row \o http://localhost:14445/Button.qml \o Button.qml returned immediately
+\row \o http://localhost:14445/content/WebView.qml \o content/WebView.qml returned immediately
+\row \o http://localhost:14445/slowMain.qml \o slowMain.qml returned after 500ms
+\endtable
+*/
+TestHTTPServer::TestHTTPServer(quint16 port)
+: m_hasFailed(false)
+{
+    QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
+
+    server.listen(QHostAddress::LocalHost, port);
+}
+
+bool TestHTTPServer::isValid() const
+{
+    return server.isListening();
+}
+
+bool TestHTTPServer::serveDirectory(const QString &dir, Mode mode)
+{
+    dirs.append(qMakePair(dir, mode));
+    return true;
+}
+
+bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
+{
+    m_hasFailed = false;
+
+    QFile expectFile(expect.toLocalFile());
+    if (!expectFile.open(QIODevice::ReadOnly)) return false;
+    
+    QFile replyFile(reply.toLocalFile());
+    if (!replyFile.open(QIODevice::ReadOnly)) return false;
+
+    bodyData = QByteArray();
+    if (body.isValid()) {
+        QFile bodyFile(body.toLocalFile());
+        if (!bodyFile.open(QIODevice::ReadOnly)) return false;
+        bodyData = bodyFile.readAll();
+    }
+
+    waitData = expectFile.readAll();
+    /*
+    while (waitData.endsWith('\n'))
+        waitData = waitData.left(waitData.count() - 1);
+        */
+
+    replyData = replyFile.readAll();
+
+    if (!replyData.endsWith('\n'))
+        replyData.append("\n");
+    replyData.append("Content-length: " + QByteArray::number(bodyData.length()));
+    replyData .append("\n\n");
+
+    for (int ii = 0; ii < replyData.count(); ++ii) {
+        if (replyData.at(ii) == '\n' && (!ii || replyData.at(ii - 1) != '\r')) {
+            replyData.insert(ii, '\r');
+            ++ii;
+        }
+    }
+    replyData.append(bodyData);
+
+    return true;
+}
+
+bool TestHTTPServer::hasFailed() const
+{
+    return m_hasFailed;
+}
+
+void TestHTTPServer::newConnection()
+{
+    QTcpSocket *socket = server.nextPendingConnection();
+    if (!socket) return;
+
+    if (!dirs.isEmpty())
+        dataCache.insert(socket, QByteArray());
+
+    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
+    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+void TestHTTPServer::disconnected()
+{
+    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+    if (!socket) return;
+
+    dataCache.remove(socket);
+    for (int ii = 0; ii < toSend.count(); ++ii) {
+        if (toSend.at(ii).first == socket) {
+            toSend.removeAt(ii);
+            --ii;
+        }
+    }
+    socket->deleteLater();
+}
+
+void TestHTTPServer::readyRead()
+{
+    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+    if (!socket) return;
+
+    QByteArray ba = socket->readAll();
+
+    if (!dirs.isEmpty()) {
+        serveGET(socket, ba);
+        return;
+    }
+
+    if (m_hasFailed || waitData.isEmpty()) {
+        qWarning() << "TestHTTPServer: Unexpected data" << ba;
+        return;
+    }
+
+    for (int ii = 0; ii < ba.count(); ++ii) {
+        const char c = ba.at(ii);
+        if (c == '\r' && waitData.isEmpty())
+           continue;
+        else if (!waitData.isEmpty() && c == waitData.at(0))
+            waitData = waitData.mid(1);
+        else if (c == '\r')
+            continue;
+        else {
+            QByteArray data = ba.mid(ii);
+            qWarning() << "TestHTTPServer: Unexpected data" << data;
+            m_hasFailed = true;
+            socket->disconnect();
+            return;
+        }
+    }
+
+    if (waitData.isEmpty()) {
+        socket->write(replyData);
+        socket->disconnect();
+    }
+}
+
+bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileName)
+{
+    for (int ii = 0; ii < dirs.count(); ++ii) {
+        QString dir = dirs.at(ii).first;
+        Mode mode = dirs.at(ii).second;
+
+        QString dirFile = dir + QLatin1String("/") + QLatin1String(fileName);
+        
+        QFile file(dirFile);
+        if (file.open(QIODevice::ReadOnly)) {
+
+            if (mode == Disconnect)
+                return true;
+
+            QByteArray data = file.readAll();
+
+            QByteArray response = "HTTP/1.0 200 OK\r\nContent-type: text/html; charset=UTF-8\r\nContent-length: ";
+            response += QByteArray::number(data.count());
+            response += "\r\n\r\n";
+            response += data;
+
+            if (mode == Delay) {
+                toSend.append(qMakePair(socket, response));
+                QTimer::singleShot(500, this, SLOT(sendOne()));
+                return false;
+            } else {
+                socket->write(response);
+                return true;
+            }
+        }
+    }
+
+
+    QByteArray response = "HTTP/1.0 404 Not found\r\nContent-type: text/html; charset=UTF-8\r\n\r\n";
+    socket->write(response);
+
+    return true;
+}
+
+void TestHTTPServer::sendOne()
+{
+    if (!toSend.isEmpty()) {
+        toSend.first().first->write(toSend.first().second);
+        toSend.first().first->close();
+        toSend.removeFirst();
+    }
+}
+
+void TestHTTPServer::serveGET(QTcpSocket *socket, const QByteArray &data)
+{
+    if (!dataCache.contains(socket))
+        return;
+
+    QByteArray total = dataCache[socket] + data;
+    dataCache[socket] = total;
+    
+    if (total.contains("\n\r\n")) {
+
+        bool close = true;
+
+        if (total.startsWith("GET /")) {
+
+            int space = total.indexOf(' ', 4);
+            if (space != -1) {
+
+                QByteArray req = total.mid(5, space - 5);
+                close = reply(socket, req);
+
+            }
+        }
+        dataCache.remove(socket);
+
+        if (close)
+            socket->close();
+    }
+}
+
diff --git a/tests/auto/declarative/shared/testhttpserver.h b/tests/auto/declarative/shared/testhttpserver.h
new file mode 100644
index 0000000..62fe7b4
--- /dev/null
+++ b/tests/auto/declarative/shared/testhttpserver.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTHTTPSERVER_H
+#define TESTHTTPSERVER_H
+
+#include <QObject>
+#include <QTcpServer>
+#include <QUrl>
+#include <QPair>
+
+class TestHTTPServer : public QObject
+{
+    Q_OBJECT
+public:
+    TestHTTPServer(quint16 port);
+
+    bool isValid() const;
+
+    enum Mode { Normal, Delay, Disconnect };
+    bool serveDirectory(const QString &, Mode = Normal);
+
+    bool wait(const QUrl &expect, const QUrl &reply, const QUrl &body);
+    bool hasFailed() const;
+
+private slots:
+    void newConnection();
+    void disconnected();
+    void readyRead();
+    void sendOne();
+
+private:
+    void serveGET(QTcpSocket *, const QByteArray &);
+    bool reply(QTcpSocket *, const QByteArray &);
+
+    QList<QPair<QString, Mode> > dirs;
+    QHash<QTcpSocket *, QByteArray> dataCache;
+    QList<QPair<QTcpSocket *, QByteArray> > toSend;
+
+    QByteArray waitData;
+    QByteArray replyData;
+    QByteArray bodyData;
+    bool m_hasFailed;
+
+    QTcpServer server;
+};
+
+#endif // TESTHTTPSERVER_H
+
diff --git a/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp b/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp
deleted file mode 100644
index 3b00685..0000000
--- a/tests/auto/declarative/xmlhttprequest/testhttpserver.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "testhttpserver.h"
-#include <QTcpSocket>
-#include <QDebug>
-#include <QFile>
-
-TestHTTPServer::TestHTTPServer(quint16 port)
-: m_hasFailed(false)
-{
-    QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
-
-    server.listen(QHostAddress::LocalHost, port);
-}
-
-bool TestHTTPServer::isValid() const
-{
-    return server.isListening();
-}
-
-bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
-{
-    m_hasFailed = false;
-
-    QFile expectFile(expect.toLocalFile());
-    if (!expectFile.open(QIODevice::ReadOnly)) return false;
-    
-    QFile replyFile(reply.toLocalFile());
-    if (!replyFile.open(QIODevice::ReadOnly)) return false;
-
-    bodyData = QByteArray();
-    if (body.isValid()) {
-        QFile bodyFile(body.toLocalFile());
-        if (!bodyFile.open(QIODevice::ReadOnly)) return false;
-        bodyData = bodyFile.readAll();
-    }
-
-    waitData = expectFile.readAll();
-    /*
-    while (waitData.endsWith('\n'))
-        waitData = waitData.left(waitData.count() - 1);
-        */
-
-    replyData = replyFile.readAll();
-
-    if (!replyData.endsWith('\n'))
-        replyData.append("\n");
-    replyData.append("Content-length: " + QByteArray::number(bodyData.length()));
-    replyData .append("\n\n");
-
-    for (int ii = 0; ii < replyData.count(); ++ii) {
-        if (replyData.at(ii) == '\n' && (!ii || replyData.at(ii - 1) != '\r')) {
-            replyData.insert(ii, '\r');
-            ++ii;
-        }
-    }
-    replyData.append(bodyData);
-
-    return true;
-}
-
-bool TestHTTPServer::hasFailed() const
-{
-    return m_hasFailed;
-}
-
-void TestHTTPServer::newConnection()
-{
-    QTcpSocket *socket = server.nextPendingConnection();
-    if (!socket) return;
-
-    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
-    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
-}
-
-void TestHTTPServer::disconnected()
-{
-    sender()->deleteLater();
-}
-
-void TestHTTPServer::readyRead()
-{
-    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
-    if (!socket) return;
-
-    QByteArray ba = socket->readAll();
-
-    if (m_hasFailed || waitData.isEmpty()) {
-        qWarning() << "TestHTTPServer: Unexpected data" << ba;
-        return;
-    }
-
-    for (int ii = 0; ii < ba.count(); ++ii) {
-        const char c = ba.at(ii);
-        if (c == '\r' && waitData.isEmpty())
-           continue;
-        else if (!waitData.isEmpty() && c == waitData.at(0))
-            waitData = waitData.mid(1);
-        else if (c == '\r')
-            continue;
-        else {
-            QByteArray data = ba.mid(ii);
-            qWarning() << "TestHTTPServer: Unexpected data" << data;
-            m_hasFailed = true;
-            socket->disconnect();
-            return;
-        }
-    }
-
-    if (waitData.isEmpty()) {
-        socket->write(replyData);
-        socket->disconnect();
-    }
-}
-
diff --git a/tests/auto/declarative/xmlhttprequest/testhttpserver.h b/tests/auto/declarative/xmlhttprequest/testhttpserver.h
deleted file mode 100644
index 709532e..0000000
--- a/tests/auto/declarative/xmlhttprequest/testhttpserver.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef TESTHTTPSERVER_H
-#define TESTHTTPSERVER_H
-
-#include <QObject>
-#include <QTcpServer>
-#include <QUrl>
-
-class TestHTTPServer : public QObject
-{
-    Q_OBJECT
-public:
-    TestHTTPServer(quint16 port);
-
-    bool isValid() const;
-
-    bool wait(const QUrl &expect, const QUrl &reply, const QUrl &body);
-    bool hasFailed() const;
-
-private slots:
-    void newConnection();
-    void disconnected();
-    void readyRead();
-
-private:
-    QByteArray waitData;
-    QByteArray replyData;
-    QByteArray bodyData;
-    bool m_hasFailed;
-
-    QTcpServer server;
-};
-
-#endif // TESTHTTPSERVER_H
-
diff --git a/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro b/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro
index 5d35a89..6af4e39 100644
--- a/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro
+++ b/tests/auto/declarative/xmlhttprequest/xmlhttprequest.pro
@@ -2,10 +2,11 @@ load(qttest_p4)
 contains(QT_CONFIG,declarative): QT += declarative webkit network
 macx:CONFIG -= app_bundle
 
-HEADERS += testhttpserver.h
+INCLUDEPATH += ../shared/
+HEADERS += ../shared/testhttpserver.h
 
 SOURCES += tst_xmlhttprequest.cpp \
-           testhttpserver.cpp
+           ../shared/testhttpserver.cpp
 
 
 # Define SRCDIR equal to test's source directory
-- 
cgit v0.12