From 8cfafdfb1e93c332723885c8a3f9bc20c2f6843a Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Wed, 3 Apr 2013 16:40:44 +0200 Subject: [PATCH] Extract some code into libtestutils 1. Un-inline SandboxFileEngineHandler (originally it was all implemented in single header file to avoid the need for a real library to be linked) 2. Extract RndSsuCliTest::Process 3. Keep all the stuff inside tests/testutils --- buildpath.pri | 5 +- tests/sandbox/sandboxfileenginehandler.h | 90 ------------------- tests/tests.pri | 2 +- tests/tests.pro | 3 +- tests/tests.xml | 10 +-- tests/testutils/process.cpp | 68 ++++++++++++++ tests/testutils/process.h | 36 ++++++++ tests/testutils/runtest.sh | 4 + tests/testutils/sandboxfileenginehandler.cpp | 88 ++++++++++++++++++ tests/testutils/sandboxfileenginehandler.h | 19 ++++ tests/{sandbox => testutils}/sandboxhook.cpp | 0 .../sandbox.pro => testutils/sandboxhook.pro} | 2 + tests/testutils/testutils.pro | 27 ++++++ tests/ut_rndssucli/rndssuclitest.cpp | 63 +------------ tests/ut_rndssucli/rndssuclitest.h | 2 - tests/ut_rndssucli/ut_rndssucli.pro | 1 + tests/ut_urlresolver/main.cpp | 2 +- tests/ut_urlresolver/ut_urlresolver.pro | 2 +- 18 files changed, 261 insertions(+), 163 deletions(-) delete mode 100644 tests/sandbox/sandboxfileenginehandler.h create mode 100644 tests/testutils/process.cpp create mode 100644 tests/testutils/process.h create mode 100755 tests/testutils/runtest.sh create mode 100644 tests/testutils/sandboxfileenginehandler.cpp create mode 100644 tests/testutils/sandboxfileenginehandler.h rename tests/{sandbox => testutils}/sandboxhook.cpp (100%) rename tests/{sandbox/sandbox.pro => testutils/sandboxhook.pro} (94%) create mode 100644 tests/testutils/testutils.pro diff --git a/buildpath.pri b/buildpath.pri index b24d94a..a79c051 100644 --- a/buildpath.pri +++ b/buildpath.pri @@ -16,6 +16,9 @@ UI_HEADERS_DIR = $$BUILD UI_SOURCES_DIR = $$BUILD RCC_DIR = $$BUILD +# This definitely needs to be refactorized somehow (the common module{.pro,.pri,_dependencies.pri} +# approach would do a good job here) LIBS += -L$$PWD/build/libssu -LD_LIBRARY_PATH = $$PWD/build/libssu +LIBS += -L$$PWD/build/testutils +LD_LIBRARY_PATH = $$PWD/build/libssu:$$PWD/build/testutils INCLUDEPATH += $$PWD/libssu diff --git a/tests/sandbox/sandboxfileenginehandler.h b/tests/sandbox/sandboxfileenginehandler.h deleted file mode 100644 index a2e2312..0000000 --- a/tests/sandbox/sandboxfileenginehandler.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file sandboxfileenginehandler.h - * @copyright 2013 Jolla Ltd. - * @author Martin Kampas - * @date 2013 - */ - -#ifndef _SANDBOXINGFILEENGINEHANDLER_H -#define _SANDBOXINGFILEENGINEHANDLER_H - -#include -#include -#include -#include -#include -#include - -#include -#include "../../constants.h" - -/** - * Redirects all file operations on system configuration files to files under - * directory specified by SSU_TESTS_SANDBOX environment variable. - */ -class SandboxFileEngineHandler : public QAbstractFileEngineHandler { - public: - QAbstractFileEngine *create(const QString &fileName) const{ - static bool enabled = false; - static bool firstCall = true; - - if (!enabled && !firstCall){ - return 0; - } - - static QString sandboxPath = - QProcessEnvironment::systemEnvironment().value("SSU_TESTS_SANDBOX"); - - if (firstCall){ - firstCall = false; - - if (sandboxPath.isEmpty()){ - return 0; - } - - if (!QFileInfo(sandboxPath).exists()){ - qFatal("%s: Invalid SSU_TESTS_SANDBOX value: No such file or directory", - qPrintable(sandboxPath)); - } - - if (!QFileInfo(sandboxPath).isDir()){ - qFatal("%s: Invalid SSU_TESTS_SANDBOX value: Not a directory", - qPrintable(sandboxPath)); - } - - enabled = true; - } - - if (!fileName.startsWith('/')){ - return 0; - } - - static QSet ssuConfigFiles = QSet() - << SSU_CONFIGURATION - << SSU_REPO_CONFIGURATION - << SSU_DEFAULT_CONFIGURATION - << SSU_BOARD_MAPPING_CONFIGURATION; - - static QSet ssuConfigDirectories = QSet() - << SSU_BOARD_MAPPING_CONFIGURATION_DIR; - - if (!ssuConfigFiles.contains(fileName)){ - bool match = false; - foreach (const QString &ssuConfigDirectory, ssuConfigDirectories){ - if (fileName.startsWith(ssuConfigDirectory + '/')){ - match = true; - break; - } - } - if (!match){ - return 0; - } - } - - const QString fileName_ = QDir(sandboxPath).absoluteFilePath(QString(fileName).remove(0, 1)); - - return new QFSFileEngine(fileName_); - } -}; - -#endif diff --git a/tests/tests.pri b/tests/tests.pri index 29b0ac5..fed6f55 100644 --- a/tests/tests.pri +++ b/tests/tests.pri @@ -1,4 +1,4 @@ -DEPENDPATH *= $${PWD}/sandbox +DEPENDPATH *= $${PWD}/testutils TESTS_PATH = /opt/tests/ssu DEFINES += TESTS_PATH="'\"$${TESTS_PATH}\"'" diff --git a/tests/tests.pro b/tests/tests.pro index 90a1a32..f31c353 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs CONFIG += qt ordered coverage debug SUBDIRS = \ - sandbox \ + testutils \ + testutils/sandboxhook.pro \ ut_rndssucli \ ut_settings \ ut_ssuurlresolver \ diff --git a/tests/tests.xml b/tests/tests.xml index b68337d..a75f6a8 100644 --- a/tests/tests.xml +++ b/tests/tests.xml @@ -5,27 +5,27 @@ - /opt/tests/ssu/ut_rndssucli + /opt/tests/ssu/runtest.sh ut_rndssucli - /opt/tests/ssu/ut_settings + /opt/tests/ssu/runtest.sh ut_settings - /opt/tests/ssu/ut_ssuurlresolver + /opt/tests/ssu/runtest.sh ut_ssuurlresolver - /opt/tests/ssu/ut_urlresolver + /opt/tests/ssu/runtest.sh ut_urlresolver - /opt/tests/ssu/ut_variables + /opt/tests/ssu/runtest.sh ut_variables diff --git a/tests/testutils/process.cpp b/tests/testutils/process.cpp new file mode 100644 index 0000000..f2f27d5 --- /dev/null +++ b/tests/testutils/process.cpp @@ -0,0 +1,68 @@ +/** + * @file process.cpp + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#include "process.h" + +/** + * @class Wraps QProcess for easier use within test code + * + * Example use: + * + * @code + * Process ssu; + * const QString output = ssu.execute("ssu", QStringList() << "mode"); + * QVERIFY2(!ssu.hasError(), qPrintable(ssu.fmtErrorMessage())); + * + * QCOMPARE(output, "..."); + * @endcode + */ + +Process::Process() : m_expectFail(false), m_timedOut(false) {} + +QString Process::execute(const QString &program, const QStringList &arguments, + bool expectedResult){ + Q_ASSERT(processStatus() == NotRunning); + m_program = program; + m_arguments = arguments; + m_expectFail = expectedResult == ExpectFail; + m_process.start(program, arguments); + m_timedOut = !m_process.waitForFinished(); + return m_process.readAllStandardOutput(); +} + +bool Process::hasError(){ + return m_timedOut + || m_process.error() != QProcess::UnknownError + || m_process.exitStatus() != QProcess::NormalExit + || (m_process.exitCode() != 0) != m_expectFail; +} + +QString Process::fmtErrorMessage(){ + Q_ASSERT(hasError()); + + QStringList reasons; + if (m_timedOut){ + reasons.append("Timed out"); + }else if (m_process.exitStatus() != QProcess::NormalExit){ + reasons.append("Process crashed"); + }else if (m_expectFail && (m_process.exitCode() == 0)){ + reasons.append("Did not fail while it was expected to"); + }else{ + if (m_process.error() != QProcess::UnknownError){ + reasons.append(m_process.errorString()); + } + const QString errorOut = m_process.readAllStandardError(); + if (!errorOut.isEmpty()){ + reasons.append(errorOut); + } + } + + return QString("Failed to execute `%1 %2`: %3") + .arg(m_program) + .arg(QStringList(m_arguments).replaceInStrings(QRegExp("^|$"), "\"").join(" ")) + .arg(reasons.join(": ")); +} diff --git a/tests/testutils/process.h b/tests/testutils/process.h new file mode 100644 index 0000000..4c6fbcf --- /dev/null +++ b/tests/testutils/process.h @@ -0,0 +1,36 @@ +/** + * @file process.h + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#ifndef _PROCESS_H +#define _PROCESS_H + +#include + +class Process { + public: + enum ExpectedResult { + ExpectSuccess, + ExpectFail + }; + + public: + Process(); + + QString execute(const QString &program, const QStringList &arguments, + bool expectedResult = ExpectSuccess); + bool hasError(); + QString fmtErrorMessage(); + + private: + QProcess m_process; + QString m_program; + QStringList m_arguments; + bool m_expectFail; + bool m_timedOut; +}; + +#endif diff --git a/tests/testutils/runtest.sh b/tests/testutils/runtest.sh new file mode 100755 index 0000000..ed5e8b3 --- /dev/null +++ b/tests/testutils/runtest.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +export LD_LIBRARY_PATH="`dirname "$0"`:${LD_LIBRARY_PATH}" +exec "`dirname "$0"`/$1" diff --git a/tests/testutils/sandboxfileenginehandler.cpp b/tests/testutils/sandboxfileenginehandler.cpp new file mode 100644 index 0000000..e8e380b --- /dev/null +++ b/tests/testutils/sandboxfileenginehandler.cpp @@ -0,0 +1,88 @@ +/** + * @file sandboxfileenginehandler.cpp + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#include "sandboxfileenginehandler.h" + +#include +#include +#include +#include +#include + +#include +#include "../../constants.h" + +/** + * @class SandboxFileEngineHandler + * + * Redirects all file operations on system configuration files to files under + * directory specified by SSU_TESTS_SANDBOX environment variable. + */ + +SandboxFileEngineHandler::SandboxFileEngineHandler() {} + +QAbstractFileEngine *SandboxFileEngineHandler::create(const QString &fileName) const{ + static bool enabled = false; + static bool firstCall = true; + + if (!enabled && !firstCall){ + return 0; + } + + static QString sandboxPath = + QProcessEnvironment::systemEnvironment().value("SSU_TESTS_SANDBOX"); + + if (firstCall){ + firstCall = false; + + if (sandboxPath.isEmpty()){ + return 0; + } + + if (!QFileInfo(sandboxPath).exists()){ + qFatal("%s: Invalid SSU_TESTS_SANDBOX value: No such file or directory", + qPrintable(sandboxPath)); + } + + if (!QFileInfo(sandboxPath).isDir()){ + qFatal("%s: Invalid SSU_TESTS_SANDBOX value: Not a directory", + qPrintable(sandboxPath)); + } + + enabled = true; + } + + if (!fileName.startsWith('/')){ + return 0; + } + + static QSet ssuConfigFiles = QSet() + << SSU_CONFIGURATION + << SSU_REPO_CONFIGURATION + << SSU_DEFAULT_CONFIGURATION + << SSU_BOARD_MAPPING_CONFIGURATION; + + static QSet ssuConfigDirectories = QSet() + << SSU_BOARD_MAPPING_CONFIGURATION_DIR; + + if (!ssuConfigFiles.contains(fileName)){ + bool match = false; + foreach (const QString &ssuConfigDirectory, ssuConfigDirectories){ + if (fileName.startsWith(ssuConfigDirectory + '/')){ + match = true; + break; + } + } + if (!match){ + return 0; + } + } + + const QString fileName_ = QDir(sandboxPath).absoluteFilePath(QString(fileName).remove(0, 1)); + + return new QFSFileEngine(fileName_); +} diff --git a/tests/testutils/sandboxfileenginehandler.h b/tests/testutils/sandboxfileenginehandler.h new file mode 100644 index 0000000..4888773 --- /dev/null +++ b/tests/testutils/sandboxfileenginehandler.h @@ -0,0 +1,19 @@ +/** + * @file sandboxfileenginehandler.h + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#ifndef _SANDBOXINGFILEENGINEHANDLER_H +#define _SANDBOXINGFILEENGINEHANDLER_H + +#include + +class SandboxFileEngineHandler : public QAbstractFileEngineHandler { + public: + SandboxFileEngineHandler(); + QAbstractFileEngine *create(const QString &fileName) const; +}; + +#endif diff --git a/tests/sandbox/sandboxhook.cpp b/tests/testutils/sandboxhook.cpp similarity index 100% rename from tests/sandbox/sandboxhook.cpp rename to tests/testutils/sandboxhook.cpp diff --git a/tests/sandbox/sandbox.pro b/tests/testutils/sandboxhook.pro similarity index 94% rename from tests/sandbox/sandbox.pro rename to tests/testutils/sandboxhook.pro index f4a83bf..0b607e1 100644 --- a/tests/sandbox/sandbox.pro +++ b/tests/testutils/sandboxhook.pro @@ -7,6 +7,8 @@ CONFIG += console qtestlib QT -= gui QT += network testlib +LIBS += -ltestutils + !include( ../tests.pri ) { error("Unable to find tests include") } unix:target.path = $${PREFIX}/$$TESTS_PATH diff --git a/tests/testutils/testutils.pro b/tests/testutils/testutils.pro new file mode 100644 index 0000000..a19124d --- /dev/null +++ b/tests/testutils/testutils.pro @@ -0,0 +1,27 @@ +HEADERS = \ + process.h \ + sandboxfileenginehandler.h \ + +SOURCES = \ + process.cpp \ + sandboxfileenginehandler.cpp \ + +TEMPLATE = lib +TARGET = testutils +CONFIG -= app_bundle +CONFIG += console qtestlib +QT -= gui +QT += network testlib + +LIBS += -lssu + +!include( ../tests.pri ) { error("Unable to find tests include") } + +unix:target.path = $${PREFIX}/$$TESTS_PATH +INSTALLS += target + +exec_wrapper.path = $${PREFIX}/$$TESTS_PATH +exec_wrapper.files = $${PWD}/runtest.sh +INSTALLS += exec_wrapper + +!include( ../../buildpath.pri ) { error("Unable to find build path specification") } diff --git a/tests/ut_rndssucli/rndssuclitest.cpp b/tests/ut_rndssucli/rndssuclitest.cpp index 137aa13..51f6f1a 100644 --- a/tests/ut_rndssucli/rndssuclitest.cpp +++ b/tests/ut_rndssucli/rndssuclitest.cpp @@ -12,68 +12,9 @@ #include -typedef QStringList Args; // improve readability +#include "../testutils/process.h" -class RndSsuCliTest::Process { - public: - enum ExpectedResult { - ExpectSuccess, - ExpectFail - }; - - Process() : m_expectFail(false), m_timedOut(false) {} - - QString execute(const QString &program, const QStringList &arguments, - bool expectedResult = ExpectSuccess){ - Q_ASSERT(processStatus() == NotRunning); - m_program = program; - m_arguments = arguments; - m_expectFail = expectedResult == ExpectFail; - m_process.start(program, arguments); - m_timedOut = !m_process.waitForFinished(); - return m_process.readAllStandardOutput(); - } - - bool hasError(){ - return m_timedOut - || m_process.error() != QProcess::UnknownError - || m_process.exitStatus() != QProcess::NormalExit - || (m_process.exitCode() != 0) != m_expectFail; - } - - QString fmtErrorMessage(){ - Q_ASSERT(hasError()); - - QStringList reasons; - if (m_timedOut){ - reasons.append("Timed out"); - }else if (m_process.exitStatus() != QProcess::NormalExit){ - reasons.append("Process crashed"); - }else if (m_expectFail && (m_process.exitCode() == 0)){ - reasons.append("Did not fail while it was expected to"); - }else{ - if (m_process.error() != QProcess::UnknownError){ - reasons.append(m_process.errorString()); - } - const QString errorOut = m_process.readAllStandardError(); - if (!errorOut.isEmpty()){ - reasons.append(errorOut); - } - } - - return QString("Failed to execute `%1 %2`: %3") - .arg(m_program) - .arg(QStringList(m_arguments).replaceInStrings(QRegExp("^|$"), "\"").join(" ")) - .arg(reasons.join(": ")); - } - - private: - QProcess m_process; - QString m_program; - QStringList m_arguments; - bool m_expectFail; - bool m_timedOut; -}; +typedef QStringList Args; // improve readability void RndSsuCliTest::initTestCase(){ Process mktemp; diff --git a/tests/ut_rndssucli/rndssuclitest.h b/tests/ut_rndssucli/rndssuclitest.h index a0cbf31..96deb9c 100644 --- a/tests/ut_rndssucli/rndssuclitest.h +++ b/tests/ut_rndssucli/rndssuclitest.h @@ -13,8 +13,6 @@ class RndSsuCliTest: public QObject { Q_OBJECT - class Process; - private slots: void initTestCase(); void cleanupTestCase(); diff --git a/tests/ut_rndssucli/ut_rndssucli.pro b/tests/ut_rndssucli/ut_rndssucli.pro index 29563af..ef98d18 100644 --- a/tests/ut_rndssucli/ut_rndssucli.pro +++ b/tests/ut_rndssucli/ut_rndssucli.pro @@ -10,6 +10,7 @@ TARGET = ut_rndssucli LIBS += \ -lssu \ + -ltestutils \ CONFIG -= app_bundle CONFIG += console qtestlib diff --git a/tests/ut_urlresolver/main.cpp b/tests/ut_urlresolver/main.cpp index f89531a..93a0479 100644 --- a/tests/ut_urlresolver/main.cpp +++ b/tests/ut_urlresolver/main.cpp @@ -7,7 +7,7 @@ #include -#include "../sandbox/sandboxfileenginehandler.h" +#include "../testutils/sandboxfileenginehandler.h" #include "urlresolvertest.cpp" int main(int argc, char **argv){ diff --git a/tests/ut_urlresolver/ut_urlresolver.pro b/tests/ut_urlresolver/ut_urlresolver.pro index e335941..ef6bc43 100644 --- a/tests/ut_urlresolver/ut_urlresolver.pro +++ b/tests/ut_urlresolver/ut_urlresolver.pro @@ -3,7 +3,7 @@ SOURCES = main.cpp \ urlresolvertest.cpp TEMPLATE = app TARGET = ut_urlresolver -LIBS += -lssu +LIBS += -lssu -ltestutils CONFIG -= app_bundle CONFIG += console qtestlib QT -= gui