AusweisApp2/test/helper/PersoSimController.cpp

180 lines
3.3 KiB
C++

/*!
* PersoSimController.cpp
*
* \copyright Copyright (c) 2014 Governikus GmbH & Co. KG
*/
#include "PersoSimController.h"
#include <signal.h>
#include <QEventLoop>
#include "testMacros.h"
using governikus::PersoSimController;
static const char* const sPersoSimPrompt = "PersoSim commandline: ";
PersoSimController* PersoSimController::sActiveController = nullptr;
bool PersoSimController::sAbortSignalHandlerInstalled = false;
// We very much want to clean up the active PersoSimController -- since
// otherwise the PersoSim process keeps running -- so we use a global
// destructor to destroy it.
struct CleanupHelper
{
~CleanupHelper()
{
PersoSimController::cleanUpActiveController();
}
};
static CleanupHelper sCleanupHelper;
PersoSimController::PersoSimController()
: QObject()
, mProcess(nullptr)
, mEventLoop(nullptr)
{
}
PersoSimController::~PersoSimController()
{
if (sActiveController == this)
{
sActiveController = nullptr;
}
if (mProcess != nullptr)
{
QCOMPARE(mProcess->write("exit\n"), 5);
mProcess->waitForFinished(-1);
}
}
bool PersoSimController::init()
{
#ifdef PERSOSIM_TESTS_ENABLED
return startProcess();
#else
XSKIP("PersoSim tests not enabled", false);
#endif
}
void PersoSimController::cleanUpActiveController()
{
delete sActiveController;
sActiveController = nullptr;
}
bool PersoSimController::startProcess()
{
XVERIFY(mProcess == nullptr, false);
XVERIFY(sActiveController == nullptr, false);
mProcess = new QProcess;
mProcess->setProgram(JAVA_EXECUTABLE);
mProcess->setArguments(QStringList() << "-jar" << PERSOSIM_EXECUTABLE << "--consoleOnly");
mProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel);
connect(mProcess, &QProcess::readyRead, this, &PersoSimController::inputAvailable);
connect(mProcess, QOverload<int>::of(&QProcess::finished), this, &PersoSimController::processFinished);
mProcess->start();
XVERIFY(mProcess->waitForStarted(-1), false);
XCOMPARE(mProcess->state(), QProcess::Running, false);
sActiveController = this;
installAbortSignalHandler();
// wait for PersoSim command line prompt
QEventLoop eventLoop;
mEventLoop = &eventLoop;
try
{
int result = eventLoop.exec();
mEventLoop = nullptr;
XCOMPARE(result, 0, false);
}
catch (...)
{
mEventLoop = nullptr;
throw;
}
return true;
}
void PersoSimController::inputAvailable()
{
QByteArray line = mProcess->readLine();
if (line.isEmpty())
{
return;
}
if (line.endsWith('\n'))
{
line.truncate(line.length() - 1);
}
if (line == sPersoSimPrompt)
{
if (mEventLoop != nullptr)
{
mEventLoop->exit(0);
}
}
qDebug("PersoSim: %s", line.data());
}
void PersoSimController::processFinished(int /*pExitCode*/)
{
if (mEventLoop != nullptr)
{
mEventLoop->exit(1);
}
if (sActiveController == this)
{
sActiveController = nullptr;
}
}
void PersoSimController::installAbortSignalHandler()
{
// We very much want to clean up the active PersoSimController -- since
// otherwise the PersoSim process keeps running -- so we install a SIGABRT
// signal handler for the case that something misbehaves (triggering an
// assert or throwing an uncaught exception) and abort() is called.
if (!sAbortSignalHandlerInstalled)
{
signal(SIGABRT, &abortSignalHandler);
sAbortSignalHandlerInstalled = true;
}
}
void PersoSimController::abortSignalHandler(int /*pSignal*/)
{
cleanUpActiveController();
}