diff --git a/libssu/sandbox.cpp b/libssu/sandbox.cpp index 2f13df2..4273023 100644 --- a/libssu/sandbox.cpp +++ b/libssu/sandbox.cpp @@ -125,6 +125,13 @@ QString Sandbox::map(const QString &fileName) QFileInfo(fileName).absoluteFilePath())); } +QString Sandbox::map(const QString &pathName, const QString &fileName) +{ + return effectiveRootDir().filePath( + QDir::root().relativeFilePath( + QFileInfo(pathName + fileName).absoluteFilePath())); +} + /** * Copies selected files into sandbox. Existing files in sandbox are not overwriten. * diff --git a/libssu/sandbox_p.h b/libssu/sandbox_p.h index 23fabf5..05214ad 100644 --- a/libssu/sandbox_p.h +++ b/libssu/sandbox_p.h @@ -12,6 +12,12 @@ #include #include +// use either environment variable SSU_TESTS_DATA_PATH or compile time +// TESTS_DATA_PATH to locate test data +#define LOCATE_DATA_PATH (getenv("SSU_TESTS_DATA_PATH") ? \ + getenv("SSU_TESTS_DATA_PATH") : \ + TESTS_DATA_PATH) + class Sandbox { public: enum Usage { @@ -36,6 +42,7 @@ class Sandbox { static QDir effectiveRootDir(); static QString map(const QString &fileName); + static QString map(const QString &pathName, const QString &fileName); bool addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter, const QStringList &filterNames = QStringList(), bool recurse = true); diff --git a/run-tests b/run-tests new file mode 100755 index 0000000..b8216cf --- /dev/null +++ b/run-tests @@ -0,0 +1,75 @@ +#!/bin/sh +# +# Simple script to run all tests either in-tree or after test RPM +# installation. Output will be nicely formatted if output formatter +# is available. All arguments to this script are passed to formatoutput. + +prepareInTreeTestData(){ + # this is a dirty hack to get most of the test data into a place + # usable for running tests without installation. Currently this + # causes some duplication + mkdir -p build/testdata + TESTDATA=`find tests -name testdata` + + for t in $TESTDATA; do + test=`echo $t | sed 's,.*tests/,,' | sed 's,/.*,,'` + mkdir -p build/testdata/$test/ + dirs=`find $t/* -prune -type f` + if [ -z "$dirs" ]; then + cp -a $t/* build/testdata/$test/ + else + mkdir -p build/testdata/$test/configroot/usr/share/ssu/ + mkdir -p build/testdata/$test/configroot/etc/ssu/ + for ini in $t/*.ini; do + inifile=`echo $ini | sed 's,.*/,,'` + if [ $inifile = "ssu.ini" ]; then + cp $ini build/testdata/$test/configroot/etc/ssu/ + elif [ $inifile = "board-mappings.ini" ]; then + mkdir -p build/testdata/$test/configroot/usr/share/ssu/board-mappings.d + cp $ini build/testdata/$test/configroot/usr/share/ssu/board-mappings.d/ + else + cp $ini build/testdata/$test/configroot/usr/share/ssu/ + fi + done + cp $t/* build/testdata/$test/configroot/ + for key in $t/*.{key,crt}; do + cp $key build/testdata/$test/ + done + fi + done +} + +if [ -d "build" ]; then + BASE_DIR="`pwd`/build" + export LD_LIBRARY_PATH="$BASE_DIR/lib:${LD_LIBRARY_PATH}" + export SSU_SANDBOX_PATH="$BASE_DIR/lib/libsandboxhook.so" + prepareInTreeTestData + TESTS=`ls $BASE_DIR/bin/ut_*` + if [ -f "$BASE_DIR/bin/formatoutput" ]; then + FORMATOUTPUT="$BASE_DIR/bin/formatoutput" + fi +elif [ -d "/opt/tests/ssu" ]; then + BASE_DIR="/opt/tests/ssu" + export LD_LIBRARY_PATH="$BASE_DIR:${LD_LIBRARY_PATH}" + TESTS=`ls $BASE_DIR/ut_*` + if [ -f "$BASE_DIR/formatoutput" ]; then + FORMATOUTPUT="$BASE_DIR/formatoutput" + fi +else + echo "Neither ./build nor /opt/tests/ssu exist, exiting" + exit 1 +fi + +for test in $TESTS; do + if [ -d "./build/testdata/`basename $test`" ]; then + export SSU_TESTS_DATA_PATH="`pwd`/build/testdata/`basename $test`" + else + unset SSU_TESTS_DATA_PATH + fi + + if [ -z "$FORMATOUTPUT" ]; then + $test | grep -v "^PASS" + else + $test | $FORMATOUTPUT $@ + fi +done diff --git a/tests/formatoutput/formatoutput.pro b/tests/formatoutput/formatoutput.pro new file mode 100644 index 0000000..26564be --- /dev/null +++ b/tests/formatoutput/formatoutput.pro @@ -0,0 +1,4 @@ +TARGET = formatoutput +include(../testapplication.pri) + +SOURCES = main.cpp diff --git a/tests/formatoutput/main.cpp b/tests/formatoutput/main.cpp new file mode 100644 index 0000000..040d3f9 --- /dev/null +++ b/tests/formatoutput/main.cpp @@ -0,0 +1,96 @@ +/** + * @file main.cpp + * @copyright 2015 Jolla Ltd. + * @author Bernd Wachter + * @date 2015 + */ + +#include +#include +#include + +void usage(){ + QTextStream out(stderr); + out << "Parse QTest output on STDIN and make it shiny" << endl + << endl + << "Usage: formatoutput [options]" << endl + << endl + << "\t--skip-pass \tSkip PASS lines [yes]" << endl + << "\t--skip-debug \tSkip QDEBUG lines [yes]" << endl + << "\t--skip-warn \tSkip QWARN lines [no]" << endl + << "\t--skip-config \tSkip Config: lines [yes]" << endl + << endl + << "\t--help \tThis help text" << endl + << endl; +} + +bool isTrue(char *argument){ + if (!strcasecmp(argument, "yes") || + !strcasecmp(argument, "true") || + !strcmp(argument, "1")) + return true; + else return false; +} + +int main(int argc, char **argv){ + QTextStream in(stdin); + QTextStream out(stdout); + int c, option_index; + + static struct option long_options[] = { + {"skip-pass", required_argument, 0, 0 }, + {"skip-debug", required_argument, 0, 0 }, + {"skip-warn", required_argument, 0, 0 }, + {"skip-config", required_argument, 0, 0 }, + {"help", no_argument, 0, 0 } + }; + + struct { + bool skip_pass = true; + bool skip_debug = true; + bool skip_warn = false; + bool skip_config = true; + } options; + + while ((c=getopt_long_only(argc, argv, "", + long_options, &option_index)) != EOF){ + switch(c){ + case 0: + if (!strcmp(long_options[option_index].name, "help")){ + usage(); + exit(0); + } else if (!strcmp(long_options[option_index].name, "skip-pass")){ + options.skip_pass = isTrue(optarg); + } else if (!strcmp(long_options[option_index].name, "skip-debug")){ + options.skip_debug = isTrue(optarg); + } else if (!strcmp(long_options[option_index].name, "skip-warn")){ + options.skip_warn = isTrue(optarg); + } else if (!strcmp(long_options[option_index].name, "skip-config")){ + options.skip_config = isTrue(optarg); + } + break; + default: + usage(); + exit(-1); + } + } + + while (!in.atEnd()){ + QString line = in.readLine(); + + if (line.startsWith("PASS") && options.skip_pass) continue; + if (line.startsWith("QDEBUG") && options.skip_debug) continue; + if (line.startsWith("QWARN") && options.skip_warn) continue; + if (line.startsWith("Config:") && options.skip_config) continue; + + line.replace(QRegExp("^(\\*{3}.*\\*{3})"), "\033[0;36m\\1\033[0;0m"); + line.replace(QRegExp("^(QDEBUG .*)"), "\033[0;90m\\1\033[0;0m"); + line.replace(QRegExp("^(QWARN .*)"), "\033[0;34m\\1\033[0;0m"); + line.replace(QRegExp("^FAIL!"), "\033[0;31mFAIL!\033[0;0m"); + line.replace(QRegExp("^PASS"), "\033[0;32mPASS\033[0;0m"); + line.replace(QRegExp("^Totals: (\\d{1,} passed), (\\d{1,} failed), (\\d{1,} skipped)"), + "Totals: \033[0;32m\\1\033[0;0m, \033[0;31m\\2\033[0;0m, \033[0;33m\\3\033[0;0m"); + out << line << endl; + } + +} diff --git a/tests/tests.pro b/tests/tests.pro index b5477b7..7fe0a0a 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs CONFIG += ordered coverage debug SUBDIRS = \ testutils \ + formatoutput \ testutils/sandboxhook.pro \ ut_coreconfig \ ut_deviceinfo \ @@ -16,4 +17,8 @@ SUBDIRS = \ include(tests_common.pri) tests.files = tests.xml tests.path = $$TESTS_PATH -INSTALLS += tests + +scripts.files = ../run-tests +scripts.path = $$TESTS_PATH + +INSTALLS += tests scripts diff --git a/tests/ut_coreconfig/main.cpp b/tests/ut_coreconfig/main.cpp index 6fc2205..a967946 100644 --- a/tests/ut_coreconfig/main.cpp +++ b/tests/ut_coreconfig/main.cpp @@ -11,7 +11,7 @@ #include "coreconfigtest.h" int main(int argc, char **argv){ - Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + Sandbox sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ThisProcess); if (!sandbox.activate()){ qFatal("Failed to activate sandbox"); diff --git a/tests/ut_deviceinfo/main.cpp b/tests/ut_deviceinfo/main.cpp index 1e363a9..b7519ad 100644 --- a/tests/ut_deviceinfo/main.cpp +++ b/tests/ut_deviceinfo/main.cpp @@ -11,7 +11,7 @@ #include "deviceinfotest.h" int main(int argc, char **argv){ - Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + Sandbox sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ThisProcess); if (!sandbox.activate()){ qFatal("Failed to activate sandbox"); diff --git a/tests/ut_repomanager/main.cpp b/tests/ut_repomanager/main.cpp index bf999f6..8c36ff8 100644 --- a/tests/ut_repomanager/main.cpp +++ b/tests/ut_repomanager/main.cpp @@ -11,7 +11,7 @@ #include "repomanagertest.h" int main(int argc, char **argv){ - Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + Sandbox sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ThisProcess); if (!sandbox.activate()){ qFatal("Failed to activate sandbox"); diff --git a/tests/ut_sandbox/sandboxtest.cpp b/tests/ut_sandbox/sandboxtest.cpp index bf56c00..17480c4 100644 --- a/tests/ut_sandbox/sandboxtest.cpp +++ b/tests/ut_sandbox/sandboxtest.cpp @@ -15,55 +15,55 @@ void SandboxTest::test(){ const QDir::Filters noHidden = QDir::AllEntries | QDir::NoDotAndDotDot; - QCOMPARE(QDir(Sandbox::map(TESTS_DATA_PATH "/world")).entryList(noHidden, QDir::Name), + QCOMPARE(QDir(Sandbox::map(LOCATE_DATA_PATH, "/world")).entryList(noHidden, QDir::Name), QStringList() << "world-and-sandbox" << "world-only" << "world-only-to-be-copied-into-sandbox"); - QVERIFY(!QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-only")).isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/world-only")).trimmed(), + QVERIFY(!QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only")).isWritable()); + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only")).trimmed(), QString("world/world-only")); - QVERIFY(!QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-and-sandbox")).isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/world-and-sandbox")).trimmed(), + QVERIFY(!QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-and-sandbox")).isWritable()); + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/world-and-sandbox")).trimmed(), QString("world/world-and-sandbox")); - QVERIFY(!QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-only-to-be-copied-into-sandbox")) + QVERIFY(!QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only-to-be-copied-into-sandbox")) .isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/world-only-to-be-copied-into-sandbox")) + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only-to-be-copied-into-sandbox")) .trimmed(), QString("world/world-only-to-be-copied-into-sandbox")); - QVERIFY(!QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/sandbox-only")).exists()); + QVERIFY(!QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/sandbox-only")).exists()); - Sandbox sandbox(Sandbox::map(TESTS_DATA_PATH "/sandbox"), + Sandbox sandbox(Sandbox::map(LOCATE_DATA_PATH, "/sandbox"), Sandbox::UseAsSkeleton, Sandbox::ThisProcess | Sandbox::ChildProcesses); - sandbox.addWorldFiles(Sandbox::map(TESTS_DATA_PATH "/world"), QDir::AllEntries, + sandbox.addWorldFiles(Sandbox::map(LOCATE_DATA_PATH, "/world"), QDir::AllEntries, QStringList() << "*-to-be-copied-into-sandbox"); QVERIFY(sandbox.activate()); - QCOMPARE(QDir(Sandbox::map(TESTS_DATA_PATH "/world")).entryList(noHidden, QDir::Name), + QCOMPARE(QDir(Sandbox::map(LOCATE_DATA_PATH, "/world")).entryList(noHidden, QDir::Name), QStringList() << "sandbox-only" << "world-and-sandbox" << "world-only-to-be-copied-into-sandbox"); - QVERIFY(!QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-only")).exists()); + QVERIFY(!QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only")).exists()); - QVERIFY(QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-and-sandbox")).isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/world-and-sandbox")).trimmed(), + QVERIFY(QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-and-sandbox")).isWritable()); + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/world-and-sandbox")).trimmed(), QString("sandbox/world-and-sandbox")); - QVERIFY(QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/world-only-to-be-copied-into-sandbox")) + QVERIFY(QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only-to-be-copied-into-sandbox")) .isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/world-only-to-be-copied-into-sandbox")) + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/world-only-to-be-copied-into-sandbox")) .trimmed(), QString("world/world-only-to-be-copied-into-sandbox")); - QVERIFY(QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/sandbox-only")).exists()); - QVERIFY(QFileInfo(Sandbox::map(TESTS_DATA_PATH "/world/sandbox-only")).isWritable()); - QCOMPARE(readAll(Sandbox::map(TESTS_DATA_PATH "/world/sandbox-only")).trimmed(), + QVERIFY(QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/sandbox-only")).exists()); + QVERIFY(QFileInfo(Sandbox::map(LOCATE_DATA_PATH, "/world/sandbox-only")).isWritable()); + QCOMPARE(readAll(Sandbox::map(LOCATE_DATA_PATH, "/world/sandbox-only")).trimmed(), QString("sandbox/sandbox-only")); } diff --git a/tests/ut_ssucli/ssuclitest.cpp b/tests/ut_ssucli/ssuclitest.cpp index 3c8ec3f..4544cd8 100644 --- a/tests/ut_ssucli/ssuclitest.cpp +++ b/tests/ut_ssucli/ssuclitest.cpp @@ -20,12 +20,16 @@ typedef QStringList Args; // improve readability void SsuCliTest::init(){ Q_ASSERT(m_sandbox == 0); - m_sandbox = new Sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + m_sandbox = new Sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ChildProcesses); if (!m_sandbox->activate()){ QFAIL("Failed to activate sandbox"); } - setenv("LD_PRELOAD", qPrintable(QString("%1/libsandboxhook.so").arg(TESTS_PATH)), 1); + if (getenv("SSU_SANDBOX_PATH")){ + qDebug() << "Using in-tree sandbox"; + setenv("LD_PRELOAD", getenv("SSU_SANDBOX_PATH"), 1); + } else + setenv("LD_PRELOAD", qPrintable(QString("%1/libsandboxhook.so").arg(TESTS_PATH)), 1); m_bus = new QProcess(this); m_bus->start("dbus-daemon", diff --git a/tests/ut_ssuurlresolver/ssuurlresolvertest.cpp b/tests/ut_ssuurlresolver/ssuurlresolvertest.cpp index c6c5054..369b542 100644 --- a/tests/ut_ssuurlresolver/ssuurlresolvertest.cpp +++ b/tests/ut_ssuurlresolver/ssuurlresolvertest.cpp @@ -22,12 +22,16 @@ */ void SsuUrlResolverTest::initTestCase(){ - m_sandbox = new Sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + m_sandbox = new Sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseDirectly, Sandbox::ChildProcesses); if (!m_sandbox->activate()){ QFAIL("Failed to activate sandbox"); } - setenv("LD_PRELOAD", qPrintable(QString("%1/libsandboxhook.so").arg(TESTS_PATH)), 1); + if (getenv("SSU_SANDBOX_PATH")){ + qDebug() << "Using in-tree sandbox"; + setenv("LD_PRELOAD", getenv("SSU_SANDBOX_PATH"), 1); + } else + setenv("LD_PRELOAD", qPrintable(QString("%1/libsandboxhook.so").arg(TESTS_PATH)), 1); } void SsuUrlResolverTest::cleanupTestCase(){ diff --git a/tests/ut_urlresolver/main.cpp b/tests/ut_urlresolver/main.cpp index 1873572..147d8f4 100644 --- a/tests/ut_urlresolver/main.cpp +++ b/tests/ut_urlresolver/main.cpp @@ -11,7 +11,7 @@ #include "urlresolvertest.cpp" int main(int argc, char **argv){ - Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + Sandbox sandbox(QString("%1/configroot").arg(LOCATE_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ThisProcess); if (!sandbox.activate()){ qFatal("Failed to activate sandbox"); diff --git a/tests/ut_urlresolver/urlresolvertest.cpp b/tests/ut_urlresolver/urlresolvertest.cpp index 7e48d2a..1fcb53f 100644 --- a/tests/ut_urlresolver/urlresolvertest.cpp +++ b/tests/ut_urlresolver/urlresolvertest.cpp @@ -142,7 +142,7 @@ void UrlResolverTest::checkRegisterDevice(){ QVERIFY2(!ssu.registerDevice(&doc), "Ssu::registerDevice() should fail when 'certificate' is empty"); - QFile certificateFile(TESTS_DATA_PATH "/mycert.crt"); + QFile certificateFile(QString("%1/mycert.crt").arg(LOCATE_DATA_PATH)); QVERIFY(certificateFile.open(QIODevice::ReadOnly)); certificate.appendChild(doc.createTextNode(certificateFile.readAll())); @@ -153,7 +153,7 @@ void UrlResolverTest::checkRegisterDevice(){ QVERIFY2(!ssu.registerDevice(&doc), "Ssu::registerDevice() should fail when 'privateKey' is empty"); - QFile privateKeyFile(TESTS_DATA_PATH "/mykey.key"); + QFile privateKeyFile(QString("%1/mykey.key").arg(LOCATE_DATA_PATH)); QVERIFY(privateKeyFile.open(QIODevice::ReadOnly)); privateKey.appendChild(doc.createTextNode(privateKeyFile.readAll()));