Move test helper to separate library

Allows to share common test helper code
between tests for different components
This commit is contained in:
Martchus 2017-04-01 16:56:36 +02:00
parent 9b70b81ae9
commit 40b8713ba6
9 changed files with 240 additions and 67 deletions

View File

@ -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)

View File

@ -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)

View File

@ -1,13 +1,12 @@
#include "./helper.h"
#include "../syncthingconnection.h"
#include "../testhelper/helper.h"
#include "../testhelper/syncthingtestinstance.h"
#include <c++utilities/tests/testutils.h>
#include <cppunit/TestFixture.h>
#include <QCoreApplication>
#include <QProcess>
#include <QFileInfo>
#include <QDir>
#include <QStringBuilder>
@ -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<typename Handler>
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<void(SyncthingConnection::*)(void)>(&SyncthingConnection::connect));
CPPUNIT_ASSERT_EQUAL_MESSAGE("connected and paused (one dev is initially paused)", QStringLiteral("connected, paused"), m_connection.statusText());

View File

@ -1,7 +1,8 @@
#include "./helper.h"
#include "../syncthingconfig.h"
#include "../utils.h"
#include "../testhelper/helper.h"
#include <c++utilities/tests/testutils.h>
#include <c++utilities/chrono/datetime.h>
#include <c++utilities/chrono/timespan.h>

55
testhelper/CMakeLists.txt Normal file
View File

@ -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()

27
testhelper/global.h Normal file
View File

@ -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 <c++utilities/application/global.h>
#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

View File

@ -1,5 +1,5 @@
#ifndef TESTS_HELPER_H
#define TESTS_HELPER_H
#ifndef SYNCTHINGTESTHELPER_H
#define SYNCTHINGTESTHELPER_H
#include <c++utilities/conversion/stringbuilder.h>
@ -138,4 +138,4 @@ void waitForSignal(typename QtPrivate::FunctionPointer<Signal>::Object *sender,
QObject::disconnect(handlerConnection);
}
#endif // TESTS_HELPER_H
#endif // SYNCTHINGTESTHELPER_H

View File

@ -0,0 +1,77 @@
#include "./syncthingtestinstance.h"
#include "./helper.h"
#include <c++utilities/tests/testutils.h>
#include <QFileInfo>
#include <QDir>
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();
}
}

View File

@ -0,0 +1,60 @@
#ifndef SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H
#define SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H
#include "./global.h"
#include "./helper.h"
#include <QCoreApplication>
#include <QProcess>
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