aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
aheinecke@404:  * Software engineering by Intevation GmbH
aheinecke@404:  *
aheinecke@404:  * This file is Free Software under the GNU GPL (v>=2)
aheinecke@404:  * and comes with ABSOLUTELY NO WARRANTY!
aheinecke@404:  * See LICENSE.txt for details.
aheinecke@404:  */
aheinecke@43: #include "downloadertest.h"
aheinecke@43: #include "downloader.h"
aheinecke@240: #include "common.h"
aheinecke@43: 
aheinecke@43: #include <QTextStream>
aheinecke@43: #include <QFile>
aheinecke@48: #include <QVariant>
aheinecke@240: #include <unistd.h>
aheinecke@43: 
aheinecke@51: #define MAX_WAIT 20
aheinecke@51: 
aheinecke@51: #define SETUP_SPY \
aheinecke@51:     QSignalSpy newListAvailable(downloader,                                 \
aheinecke@51:             SIGNAL(newListAvailable(const QString&, const QDateTime&)));    \
aheinecke@51:     QSignalSpy newSoftwareAvailable(downloader,                             \
aheinecke@51:            SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&))); \
aheinecke@51:     QSignalSpy errors(downloader, SIGNAL(error(const QString &,             \
aheinecke@51:                     SSLConnection::ErrorCode)));                            \
aheinecke@51: 
aheinecke@43: void DownloaderTest::startServer(QString additionalOptions)
aheinecke@43: {
aheinecke@43:     QFile serverConfig(serverConfigDir.path() + "/" + "hiawatha.conf");
aheinecke@43:     QFile mimeConfig(serverConfigDir.path() + "/" + "mimetype.conf");
aheinecke@43:     if (serverProc.state() == QProcess::Running) {
aheinecke@43:         serverProc.close();
aheinecke@43:     }
aheinecke@43:     serverConfig.open(QIODevice::WriteOnly);
aheinecke@43:     mimeConfig.open(QIODevice::WriteOnly);
aheinecke@43:     mimeConfig.close(); /* just an empty file */
aheinecke@43: 
aheinecke@43:     QTextStream configStream(&serverConfig);
aheinecke@43:     configStream <<
aheinecke@43:         "Binding { " << endl <<
aheinecke@43:         "Port = 44443 " << endl <<
aheinecke@43:         "SSLcertFile = " << SOURCE_DIR <<
aheinecke@43:         "/data/valid_ssl_bp_priv.pem" << endl <<
aheinecke@43:         "Interface = 127.0.0.1" << endl <<
aheinecke@43:         "}" << endl <<
aheinecke@43:         "Hostname = 127.0.0.1" << endl <<
aheinecke@240:         "WebsiteRoot = " << serverConfigDir.path() << endl;
aheinecke@43:     configStream.flush();
aheinecke@43: 
aheinecke@43:     serverConfig.close();
aheinecke@43:     serverProc.start();
aheinecke@43:     serverProc.waitForStarted();
aheinecke@43: }
aheinecke@43: 
aheinecke@43: void DownloaderTest::initTestCase() {
aheinecke@43:     QStringList arguments;
aheinecke@43:     serverProc.setProgram(HIAWATHA_EXECUTABLE);
aheinecke@43:     arguments << "-d" << "-c" << serverConfigDir.path();
aheinecke@43:     serverProc.setArguments(arguments);
aheinecke@45:     qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode");
aheinecke@43:     startServer();
aheinecke@240:     garbageInfo = QFileInfo(getRandomDataFile(2 * 1024, serverConfigDir.path()));
aheinecke@240:     QVERIFY(QFile::copy(QString::fromLocal8Bit(SOURCE_DIR"/data/list-valid.txt"),
aheinecke@240:         serverConfigDir.path() + "/" + "list-valid.txt"));
aheinecke@240: 
aheinecke@43:     QTest::qWait(1000); /* Wait for the server to settle */
aheinecke@43: }
aheinecke@43: 
aheinecke@45: void DownloaderTest::downloaderError(const QString &message, SSLConnection::ErrorCode error)
aheinecke@43: {
aheinecke@43:     qDebug() << "Downloader Error: " << error << " Msg: " << message;
aheinecke@43: }
aheinecke@43: 
aheinecke@47: bool filesEqual(QString filename1, QString filename2)
aheinecke@47: {
aheinecke@47:     bool retval = false;
aheinecke@47:     QFile file1(filename1);
aheinecke@47:     QFile file2(filename2);
aheinecke@47:     file1.open(QIODevice::ReadOnly);
aheinecke@47:     file2.open(QIODevice::ReadOnly);
aheinecke@47: 
aheinecke@47:     retval = (file1.readAll() == file2.readAll());
aheinecke@47:     file1.close();
aheinecke@47:     file2.close();
aheinecke@47:     return retval;
aheinecke@47: }
aheinecke@47: 
aheinecke@52: void DownloaderTest::testOtherCertificate()
aheinecke@52: {
aheinecke@52:     QFile otherCert(QString::fromLatin1(SOURCE_DIR) +
aheinecke@52:             "/data/valid_ssl_rsa.pem");
aheinecke@52:     otherCert.open(QIODevice::ReadOnly);
aheinecke@52: 
aheinecke@240:     QFileInfo fi(getRandomDataFile(200));
aheinecke@240: 
aheinecke@52:     Downloader* downloader = new Downloader(this,
aheinecke@52:             QString::fromLatin1("https://localhost:44443"),
aheinecke@52:             otherCert.readAll(),
aheinecke@52:             QDateTime::currentDateTime(), // Last installed SW
aheinecke@52:             QDateTime::fromString("2010", "YYYY"),
aheinecke@240:             "/" + garbageInfo.fileName(),
aheinecke@52:             "/list-valid.txt");
aheinecke@52:     otherCert.close();
aheinecke@52: 
aheinecke@52:     SETUP_SPY
aheinecke@52: 
aheinecke@52:     downloader->start();
aheinecke@52: 
aheinecke@52:     int waited = 0;
aheinecke@52:     while (errors.count() == 0  && waited < MAX_WAIT) {
aheinecke@52:         QTest::qWait(200);
aheinecke@52:         waited++;
aheinecke@52:     }
aheinecke@52:     QVERIFY(waited != MAX_WAIT);
aheinecke@52:     QVERIFY(newListAvailable.count() == 0);
aheinecke@52:     QVERIFY(newSoftwareAvailable.count() == 0);
aheinecke@52: 
aheinecke@52:     QList<QVariant> arguments = errors.takeFirst();
aheinecke@52: 
aheinecke@52:     int error = arguments.at(1).toInt();
aheinecke@52: 
aheinecke@52:     QVERIFY(error == SSLConnection::InvalidCertificate);
aheinecke@52: }
aheinecke@52: 
aheinecke@48: void DownloaderTest::testNoConnection()
aheinecke@48: {
aheinecke@48:     Downloader* downloader = new Downloader(this,
aheinecke@48:             QString::fromLatin1("https://foobar.intevation.de"));
aheinecke@51: 
aheinecke@51:     SETUP_SPY
aheinecke@51: 
aheinecke@48:     downloader->start();
aheinecke@48: 
aheinecke@48:     int waited = 0;
aheinecke@48:     while (newListAvailable.count() == 0 &&
aheinecke@51:             errors.count() == 0  && waited < MAX_WAIT) {
aheinecke@48:         QTest::qWait(200);
aheinecke@48:         waited++;
aheinecke@48:     }
aheinecke@51:     QVERIFY(waited != MAX_WAIT);
aheinecke@51:     QVERIFY(newListAvailable.count() == 0);
aheinecke@51:     QVERIFY(newSoftwareAvailable.count() == 0);
aheinecke@48: 
aheinecke@48:     QList<QVariant> arguments = errors.takeFirst();
aheinecke@48: 
aheinecke@48:     int error = arguments.at(1).toInt();
aheinecke@48: 
aheinecke@48:     QVERIFY(error == SSLConnection::NoConnection);
aheinecke@48: }
aheinecke@48: 
aheinecke@55: void DownloaderTest::testNewSoftware()
aheinecke@55: {
aheinecke@55:     QFile validCert(QString::fromLatin1(SOURCE_DIR) +
aheinecke@55:             "/data/valid_ssl_bp.pem");
aheinecke@55:     validCert.open(QIODevice::ReadOnly);
aheinecke@55: 
aheinecke@55:     Downloader* downloader = new Downloader(this,
aheinecke@55:             QString::fromLatin1("https://localhost:44443"),
aheinecke@55:             validCert.readAll(),
aheinecke@55:             QDateTime::fromString("2010", "YYYY"),
aheinecke@55:             QDateTime::currentDateTime(),
aheinecke@240:             "/" + garbageInfo.fileName(),
aheinecke@55:             "/list-valid.txt");
aheinecke@55:     validCert.close();
aheinecke@55: 
aheinecke@55:     SETUP_SPY
aheinecke@55: 
aheinecke@55:     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
aheinecke@55:             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
aheinecke@55: 
aheinecke@55:     downloader->start();
aheinecke@55: 
aheinecke@55:     int waited = 0;
aheinecke@55:     while (newSoftwareAvailable.count() == 0 &&
aheinecke@55:             errors.count() == 0  && waited < 20) {
aheinecke@55:         QTest::qWait(200);
aheinecke@55:         waited++;
aheinecke@55:     }
aheinecke@55:     QVERIFY(waited != 20);
aheinecke@55:     QVERIFY(newListAvailable.count() == 0);
aheinecke@55:     QVERIFY(newSoftwareAvailable.count() == 1);
aheinecke@55:     QVERIFY(errors.count() == 0);
aheinecke@55: 
aheinecke@55:     QList<QVariant> arguments = newSoftwareAvailable.takeFirst();
aheinecke@55: 
aheinecke@240:     QVERIFY(filesEqual(serverConfigDir.path() + "/" + garbageInfo.fileName(),
aheinecke@55:         arguments.at(0).toString()));
aheinecke@55: 
aheinecke@55:     delete downloader;
aheinecke@55: }
aheinecke@55: 
aheinecke@43: void DownloaderTest::testNewList()
aheinecke@43: {
aheinecke@43:     QFile validCert(QString::fromLatin1(SOURCE_DIR) +
aheinecke@43:             "/data/valid_ssl_bp.pem");
aheinecke@43:     validCert.open(QIODevice::ReadOnly);
aheinecke@43: 
aheinecke@43:     Downloader* downloader = new Downloader(this,
aheinecke@43:             QString::fromLatin1("https://localhost:44443"),
aheinecke@43:             validCert.readAll(),
aheinecke@43:             QDateTime::currentDateTime(), // Last installed SW
aheinecke@43:             QDateTime::fromString("2010", "YYYY"),
aheinecke@240:             "/" + garbageInfo.fileName(),
aheinecke@46:             "/list-valid.txt");
aheinecke@43:     validCert.close();
aheinecke@43: 
aheinecke@51:     SETUP_SPY
aheinecke@51: 
aheinecke@45:     connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
aheinecke@45:             this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
aheinecke@43: 
aheinecke@43:     downloader->start();
aheinecke@43: 
aheinecke@43:     int waited = 0;
aheinecke@43:     while (newListAvailable.count() == 0 &&
aheinecke@43:             errors.count() == 0  && waited < 20) {
aheinecke@48:         QTest::qWait(200);
aheinecke@43:         waited++;
aheinecke@43:     }
aheinecke@43:     QVERIFY(waited != 20);
aheinecke@43:     QVERIFY(newListAvailable.count() == 1);
aheinecke@43:     QVERIFY(newSoftwareAvailable.count() == 0);
aheinecke@43:     QVERIFY(errors.count() == 0);
aheinecke@47: 
aheinecke@47:     QList<QVariant> arguments = newListAvailable.takeFirst();
aheinecke@47: 
aheinecke@47:     QVERIFY(filesEqual(QString::fromLatin1(SOURCE_DIR) + "/data/list-valid.txt",
aheinecke@47:         arguments.at(0).toString()));
aheinecke@47: 
aheinecke@43:     delete downloader;
aheinecke@43: }
aheinecke@43: 
aheinecke@43: void DownloaderTest::cleanupTestCase() {
aheinecke@43:     if (serverProc.state() == QProcess::Running) {
aheinecke@43:         serverProc.close();
aheinecke@43:     }
aheinecke@43: }
aheinecke@43: 
aheinecke@43: QTEST_GUILESS_MAIN (DownloaderTest);
aheinecke@43: