From 40b8713ba6d8eabc70fe2b3e90e3ca5c8804305a Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 1 Apr 2017 16:56:36 +0200 Subject: [PATCH] Move test helper to separate library Allows to share common test helper code between tests for different components --- CMakeLists.txt | 1 + connector/CMakeLists.txt | 6 +- connector/tests/connectiontests.cpp | 72 +++------------------- connector/tests/misctests.cpp | 3 +- testhelper/CMakeLists.txt | 55 +++++++++++++++++ testhelper/global.h | 27 +++++++++ {connector/tests => testhelper}/helper.h | 6 +- testhelper/syncthingtestinstance.cpp | 77 ++++++++++++++++++++++++ testhelper/syncthingtestinstance.h | 60 ++++++++++++++++++ 9 files changed, 240 insertions(+), 67 deletions(-) create mode 100644 testhelper/CMakeLists.txt create mode 100644 testhelper/global.h rename {connector/tests => testhelper}/helper.h (98%) create mode 100644 testhelper/syncthingtestinstance.cpp create mode 100644 testhelper/syncthingtestinstance.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 70c7c7e..9907348 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ option(NO_MODEL "specifies whether building models should be skipped, implies NO # add subdirectories enable_testing() +add_subdirectory(testhelper) add_subdirectory(connector) link_directories(${LIB_SYNCTHING_CONNECTOR_BINARY_DIR}) if(NOT NO_CLI) diff --git a/connector/CMakeLists.txt b/connector/CMakeLists.txt index 79f3c8c..cf42c91 100644 --- a/connector/CMakeLists.txt +++ b/connector/CMakeLists.txt @@ -31,7 +31,6 @@ set(SRC_FILES ) set(TEST_HEADER_FILES - tests/helper.h ) set(TEST_SRC_FILES tests/cppunit.cpp @@ -55,6 +54,11 @@ find_package(qtutilities 5.0.0 REQUIRED) include_directories(BEFORE SYSTEM ${QT_UTILITIES_INCLUDE_DIRS}) list(APPEND CMAKE_MODULE_PATH ${QT_UTILITIES_MODULE_DIRS}) +# find test helper +find_package(syncthingtesthelper ${META_APP_VERSION} REQUIRED) +include_directories(BEFORE SYSTEM ${SYNCTHINGTESTHELPER_INCLUDE_DIRS}) +list(APPEND TEST_LIBRARIES ${SYNCTHINGTESTHELPER_LIB}) + # link also explicitely against the following Qt 5 modules list(APPEND ADDITIONAL_QT_MODULES Network) diff --git a/connector/tests/connectiontests.cpp b/connector/tests/connectiontests.cpp index 77a4138..534b8de 100644 --- a/connector/tests/connectiontests.cpp +++ b/connector/tests/connectiontests.cpp @@ -1,13 +1,12 @@ -#include "./helper.h" #include "../syncthingconnection.h" +#include "../testhelper/helper.h" +#include "../testhelper/syncthingtestinstance.h" + #include #include -#include -#include -#include #include #include @@ -20,7 +19,7 @@ using namespace CPPUNIT_NS; /*! * \brief The ConnectionTests class tests the SyncthingConnector. */ -class ConnectionTests : public TestFixture +class ConnectionTests : public TestFixture, private SyncthingTestInstance { CPPUNIT_TEST_SUITE(ConnectionTests); CPPUNIT_TEST(testConnection); @@ -44,20 +43,12 @@ private: template QMetaObject::Connection handleNewDirs(Handler handler, bool *ok); - QString m_apiKey; - QCoreApplication m_app; - QProcess m_syncthingProcess; SyncthingConnection m_connection; }; CPPUNIT_TEST_SUITE_REGISTRATION(ConnectionTests); -static int dummy1 = 0; -static char *dummy2; - -ConnectionTests::ConnectionTests() : - m_apiKey(QStringLiteral("syncthingconnectortest")), - m_app(dummy1, &dummy2) +ConnectionTests::ConnectionTests() {} // @@ -69,44 +60,10 @@ ConnectionTests::ConnectionTests() : */ void ConnectionTests::setUp() { - cerr << "\n - Launching Syncthing and setup connection ..." << endl; + SyncthingTestInstance::start(); - // setup st config - const string configFilePath = workingCopyPath("testconfig/config.xml"); - if(configFilePath.empty()) { - throw runtime_error("Unable to setup Syncthing config directory."); - } - const QFileInfo configFile(QString::fromLocal8Bit(configFilePath.data())); - // clean config dir - const QDir configDir(configFile.dir()); - for(QFileInfo &configEntry : configDir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)) { - if(configEntry.isDir()) { - QDir(configEntry.absoluteFilePath()).removeRecursively(); - } else if(configEntry.fileName() != QStringLiteral("config.xml")) { - QFile::remove(configEntry.absoluteFilePath()); - } - } - - // determine st path - const QByteArray syncthingPathFromEnv(qgetenv("SYNCTHING_PATH")); - const QString syncthingPath(syncthingPathFromEnv.isEmpty() ? QStringLiteral("syncthing") : QString::fromLocal8Bit(syncthingPathFromEnv)); - - // determine st port - const int syncthingPortFromEnv(qEnvironmentVariableIntValue("SYNCTHING_PORT")); - const QString syncthingPort(!syncthingPortFromEnv ? QStringLiteral("4001") : QString::number(syncthingPortFromEnv)); - - // start st - QStringList args; - args.reserve(2); - args << QStringLiteral("-gui-address=http://localhost:") + syncthingPort; - args << QStringLiteral("-gui-apikey=") + m_apiKey; - args << QStringLiteral("-home=") + configFile.absolutePath(); - args << QStringLiteral("-no-browser"); - args << QStringLiteral("-verbose"); - m_syncthingProcess.start(syncthingPath, args); - - // setup connection - m_connection.setSyncthingUrl(QStringLiteral("http://localhost:") + syncthingPort); + cerr << "\n - Preparing connection ..." << endl; + m_connection.setSyncthingUrl(QStringLiteral("http://localhost:") + syncthingPort()); // keep track of status changes QObject::connect(&m_connection, &SyncthingConnection::statusChanged, [this] { @@ -119,16 +76,7 @@ void ConnectionTests::setUp() */ void ConnectionTests::tearDown() { - if(m_syncthingProcess.state() == QProcess::Running) { - cerr << "\n - Waiting for Syncthing to terminate ..." << endl; - m_syncthingProcess.terminate(); - m_syncthingProcess.waitForFinished(); - } - if(m_syncthingProcess.isOpen()) { - cerr << "\n - Syncthing terminated with exit code " << m_syncthingProcess.exitCode() << ".\n"; - cerr << "\n - Syncthing stdout during the testrun:\n" << m_syncthingProcess.readAllStandardOutput().data(); - cerr << "\n - Syncthing stderr during the testrun:\n" << m_syncthingProcess.readAllStandardError().data(); - } + SyncthingTestInstance::stop(); } // @@ -209,7 +157,7 @@ void ConnectionTests::testConnection() } // initial connection - m_connection.setApiKey(m_apiKey.toUtf8()); + m_connection.setApiKey(apiKey().toUtf8()); waitForConnection(&SyncthingConnection::statusChanged, static_cast(&SyncthingConnection::connect)); CPPUNIT_ASSERT_EQUAL_MESSAGE("connected and paused (one dev is initially paused)", QStringLiteral("connected, paused"), m_connection.statusText()); diff --git a/connector/tests/misctests.cpp b/connector/tests/misctests.cpp index 95a0107..0c45251 100644 --- a/connector/tests/misctests.cpp +++ b/connector/tests/misctests.cpp @@ -1,7 +1,8 @@ -#include "./helper.h" #include "../syncthingconfig.h" #include "../utils.h" +#include "../testhelper/helper.h" + #include #include #include diff --git a/testhelper/CMakeLists.txt b/testhelper/CMakeLists.txt new file mode 100644 index 0000000..cf05142 --- /dev/null +++ b/testhelper/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) + +# metadata +set(META_PROJECT_NAME syncthingtesthelper) +set(META_PROJECT_TYPE library) +set(META_APP_NAME "Syncthing Tray Test Helper") +set(META_APP_DESCRIPTION "Helper for testing compontents of Syncthing Tray") +set(META_PUBLIC_QT_MODULES Core) +set(META_NO_INSTALL_TARGETS ON) + +# add project files +set(HEADER_FILES + helper.h + syncthingtestinstance.h +) +set(SRC_FILES + syncthingtestinstance.cpp +) + +set(TEST_HEADER_FILES +) +set(TEST_SRC_FILES +) + +set(TS_FILES +) + +# find c++utilities +find_package(c++utilities 4.0.0 REQUIRED) +use_cpp_utilities() +set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities) +set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static) + +# find qtutilities (only headers and CMake modules used) +find_package(qtutilities 5.0.0 REQUIRED) +include_directories(BEFORE SYSTEM ${QT_UTILITIES_INCLUDE_DIRS}) +list(APPEND CMAKE_MODULE_PATH ${QT_UTILITIES_MODULE_DIRS}) + +# link also explicitely against the following Qt 5 modules +list(APPEND ADDITIONAL_QT_MODULES Network) + +# include modules to apply configuration +include(BasicConfig) +include(QtConfig) +include(WindowsResources) +include(LibraryTarget) +include(Doxygen) +include(ConfigHeader) + +# exclude the targets from 'all' target so it is only built when tests are built +foreach(TESTHELPER_TARGET "${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}" "${TARGET_PREFIX}${META_PROJECT_NAME}${TARGET_SUFFIX}_static") + if(TARGET "${TESTHELPER_TARGET}") + set_target_properties("${TESTHELPER_TARGET}" PROPERTIES EXCLUDE_FROM_ALL ON) + endif() +endforeach() diff --git a/testhelper/global.h b/testhelper/global.h new file mode 100644 index 0000000..3ca9d87 --- /dev/null +++ b/testhelper/global.h @@ -0,0 +1,27 @@ +// Created via CMake from template global.h.in +// WARNING! Any changes to this file will be overwritten by the next CMake run! + +#ifndef SYNCTHINGTESTHELPER_GLOBAL +#define SYNCTHINGTESTHELPER_GLOBAL + +#include + +#ifdef SYNCTHINGTESTHELPER_STATIC +# define SYNCTHINGTESTHELPER_EXPORT +# define SYNCTHINGTESTHELPER_IMPORT +#else +# define SYNCTHINGTESTHELPER_EXPORT LIB_EXPORT +# define SYNCTHINGTESTHELPER_IMPORT LIB_IMPORT +#endif + +/*! + * \def SYNCTHINGTESTHELPER_EXPORT + * \brief Marks the symbol to be exported by the syncthingtesthelper library. + */ + +/*! + * \def SYNCTHINGTESTHELPER_IMPORT + * \brief Marks the symbol to be imported from the syncthingtesthelper library. + */ + +#endif // SYNCTHINGTESTHELPER_GLOBAL diff --git a/connector/tests/helper.h b/testhelper/helper.h similarity index 98% rename from connector/tests/helper.h rename to testhelper/helper.h index 6724acd..e3d168e 100644 --- a/connector/tests/helper.h +++ b/testhelper/helper.h @@ -1,5 +1,5 @@ -#ifndef TESTS_HELPER_H -#define TESTS_HELPER_H +#ifndef SYNCTHINGTESTHELPER_H +#define SYNCTHINGTESTHELPER_H #include @@ -138,4 +138,4 @@ void waitForSignal(typename QtPrivate::FunctionPointer::Object *sender, QObject::disconnect(handlerConnection); } -#endif // TESTS_HELPER_H +#endif // SYNCTHINGTESTHELPER_H diff --git a/testhelper/syncthingtestinstance.cpp b/testhelper/syncthingtestinstance.cpp new file mode 100644 index 0000000..ac865cd --- /dev/null +++ b/testhelper/syncthingtestinstance.cpp @@ -0,0 +1,77 @@ +#include "./syncthingtestinstance.h" +#include "./helper.h" + +#include + +#include +#include + +using namespace std; +using namespace TestUtilities; + +static int dummy1 = 0; +static char *dummy2; + +SyncthingTestInstance::SyncthingTestInstance() : + m_apiKey(QStringLiteral("syncthingtestinstance")), + m_app(dummy1, &dummy2) +{} + +/*! + * \brief Starts the Syncthing test instance. + */ +void SyncthingTestInstance::start() +{ + cerr << "\n - Launching Syncthing ..." << endl; + + // setup st config + const string configFilePath = workingCopyPath("testconfig/config.xml"); + if(configFilePath.empty()) { + throw runtime_error("Unable to setup Syncthing config directory."); + } + const QFileInfo configFile(QString::fromLocal8Bit(configFilePath.data())); + // clean config dir + const QDir configDir(configFile.dir()); + for(QFileInfo &configEntry : configDir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)) { + if(configEntry.isDir()) { + QDir(configEntry.absoluteFilePath()).removeRecursively(); + } else if(configEntry.fileName() != QStringLiteral("config.xml")) { + QFile::remove(configEntry.absoluteFilePath()); + } + } + + // determine st path + const QByteArray syncthingPathFromEnv(qgetenv("SYNCTHING_PATH")); + const QString syncthingPath(syncthingPathFromEnv.isEmpty() ? QStringLiteral("syncthing") : QString::fromLocal8Bit(syncthingPathFromEnv)); + + // determine st port + const int syncthingPortFromEnv(qEnvironmentVariableIntValue("SYNCTHING_PORT")); + m_syncthingPort = !syncthingPortFromEnv ? QStringLiteral("4001") : QString::number(syncthingPortFromEnv); + + // start st + QStringList args; + args.reserve(2); + args << QStringLiteral("-gui-address=http://localhost:") + m_syncthingPort; + args << QStringLiteral("-gui-apikey=") + m_apiKey; + args << QStringLiteral("-home=") + configFile.absolutePath(); + args << QStringLiteral("-no-browser"); + args << QStringLiteral("-verbose"); + m_syncthingProcess.start(syncthingPath, args); +} + +/*! + * \brief Terminates Syncthing and prints stdout/stderr from Syncthing. + */ +void SyncthingTestInstance::stop() +{ + if(m_syncthingProcess.state() == QProcess::Running) { + cerr << "\n - Waiting for Syncthing to terminate ..." << endl; + m_syncthingProcess.terminate(); + m_syncthingProcess.waitForFinished(); + } + if(m_syncthingProcess.isOpen()) { + cerr << "\n - Syncthing terminated with exit code " << m_syncthingProcess.exitCode() << ".\n"; + cerr << "\n - Syncthing stdout during the testrun:\n" << m_syncthingProcess.readAllStandardOutput().data(); + cerr << "\n - Syncthing stderr during the testrun:\n" << m_syncthingProcess.readAllStandardError().data(); + } +} diff --git a/testhelper/syncthingtestinstance.h b/testhelper/syncthingtestinstance.h new file mode 100644 index 0000000..cce9818 --- /dev/null +++ b/testhelper/syncthingtestinstance.h @@ -0,0 +1,60 @@ +#ifndef SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H +#define SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H + +#include "./global.h" +#include "./helper.h" + +#include +#include + +using namespace std; + +/*! + * \brief The SyncthingTestInstance class provides running a test instance of Syncthing. + * + * The class is meant to be subclassed by tests requiring a running Syncthing instance. + */ +class SYNCTHINGTESTHELPER_EXPORT SyncthingTestInstance +{ +public: + SyncthingTestInstance(); + + const QString &apiKey() const; + const QString &syncthingPort() const; + +public Q_SLOTS: + void start(); + void stop(); + +protected: + QCoreApplication &application(); + QProcess &syncthingProcess(); + +private: + QString m_apiKey; + QString m_syncthingPort; + QCoreApplication m_app; + QProcess m_syncthingProcess; +}; + +inline const QString &SyncthingTestInstance::apiKey() const +{ + return m_apiKey; +} + +inline const QString &SyncthingTestInstance::syncthingPort() const +{ + return m_syncthingPort; +} + +inline QCoreApplication &SyncthingTestInstance::application() +{ + return m_app; +} + +inline QProcess &SyncthingTestInstance::syncthingProcess() +{ + return m_syncthingProcess; +} + +#endif // SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H