a7b2f14074
We always want to have some default name so we can log something relevant. Having two constructors isn't very helpful, especially because we must initialize all members in only one initialization list (since we call the default-ctor from the overloaded one). Having a single constructor with a default parameter is one of few cases where default parameters are justified. Change-Id: Ia2d390be46ea7ad5486248d7ede7a7c95c4352e3 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
242 lines
6.1 KiB
C++
242 lines
6.1 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <iostream>
|
|
#include "Unit.hpp"
|
|
|
|
#include <cassert>
|
|
#include <dlfcn.h>
|
|
#include <fstream>
|
|
#include <sysexits.h>
|
|
#include <thread>
|
|
|
|
#include <Poco/Util/LayeredConfiguration.h>
|
|
|
|
#include "Log.hpp"
|
|
#include "Util.hpp"
|
|
|
|
#include <common/SigUtil.hpp>
|
|
|
|
UnitBase *UnitBase::Global = nullptr;
|
|
char * UnitBase::UnitLibPath;
|
|
static std::thread TimeoutThread;
|
|
static std::atomic<bool> TimeoutThreadRunning(false);
|
|
std::timed_mutex TimeoutThreadMutex;
|
|
|
|
UnitBase *UnitBase::linkAndCreateUnit(UnitType type, const std::string &unitLibPath)
|
|
{
|
|
#if !MOBILEAPP
|
|
void *dlHandle = dlopen(unitLibPath.c_str(), RTLD_GLOBAL|RTLD_NOW);
|
|
if (!dlHandle)
|
|
{
|
|
LOG_ERR("Failed to load " << unitLibPath << ": " << dlerror());
|
|
return nullptr;
|
|
}
|
|
|
|
// avoid std:string de-allocation during failure / exit.
|
|
UnitLibPath = strdup(unitLibPath.c_str());
|
|
|
|
const char *symbol = nullptr;
|
|
switch (type)
|
|
{
|
|
case UnitType::Wsd:
|
|
symbol = "unit_create_wsd";
|
|
break;
|
|
case UnitType::Kit:
|
|
symbol = "unit_create_kit";
|
|
break;
|
|
}
|
|
CreateUnitHooksFunction* createHooks;
|
|
createHooks = reinterpret_cast<CreateUnitHooksFunction *>(dlsym(dlHandle, symbol));
|
|
if (!createHooks)
|
|
{
|
|
LOG_ERR("No " << symbol << " symbol in " << unitLibPath);
|
|
return nullptr;
|
|
}
|
|
UnitBase *hooks = createHooks();
|
|
|
|
if (hooks)
|
|
hooks->setHandle(dlHandle);
|
|
|
|
return hooks;
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
bool UnitBase::init(UnitType type, const std::string &unitLibPath)
|
|
{
|
|
#if !MOBILEAPP
|
|
assert(!Global);
|
|
#else
|
|
// The LOOLWSD initialization is called in a loop on mobile, allow reuse
|
|
if (Global)
|
|
return true;
|
|
#endif
|
|
|
|
if (!unitLibPath.empty())
|
|
{
|
|
Global = linkAndCreateUnit(type, unitLibPath);
|
|
LOG_DBG(Global->_testname << ": Initializing");
|
|
if (Global && type == UnitType::Kit)
|
|
{
|
|
TimeoutThreadMutex.lock();
|
|
TimeoutThread = std::thread([]{
|
|
TimeoutThreadRunning = true;
|
|
Util::setThreadName("unit timeout");
|
|
|
|
if (TimeoutThreadMutex.try_lock_for(Global->_timeoutMilliSeconds))
|
|
{
|
|
LOG_DBG(Global->_testname << ": Unit test finished in time");
|
|
TimeoutThreadMutex.unlock();
|
|
}
|
|
else
|
|
{
|
|
LOG_ERR(Global->_testname << ": Unit test timeout after "
|
|
<< Global->_timeoutMilliSeconds);
|
|
Global->timeout();
|
|
}
|
|
TimeoutThreadRunning = false;
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (type)
|
|
{
|
|
case UnitType::Wsd:
|
|
Global = new UnitWSD();
|
|
break;
|
|
case UnitType::Kit:
|
|
Global = new UnitKit();
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Global)
|
|
Global->_type = type;
|
|
|
|
return Global != nullptr;
|
|
}
|
|
|
|
bool UnitBase::isUnitTesting()
|
|
{
|
|
return Global && Global->_dlHandle;
|
|
}
|
|
|
|
void UnitBase::setTimeout(std::chrono::milliseconds timeoutMilliSeconds)
|
|
{
|
|
assert(!TimeoutThreadRunning);
|
|
_timeoutMilliSeconds = timeoutMilliSeconds;
|
|
LOG_TST(getTestname() << ": setTimeout: " << _timeoutMilliSeconds);
|
|
}
|
|
|
|
UnitBase::~UnitBase()
|
|
{
|
|
// FIXME: we should really clean-up properly.
|
|
// if (_dlHandle)
|
|
// dlclose(_dlHandle);
|
|
_dlHandle = nullptr;
|
|
}
|
|
|
|
UnitWSD::UnitWSD(std::string testname)
|
|
: UnitBase(std::move(testname))
|
|
, _socketPoll(getTestname())
|
|
, _hasKitHooks(false)
|
|
{
|
|
_socketPoll.startThread();
|
|
}
|
|
|
|
UnitWSD::~UnitWSD()
|
|
{
|
|
_socketPoll.joinThread();
|
|
}
|
|
|
|
void UnitWSD::configure(Poco::Util::LayeredConfiguration &config)
|
|
{
|
|
if (isUnitTesting())
|
|
{
|
|
// Force HTTP - helps stracing.
|
|
config.setBool("ssl.enable", false);
|
|
// Use http:// everywhere.
|
|
config.setBool("ssl.termination", false);
|
|
// Force console output - easier to debug.
|
|
config.setBool("logging.file[@enable]", false);
|
|
}
|
|
}
|
|
|
|
void UnitWSD::lookupTile(int part, int width, int height, int tilePosX, int tilePosY,
|
|
int tileWidth, int tileHeight,
|
|
std::shared_ptr<std::vector<char>> &tile)
|
|
{
|
|
if (tile)
|
|
onTileCacheHit(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
|
|
else
|
|
onTileCacheMiss(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
|
|
}
|
|
|
|
UnitKit::UnitKit()
|
|
{
|
|
}
|
|
|
|
UnitKit::~UnitKit()
|
|
{
|
|
}
|
|
|
|
void UnitBase::exitTest(TestResult result)
|
|
{
|
|
if (_setRetValue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (result == TestResult::Ok)
|
|
LOG_INF(getTestname() << ": SUCCESS: exitTest: " << testResultAsString(result)
|
|
<< ". Flagging to shutdown.");
|
|
else
|
|
LOG_ERR(getTestname() << ": FAILURE: exitTest: " << testResultAsString(result)
|
|
<< ". Flagging to shutdown.");
|
|
|
|
_setRetValue = true;
|
|
_retValue = result == TestResult::Ok ? EX_OK : EX_SOFTWARE;
|
|
#if !MOBILEAPP
|
|
SigUtil::requestShutdown(); // And wakupWorld.
|
|
#else
|
|
SocketPoll::wakeupWorld();
|
|
#endif
|
|
}
|
|
|
|
void UnitBase::timeout()
|
|
{
|
|
// Don't timeout if we had already finished.
|
|
if (isUnitTesting() && !_setRetValue)
|
|
{
|
|
LOG_ERR(getTestname() << ": Timed out waiting for unit test to complete");
|
|
exitTest(TestResult::TimedOut);
|
|
}
|
|
}
|
|
|
|
void UnitBase::returnValue(int &retValue)
|
|
{
|
|
if (_setRetValue)
|
|
retValue = _retValue;
|
|
|
|
// tell the timeout thread that the work has finished
|
|
TimeoutThreadMutex.unlock();
|
|
if (TimeoutThread.joinable())
|
|
TimeoutThread.join();
|
|
|
|
delete Global;
|
|
Global = nullptr;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|