2016-04-05 11:41:10 -05:00
|
|
|
/* -*- 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/.
|
|
|
|
*/
|
|
|
|
|
2017-12-20 07:06:26 -06:00
|
|
|
#include <config.h>
|
2017-03-08 10:38:22 -06:00
|
|
|
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include "Unit.hpp"
|
|
|
|
|
2022-02-15 16:45:01 -06:00
|
|
|
#include <iostream>
|
2016-04-05 11:41:10 -05:00
|
|
|
#include <cassert>
|
2023-06-10 06:28:25 -05:00
|
|
|
#include <condition_variable>
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include <dlfcn.h>
|
2016-05-01 09:24:31 -05:00
|
|
|
#include <fstream>
|
wsd: test: fix rare deadlock on stopping
Since UnitBase (and children) are invoked from
different threads, UnitBase::exitTest could
have a race. This ultimately results in
invoking std::thread::join() concurrently,
which is unsafe. This can result in the
following deadlock.
In this case websrv_poll had invoked
UnitBase::exitTest concurrently and
evidently finished, leaving the main
coolwsd thread deadlocked.
(gdb) info thread
Id Target Id Frame
* 1 Thread 0x7f67528f0840 (LWP 4058508) "coolwsd" __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=4058510, futex_word=0x7f675285c910)
at ./nptl/futex-internal.c:57
(gdb) t a a bt
Thread 1 (Thread 0x7f67528f0840 (LWP 4058508) "coolwsd"):
#0 __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=4058510, futex_word=0x7f675285c910) at ./nptl/futex-internal.c:57
#1 __futex_abstimed_wait_common (cancel=true, private=128, abstime=0x0, clockid=0, expected=4058510, futex_word=0x7f675285c910) at ./nptl/futex-internal.c:87
#2 __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x7f675285c910, expected=4058510, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=128) at ./nptl/futex-internal.c:139
#3 0x00007f67529cd6a4 in __pthread_clockjoin_ex (threadid=140081742857792, thread_return=0x0, clockid=0, abstime=0x0, block=<optimized out>) at ./nptl/pthread_join_common.c:105
#4 0x00007f6752d42337 in std::thread::join() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x000055775c5fa8e0 in SocketPoll::joinThread (this=0x55775cc9b090) at net/Socket.cpp:282
#6 0x000055775c5c8121 in UnitBase::endTest (this=this@entry=0x55775cc0fe80, reason="") at common/Unit.cpp:545
#7 0x00007f67528df61f in UnitWSDClient::endTest (this=0x55775cc0fe80, reason="") at ./UnitWSDClient.hpp:118
#8 0x000055775c5cc4d1 in UnitBase::exitTest (this=0x55775cc0fe80, result=result@entry=UnitBase::TestResult::Ok, reason="") at common/Unit.cpp:486
#9 0x00007f67528d1fa3 in UnitWOPIFileUrl::invokeWSDTest (this=0x55775cc0fe80) at UnitWOPIFileUrl.cpp:269
#10 0x000055775c4accdb in UnitWSD::invokeTest (this=0x55775cc0fe80) at ./common/Unit.hpp:318
#11 0x000055775c4a38cd in COOLWSD::innerMain (this=0x7ffd34248650) at wsd/COOLWSD.cpp:5459
#12 0x000055775c4a59db in COOLWSD::main (this=<optimized out>) at wsd/COOLWSD.cpp:5706
#13 0x00007f6753ab0877 in Poco::Util::Application::run() () from /lib/libPocoUtil.so.80
#14 0x000055775c48316c in main (argc=14, argv=0x7ffd34248898) at wsd/COOLWSD.cpp:5845
Change-Id: If6162690462719f14a35241604f8a59b38a806c0
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-11-29 03:57:37 -06:00
|
|
|
#include <mutex>
|
2022-02-15 16:45:01 -06:00
|
|
|
#include <sstream>
|
2019-11-06 03:07:32 -06:00
|
|
|
#include <sysexits.h>
|
2019-11-06 07:03:53 -06:00
|
|
|
#include <thread>
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2022-05-03 06:50:24 -05:00
|
|
|
#include <Poco/JSON/Object.h>
|
|
|
|
#include <Poco/JSON/Parser.h>
|
2019-11-06 03:07:32 -06:00
|
|
|
#include <Poco/Util/LayeredConfiguration.h>
|
2022-11-17 18:26:09 -06:00
|
|
|
#include <Poco/Util/Application.h>
|
2016-04-06 13:50:55 -05:00
|
|
|
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include "Log.hpp"
|
|
|
|
#include "Util.hpp"
|
2022-12-24 23:03:25 -06:00
|
|
|
#include <test/testlog.hpp>
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
|
2017-12-20 07:06:26 -06:00
|
|
|
#include <common/SigUtil.hpp>
|
2022-12-10 12:13:22 -06:00
|
|
|
#include <common/StringVector.hpp>
|
2022-06-18 09:32:49 -05:00
|
|
|
#include <common/Message.hpp>
|
2023-06-04 15:56:55 -05:00
|
|
|
#include <unistd.h>
|
2016-11-14 07:58:04 -06:00
|
|
|
|
2021-09-14 10:05:31 -05:00
|
|
|
UnitKit *GlobalKit = nullptr;
|
|
|
|
UnitWSD *GlobalWSD = nullptr;
|
2021-09-28 04:21:45 -05:00
|
|
|
UnitTool *GlobalTool = nullptr;
|
2022-11-09 06:41:27 -06:00
|
|
|
UnitBase** UnitBase::GlobalArray = nullptr;
|
|
|
|
int UnitBase::GlobalIndex = -1;
|
2022-11-12 17:32:48 -06:00
|
|
|
char* UnitBase::UnitLibPath = nullptr;
|
2022-11-09 06:53:17 -06:00
|
|
|
void* UnitBase::DlHandle = nullptr;
|
2022-12-10 12:13:22 -06:00
|
|
|
UnitBase::TestOptions UnitBase::GlobalTestOptions;
|
2022-11-10 06:47:57 -06:00
|
|
|
UnitBase::TestResult UnitBase::GlobalResult = UnitBase::TestResult::Ok;
|
2023-06-10 06:28:25 -05:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
std::thread TimeoutThread;
|
|
|
|
std::mutex TimeoutThreadMutex;
|
|
|
|
std::condition_variable TimeoutConditionVariable;
|
|
|
|
|
|
|
|
} // namespace
|
2016-04-08 11:36:08 -05:00
|
|
|
|
2022-03-17 07:25:43 -05:00
|
|
|
/// Controls whether experimental features/behavior is enabled or not.
|
|
|
|
bool EnableExperimental = false;
|
|
|
|
|
2022-11-09 06:41:27 -06:00
|
|
|
UnitBase** UnitBase::linkAndCreateUnit(UnitType type, const std::string& unitLibPath)
|
2016-04-05 11:41:10 -05:00
|
|
|
{
|
2019-02-12 05:16:40 -06:00
|
|
|
#if !MOBILEAPP
|
2022-11-09 06:53:17 -06:00
|
|
|
DlHandle = dlopen(unitLibPath.c_str(), RTLD_GLOBAL|RTLD_NOW);
|
|
|
|
if (!DlHandle)
|
2016-04-05 11:41:10 -05:00
|
|
|
{
|
2023-09-23 09:23:37 -05:00
|
|
|
LOG_ERR("Failed to load unit-test lib " << dlerror());
|
2016-12-22 08:04:07 -06:00
|
|
|
return nullptr;
|
2016-04-05 11:41:10 -05:00
|
|
|
}
|
|
|
|
|
2020-01-17 14:49:38 -06:00
|
|
|
// avoid std:string de-allocation during failure / exit.
|
|
|
|
UnitLibPath = strdup(unitLibPath.c_str());
|
|
|
|
|
2016-12-22 08:04:07 -06:00
|
|
|
const char *symbol = nullptr;
|
2016-04-09 11:30:48 -05:00
|
|
|
switch (type)
|
|
|
|
{
|
2016-12-22 03:27:30 -06:00
|
|
|
case UnitType::Wsd:
|
2022-11-15 17:25:18 -06:00
|
|
|
{
|
2022-11-12 17:32:48 -06:00
|
|
|
// Try the multi-test version first.
|
2022-11-15 17:25:18 -06:00
|
|
|
CreateUnitHooksFunctionMulti* createHooksMulti =
|
|
|
|
reinterpret_cast<CreateUnitHooksFunctionMulti*>(
|
|
|
|
dlsym(DlHandle, "unit_create_wsd_multi"));
|
|
|
|
if (createHooksMulti)
|
|
|
|
{
|
|
|
|
UnitBase** hooks = createHooksMulti();
|
|
|
|
if (hooks)
|
2022-11-17 18:24:01 -06:00
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << "Loaded UnitTest [" << unitLibPath << "] with: ";
|
|
|
|
for (int i = 0; hooks[i] != nullptr; ++i)
|
|
|
|
{
|
|
|
|
if (i)
|
|
|
|
oss << ", ";
|
|
|
|
oss << hooks[i]->getTestname();
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_INF(oss.str());
|
2022-11-15 17:25:18 -06:00
|
|
|
return hooks;
|
2022-11-17 18:24:01 -06:00
|
|
|
}
|
2022-11-15 17:25:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fallback.
|
2016-04-09 11:30:48 -05:00
|
|
|
symbol = "unit_create_wsd";
|
|
|
|
break;
|
2022-11-15 17:25:18 -06:00
|
|
|
}
|
2016-12-22 03:27:30 -06:00
|
|
|
case UnitType::Kit:
|
2016-04-09 11:30:48 -05:00
|
|
|
symbol = "unit_create_kit";
|
|
|
|
break;
|
2021-08-10 22:41:02 -05:00
|
|
|
case UnitType::Tool:
|
|
|
|
symbol = "unit_create_tool";
|
|
|
|
break;
|
2016-04-09 11:30:48 -05:00
|
|
|
}
|
2022-11-12 17:32:48 -06:00
|
|
|
|
2022-11-12 07:19:42 -06:00
|
|
|
// Internal consistency sanity check.
|
|
|
|
selfTest();
|
|
|
|
|
2022-11-15 17:25:18 -06:00
|
|
|
CreateUnitHooksFunction* createHooks =
|
|
|
|
reinterpret_cast<CreateUnitHooksFunction*>(dlsym(DlHandle, symbol));
|
2022-11-12 17:32:48 -06:00
|
|
|
|
2016-04-05 11:41:10 -05:00
|
|
|
if (!createHooks)
|
|
|
|
{
|
2016-11-06 11:06:21 -06:00
|
|
|
LOG_ERR("No " << symbol << " symbol in " << unitLibPath);
|
2016-12-22 08:04:07 -06:00
|
|
|
return nullptr;
|
2016-04-05 11:41:10 -05:00
|
|
|
}
|
2022-11-15 17:25:18 -06:00
|
|
|
|
2022-11-09 06:41:27 -06:00
|
|
|
UnitBase* hooks = createHooks();
|
2022-11-15 17:25:18 -06:00
|
|
|
if (hooks)
|
2022-11-12 17:32:48 -06:00
|
|
|
return new UnitBase* [2] { hooks, nullptr };
|
2022-11-15 17:25:18 -06:00
|
|
|
|
|
|
|
LOG_ERR("No wsd unit-tests found in " << unitLibPath);
|
2023-02-01 05:30:30 -06:00
|
|
|
#else
|
|
|
|
(void) type;
|
|
|
|
(void) unitLibPath;
|
2022-11-09 06:41:27 -06:00
|
|
|
#endif
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2018-09-13 11:16:00 -05:00
|
|
|
return nullptr;
|
2016-04-05 11:41:10 -05:00
|
|
|
}
|
|
|
|
|
2022-12-10 12:13:22 -06:00
|
|
|
void UnitBase::initTestSuiteOptions()
|
2022-11-17 18:23:36 -06:00
|
|
|
{
|
|
|
|
static const char* TestOptions = getenv("COOL_TEST_OPTIONS");
|
|
|
|
if (TestOptions == nullptr)
|
|
|
|
return;
|
|
|
|
|
2022-12-10 12:13:22 -06:00
|
|
|
StringVector tokens = StringVector::tokenize(std::string(TestOptions), ':');
|
|
|
|
|
|
|
|
for (const auto& token : tokens)
|
|
|
|
{
|
|
|
|
// Expect name=value pairs.
|
|
|
|
const auto pair = Util::split(tokens.getParam(token), '=');
|
|
|
|
|
|
|
|
// If there is no value, assume it's a filter string.
|
|
|
|
if (pair.second.empty())
|
|
|
|
{
|
|
|
|
const std::string filter = Util::toLower(pair.first);
|
|
|
|
LOG_INF("Setting the 'filter' test option to [" << filter << ']');
|
|
|
|
GlobalTestOptions.setFilter(filter);
|
|
|
|
}
|
2022-12-11 07:30:53 -06:00
|
|
|
else if (pair.first == "keepgoing")
|
|
|
|
{
|
|
|
|
const bool keepgoing = pair.second == "1" || pair.second == "true";
|
|
|
|
LOG_INF("Setting the 'keepgoing' test option to " << keepgoing);
|
|
|
|
GlobalTestOptions.setKeepgoing(keepgoing);
|
|
|
|
}
|
2022-12-10 12:13:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnitBase::filter()
|
|
|
|
{
|
|
|
|
const auto& filter = GlobalTestOptions.getFilter();
|
2022-11-18 06:37:04 -06:00
|
|
|
for (; GlobalArray[GlobalIndex] != nullptr; ++GlobalIndex)
|
2022-11-17 18:23:36 -06:00
|
|
|
{
|
|
|
|
const std::string& name = GlobalArray[GlobalIndex]->getTestname();
|
|
|
|
if (strstr(Util::toLower(name).c_str(), filter.c_str()))
|
|
|
|
break;
|
|
|
|
|
2022-12-10 12:13:22 -06:00
|
|
|
LOG_INF("Skipping test [" << name << "] per filter [" << filter << ']');
|
2022-11-17 18:23:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-12 07:19:42 -06:00
|
|
|
void UnitBase::selfTest()
|
|
|
|
{
|
|
|
|
assert(init(UnitType::Wsd, std::string()));
|
|
|
|
assert(!UnitBase::get().isFinished());
|
|
|
|
assert(!UnitWSD::get().isFinished());
|
|
|
|
assert(GlobalArray);
|
|
|
|
assert(GlobalIndex == 0);
|
|
|
|
assert(&UnitBase::get() == GlobalArray[0]);
|
|
|
|
delete GlobalArray[0];
|
|
|
|
delete[] GlobalArray;
|
|
|
|
GlobalArray = nullptr;
|
|
|
|
GlobalIndex = -1;
|
|
|
|
GlobalKit = nullptr;
|
|
|
|
GlobalWSD = nullptr;
|
|
|
|
GlobalTool = nullptr;
|
|
|
|
|
|
|
|
assert(init(UnitType::Kit, std::string()));
|
|
|
|
assert(!UnitBase::get().isFinished());
|
|
|
|
assert(!UnitKit::get().isFinished());
|
|
|
|
assert(GlobalArray);
|
|
|
|
assert(GlobalIndex == 0);
|
|
|
|
assert(&UnitBase::get() == GlobalArray[0]);
|
|
|
|
delete GlobalArray[0];
|
|
|
|
delete[] GlobalArray;
|
|
|
|
GlobalArray = nullptr;
|
|
|
|
GlobalIndex = -1;
|
|
|
|
GlobalKit = nullptr;
|
|
|
|
GlobalWSD = nullptr;
|
|
|
|
GlobalTool = nullptr;
|
|
|
|
}
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
bool UnitBase::init(UnitType type, const std::string &unitLibPath)
|
2016-04-05 11:41:10 -05:00
|
|
|
{
|
2019-02-13 09:37:54 -06:00
|
|
|
#if !MOBILEAPP
|
2022-11-12 07:19:42 -06:00
|
|
|
LOG_ASSERT(!get(type));
|
2019-02-13 09:37:54 -06:00
|
|
|
#else
|
2021-11-18 06:08:14 -06:00
|
|
|
// The COOLWSD initialization is called in a loop on mobile, allow reuse
|
2021-09-16 06:25:29 -05:00
|
|
|
if (get(type))
|
2019-02-13 09:37:54 -06:00
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
|
2022-11-12 07:19:42 -06:00
|
|
|
LOG_ASSERT(GlobalArray == nullptr);
|
|
|
|
LOG_ASSERT(GlobalIndex == -1);
|
2022-11-09 06:41:27 -06:00
|
|
|
GlobalArray = nullptr;
|
2022-11-12 17:32:48 -06:00
|
|
|
GlobalIndex = -1;
|
2022-11-12 07:19:42 -06:00
|
|
|
GlobalKit = nullptr;
|
|
|
|
GlobalWSD = nullptr;
|
|
|
|
GlobalTool = nullptr;
|
2016-04-05 11:41:10 -05:00
|
|
|
if (!unitLibPath.empty())
|
2016-04-08 11:36:08 -05:00
|
|
|
{
|
2022-11-09 06:41:27 -06:00
|
|
|
GlobalArray = linkAndCreateUnit(type, unitLibPath);
|
2023-09-23 09:23:37 -05:00
|
|
|
if (GlobalArray == nullptr)
|
2016-04-09 11:30:48 -05:00
|
|
|
{
|
2023-09-23 09:23:37 -05:00
|
|
|
// Error is logged already.
|
|
|
|
return false;
|
|
|
|
}
|
2022-12-10 12:13:22 -06:00
|
|
|
|
2023-09-23 09:23:37 -05:00
|
|
|
initTestSuiteOptions();
|
|
|
|
|
|
|
|
// Filter tests.
|
|
|
|
GlobalIndex = 0;
|
|
|
|
filter();
|
2022-11-17 18:23:36 -06:00
|
|
|
|
2023-09-23 09:23:37 -05:00
|
|
|
UnitBase* instance = GlobalArray[GlobalIndex];
|
|
|
|
if (instance)
|
|
|
|
{
|
|
|
|
rememberInstance(type, instance);
|
|
|
|
TST_LOG_NAME("UnitBase",
|
|
|
|
"Starting test #1: " << GlobalArray[GlobalIndex]->getTestname());
|
|
|
|
instance->initialize();
|
|
|
|
|
|
|
|
if (instance && type == UnitType::Kit)
|
2022-11-09 06:41:27 -06:00
|
|
|
{
|
2023-09-23 09:23:37 -05:00
|
|
|
std::unique_lock<std::mutex> lock(TimeoutThreadMutex);
|
|
|
|
TimeoutThread = std::thread(
|
|
|
|
[instance]
|
|
|
|
{
|
|
|
|
Util::setThreadName("unit timeout");
|
2019-11-06 07:03:53 -06:00
|
|
|
|
2023-09-23 09:23:37 -05:00
|
|
|
std::unique_lock<std::mutex> lock2(TimeoutThreadMutex);
|
|
|
|
if (TimeoutConditionVariable.wait_for(lock2,
|
|
|
|
instance->_timeoutMilliSeconds) ==
|
|
|
|
std::cv_status::no_timeout)
|
2022-11-09 06:41:27 -06:00
|
|
|
{
|
2023-09-23 09:23:37 -05:00
|
|
|
LOG_DBG(instance->getTestname() << ": Unit test finished in time");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_ERR(instance->getTestname() << ": Unit test timeout after "
|
|
|
|
<< instance->_timeoutMilliSeconds);
|
|
|
|
instance->timeout();
|
|
|
|
}
|
|
|
|
});
|
2022-11-09 06:41:27 -06:00
|
|
|
}
|
2023-09-23 09:23:37 -05:00
|
|
|
|
|
|
|
return get(type) != nullptr;
|
2016-04-09 11:30:48 -05:00
|
|
|
}
|
2016-04-08 11:36:08 -05:00
|
|
|
}
|
2022-11-09 06:41:27 -06:00
|
|
|
|
|
|
|
// Fallback.
|
|
|
|
switch (type)
|
2016-04-09 11:30:48 -05:00
|
|
|
{
|
2016-12-22 03:27:30 -06:00
|
|
|
case UnitType::Wsd:
|
2022-04-21 18:14:16 -05:00
|
|
|
rememberInstance(UnitType::Wsd, new UnitWSD("UnitWSD"));
|
2022-11-12 17:32:48 -06:00
|
|
|
GlobalArray = new UnitBase* [2] { GlobalWSD, nullptr };
|
2022-11-09 06:41:27 -06:00
|
|
|
GlobalIndex = 0;
|
2016-04-09 11:30:48 -05:00
|
|
|
break;
|
2016-12-22 03:27:30 -06:00
|
|
|
case UnitType::Kit:
|
2022-04-21 18:14:16 -05:00
|
|
|
rememberInstance(UnitType::Kit, new UnitKit("UnitKit"));
|
2022-11-12 17:32:48 -06:00
|
|
|
GlobalArray = new UnitBase* [2] { GlobalKit, nullptr };
|
2022-11-09 06:41:27 -06:00
|
|
|
GlobalIndex = 0;
|
2016-04-09 11:30:48 -05:00
|
|
|
break;
|
2021-08-10 22:41:02 -05:00
|
|
|
case UnitType::Tool:
|
2022-04-21 18:14:16 -05:00
|
|
|
rememberInstance(UnitType::Tool, new UnitTool("UnitTool"));
|
2022-11-12 17:32:48 -06:00
|
|
|
GlobalArray = new UnitBase* [2] { GlobalTool, nullptr };
|
2022-11-09 06:41:27 -06:00
|
|
|
GlobalIndex = 0;
|
2021-08-10 22:41:02 -05:00
|
|
|
break;
|
2016-04-09 11:30:48 -05:00
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-09-16 06:25:29 -05:00
|
|
|
return get(type) != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
UnitBase* UnitBase::get(UnitType type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case UnitType::Wsd:
|
|
|
|
return GlobalWSD;
|
|
|
|
break;
|
|
|
|
case UnitType::Kit:
|
|
|
|
return GlobalKit;
|
|
|
|
break;
|
2021-09-28 04:21:45 -05:00
|
|
|
case UnitType::Tool:
|
|
|
|
return GlobalTool;
|
|
|
|
break;
|
2021-09-16 06:25:29 -05:00
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2021-09-16 06:25:29 -05:00
|
|
|
return nullptr;
|
2016-04-05 11:41:10 -05:00
|
|
|
}
|
|
|
|
|
2021-09-16 06:25:29 -05:00
|
|
|
void UnitBase::rememberInstance(UnitType type, UnitBase* instance)
|
2021-09-14 10:05:31 -05:00
|
|
|
{
|
2021-09-16 06:25:29 -05:00
|
|
|
assert(instance->_type == type);
|
|
|
|
|
2022-11-12 07:19:42 -06:00
|
|
|
assert(GlobalWSD == nullptr);
|
|
|
|
assert(GlobalKit == nullptr);
|
|
|
|
assert(GlobalTool == nullptr);
|
|
|
|
|
2021-09-14 10:05:31 -05:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case UnitType::Wsd:
|
|
|
|
GlobalWSD = static_cast<UnitWSD*>(instance);
|
|
|
|
break;
|
|
|
|
case UnitType::Kit:
|
|
|
|
GlobalKit = static_cast<UnitKit*>(instance);
|
|
|
|
break;
|
2021-09-28 04:21:45 -05:00
|
|
|
case UnitType::Tool:
|
|
|
|
GlobalTool = static_cast<UnitTool*>(instance);
|
|
|
|
break;
|
2021-09-14 10:05:31 -05:00
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 06:47:57 -06:00
|
|
|
int UnitBase::uninit()
|
2022-11-09 06:53:17 -06:00
|
|
|
{
|
2022-11-10 06:47:57 -06:00
|
|
|
TST_LOG_NAME("UnitBase", "Uninitializing unit-tests: "
|
|
|
|
<< (GlobalResult == TestResult::Ok ? "SUCCESS" : "FAILED"));
|
|
|
|
|
2022-11-09 06:53:17 -06:00
|
|
|
if (GlobalArray)
|
|
|
|
{
|
2022-11-10 06:47:57 -06:00
|
|
|
// By default, this will check _setRetValue and copy _retValue to the arg.
|
|
|
|
// But we call it to trigger overrides and to perform cleanups.
|
|
|
|
int retValue = GlobalResult == TestResult::Ok ? EX_OK : EX_SOFTWARE;
|
2022-11-18 06:37:04 -06:00
|
|
|
if (GlobalArray[GlobalIndex] != nullptr)
|
|
|
|
GlobalArray[GlobalIndex]->returnValue(retValue);
|
2022-11-10 06:47:57 -06:00
|
|
|
if (retValue)
|
|
|
|
GlobalResult = TestResult::Failed;
|
|
|
|
|
2022-11-12 17:32:48 -06:00
|
|
|
for (int i = 0; GlobalArray[i] != nullptr; ++i)
|
2022-11-09 06:53:17 -06:00
|
|
|
{
|
2022-11-12 17:32:48 -06:00
|
|
|
delete GlobalArray[i];
|
2022-11-09 06:53:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
delete[] GlobalArray;
|
|
|
|
GlobalArray = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalIndex = -1;
|
|
|
|
|
|
|
|
free(UnitBase::UnitLibPath);
|
|
|
|
UnitBase::UnitLibPath = nullptr;
|
|
|
|
|
|
|
|
GlobalKit = nullptr;
|
|
|
|
GlobalWSD = nullptr;
|
|
|
|
GlobalTool = nullptr;
|
|
|
|
|
|
|
|
// Close the DLL last, after deleting the test instances.
|
|
|
|
if (DlHandle)
|
|
|
|
dlclose(DlHandle);
|
|
|
|
DlHandle = nullptr;
|
|
|
|
|
2022-11-10 06:47:57 -06:00
|
|
|
return GlobalResult == TestResult::Ok ? EX_OK : EX_SOFTWARE;
|
2022-11-09 06:53:17 -06:00
|
|
|
}
|
|
|
|
|
2022-11-12 07:18:59 -06:00
|
|
|
void UnitBase::initialize()
|
|
|
|
{
|
|
|
|
assert(DlHandle != nullptr && "Invalid handle to set");
|
2022-11-16 06:46:30 -06:00
|
|
|
LOG_TST("==================== Starting [" << getTestname() << "] ====================");
|
2022-11-12 07:18:59 -06:00
|
|
|
_socketPoll->startThread();
|
|
|
|
}
|
|
|
|
|
2016-10-22 10:35:30 -05:00
|
|
|
bool UnitBase::isUnitTesting()
|
|
|
|
{
|
2022-11-12 17:32:48 -06:00
|
|
|
return DlHandle;
|
2016-10-22 10:35:30 -05:00
|
|
|
}
|
|
|
|
|
2020-12-14 13:00:55 -06:00
|
|
|
void UnitBase::setTimeout(std::chrono::milliseconds timeoutMilliSeconds)
|
2016-04-08 11:36:08 -05:00
|
|
|
{
|
2023-06-10 06:28:25 -05:00
|
|
|
assert(!TimeoutThread.joinable() && "setTimeout must be called before starting a test");
|
2016-04-08 11:36:08 -05:00
|
|
|
_timeoutMilliSeconds = timeoutMilliSeconds;
|
2021-04-12 13:40:38 -05:00
|
|
|
LOG_TST(getTestname() << ": setTimeout: " << _timeoutMilliSeconds);
|
2016-04-08 11:36:08 -05:00
|
|
|
}
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
UnitBase::~UnitBase()
|
2016-04-05 11:41:10 -05:00
|
|
|
{
|
2022-11-26 09:23:16 -06:00
|
|
|
LOG_TST(getTestname() << ": ~UnitBase: " << (failed() ? "FAILED" : "SUCCESS"));
|
2022-04-21 16:53:34 -05:00
|
|
|
|
2021-04-12 23:48:47 -05:00
|
|
|
_socketPoll->joinThread();
|
2016-04-05 11:41:10 -05:00
|
|
|
}
|
|
|
|
|
2022-06-18 09:32:49 -05:00
|
|
|
bool UnitBase::filterLOKitMessage(const std::shared_ptr<Message>& message)
|
|
|
|
{
|
|
|
|
return onFilterLOKitMessage(message);
|
|
|
|
}
|
|
|
|
|
2022-06-14 05:27:24 -05:00
|
|
|
bool UnitBase::filterSendWebSocketMessage(const char* data, const std::size_t len,
|
|
|
|
const WSOpCode code, const bool flush, int& unitReturn)
|
2022-05-03 06:50:24 -05:00
|
|
|
{
|
|
|
|
const std::string message(data, len);
|
|
|
|
if (Util::startsWith(message, "unocommandresult:"))
|
|
|
|
{
|
|
|
|
const std::size_t index = message.find_first_of('{');
|
|
|
|
if (index != std::string::npos)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
const std::string stringJSON = message.substr(index);
|
|
|
|
Poco::JSON::Parser parser;
|
|
|
|
const Poco::Dynamic::Var parsedJSON = parser.parse(stringJSON);
|
|
|
|
const auto& object = parsedJSON.extract<Poco::JSON::Object::Ptr>();
|
|
|
|
if (object->get("commandName").toString() == ".uno:Save")
|
|
|
|
{
|
|
|
|
const bool success = object->get("success").toString() == "true";
|
|
|
|
std::string result;
|
|
|
|
if (object->has("result"))
|
|
|
|
{
|
|
|
|
const Poco::Dynamic::Var parsedResultJSON = object->get("result");
|
|
|
|
const auto& resultObj = parsedResultJSON.extract<Poco::JSON::Object::Ptr>();
|
|
|
|
if (resultObj->get("type").toString() == "string")
|
|
|
|
result = resultObj->get("value").toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (onDocumentSaved(message, success, result))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const std::exception& exception)
|
|
|
|
{
|
|
|
|
LOG_TST("unocommandresult parsing failure: " << exception.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_TST("Expected json unocommandresult. Ignoring: " << message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (Util::startsWith(message, "status:"))
|
|
|
|
{
|
|
|
|
if (onDocumentLoaded(message))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (message == "statechanged: .uno:ModifiedStatus=true")
|
|
|
|
{
|
|
|
|
if (onDocumentModified(message))
|
|
|
|
return false;
|
|
|
|
}
|
2022-12-17 14:12:40 -06:00
|
|
|
else if (message == "statechanged: .uno:ModifiedStatus=false")
|
|
|
|
{
|
|
|
|
if (onDocumentUnmodified(message))
|
|
|
|
return false;
|
|
|
|
}
|
2022-05-03 06:50:24 -05:00
|
|
|
else if (Util::startsWith(message, "statechanged:"))
|
|
|
|
{
|
|
|
|
if (onDocumentStateChanged(message))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (Util::startsWith(message, "error:"))
|
|
|
|
{
|
|
|
|
if (onDocumentError(message))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-14 05:27:24 -05:00
|
|
|
return onFilterSendWebSocketMessage(data, len, code, flush, unitReturn);
|
2022-05-03 06:50:24 -05:00
|
|
|
}
|
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
void UnitBase::exitTest(TestResult result, const std::string& reason)
|
|
|
|
{
|
|
|
|
// We could be called from either a SocketPoll (websrv_poll)
|
|
|
|
// or from invokeTest (coolwsd main).
|
|
|
|
std::lock_guard<std::mutex> guard(_lock);
|
|
|
|
|
|
|
|
if (isFinished())
|
|
|
|
{
|
|
|
|
if (result != _result)
|
|
|
|
LOG_TST("exitTest got " << name(result) << " but is already finished with "
|
|
|
|
<< name(_result));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == TestResult::Ok)
|
|
|
|
{
|
|
|
|
LOG_TST("SUCCESS: exitTest: " << name(result) << (reason.empty() ? "" : ": " + reason));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_TST("ERROR: FAILURE: exitTest: " << name(result)
|
|
|
|
<< (reason.empty() ? "" : ": " + reason));
|
|
|
|
|
|
|
|
if (GlobalResult == TestResult::Ok)
|
|
|
|
GlobalResult = result;
|
2023-06-04 15:56:55 -05:00
|
|
|
|
|
|
|
LOG_TST("Dumping state");
|
|
|
|
::kill(getpid(), SIGUSR1);
|
2022-12-24 23:03:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
_result = result;
|
|
|
|
endTest(reason);
|
|
|
|
_setRetValue = true;
|
|
|
|
|
|
|
|
// Notify inheritors.
|
|
|
|
onExitTest(result, reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnitBase::timeout()
|
|
|
|
{
|
|
|
|
// Don't timeout if we had already finished.
|
|
|
|
if (isUnitTesting() && !isFinished())
|
|
|
|
{
|
|
|
|
LOG_TST("ERROR: Timed out waiting for unit test to complete within "
|
|
|
|
<< _timeoutMilliSeconds);
|
|
|
|
exitTest(TestResult::TimedOut);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnitBase::returnValue(int& retValue)
|
|
|
|
{
|
|
|
|
if (_setRetValue)
|
|
|
|
retValue = (_result == TestResult::Ok ? EX_OK : EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnitBase::endTest(const std::string& reason)
|
|
|
|
{
|
|
|
|
LOG_TST("Ending test by stopping SocketPoll [" << _socketPoll->name() << "]: " << reason);
|
|
|
|
_socketPoll->joinThread();
|
|
|
|
|
|
|
|
// tell the timeout thread that the work has finished
|
2023-06-10 06:28:25 -05:00
|
|
|
TimeoutConditionVariable.notify_all();
|
2022-12-24 23:03:25 -06:00
|
|
|
if (TimeoutThread.joinable())
|
|
|
|
TimeoutThread.join();
|
|
|
|
|
|
|
|
LOG_TST("==================== Finished [" << getTestname() << "] ====================");
|
|
|
|
}
|
|
|
|
|
2022-04-21 18:14:16 -05:00
|
|
|
UnitWSD::UnitWSD(const std::string& name)
|
|
|
|
: UnitBase(name, UnitType::Wsd)
|
2020-12-20 21:11:33 -06:00
|
|
|
, _hasKitHooks(false)
|
2016-04-09 11:30:48 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
UnitWSD::~UnitWSD()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-04-21 18:48:14 -05:00
|
|
|
void UnitWSD::defaultConfigure(Poco::Util::LayeredConfiguration& config)
|
2016-10-21 15:25:23 -05:00
|
|
|
{
|
2022-04-21 18:48:14 -05:00
|
|
|
// 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);
|
2016-10-21 15:25:23 -05:00
|
|
|
}
|
|
|
|
|
2022-08-30 00:27:44 -05:00
|
|
|
void UnitWSD::lookupTile(int part, int mode, int width, int height, int tilePosX, int tilePosY,
|
2019-02-14 13:01:43 -06:00
|
|
|
int tileWidth, int tileHeight,
|
2021-11-13 05:49:35 -06:00
|
|
|
std::shared_ptr<TileData> &tile)
|
2016-05-01 09:24:31 -05:00
|
|
|
{
|
2021-04-29 05:15:36 -05:00
|
|
|
if (isUnitTesting())
|
|
|
|
{
|
|
|
|
if (tile)
|
2022-08-30 00:27:44 -05:00
|
|
|
onTileCacheHit(part, mode, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
|
2021-04-29 05:15:36 -05:00
|
|
|
else
|
2022-08-30 00:27:44 -05:00
|
|
|
onTileCacheMiss(part, mode, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
|
2021-04-29 05:15:36 -05:00
|
|
|
}
|
2016-05-01 09:24:31 -05:00
|
|
|
}
|
|
|
|
|
2022-12-24 17:40:29 -06:00
|
|
|
void UnitWSD::DocBrokerDestroy(const std::string& key)
|
|
|
|
{
|
|
|
|
if (isUnitTesting())
|
|
|
|
{
|
|
|
|
onDocBrokerDestroy(key);
|
2023-02-25 20:52:40 -06:00
|
|
|
if (!isFinished())
|
|
|
|
{
|
|
|
|
// Not yet finished; don't start the next test just yet.
|
|
|
|
return;
|
|
|
|
}
|
2022-12-24 17:40:29 -06:00
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
// We could be called from either a SocketPoll (websrv_poll)
|
|
|
|
// or from invokeTest (coolwsd main).
|
|
|
|
std::lock_guard<std::mutex> guard(_lock);
|
2021-09-14 10:05:31 -05:00
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
// Check if we have more tests, but keep the current index if it's the last.
|
|
|
|
if (haveMoreTests())
|
2022-12-11 07:30:53 -06:00
|
|
|
{
|
2022-12-24 23:03:25 -06:00
|
|
|
// We have more tests.
|
|
|
|
++GlobalIndex;
|
|
|
|
filter();
|
2020-12-22 18:08:45 -06:00
|
|
|
|
2023-02-25 20:52:40 -06:00
|
|
|
// Clear the shortcuts.
|
|
|
|
GlobalKit = nullptr;
|
|
|
|
GlobalWSD = nullptr;
|
|
|
|
GlobalTool = nullptr;
|
2022-11-12 07:19:42 -06:00
|
|
|
|
2023-06-27 16:11:07 -05:00
|
|
|
if (GlobalArray[GlobalIndex] != nullptr && !SigUtil::getShutdownRequestFlag() &&
|
|
|
|
(_result == TestResult::Ok || GlobalTestOptions.getKeepgoing()))
|
2023-02-25 20:52:40 -06:00
|
|
|
{
|
|
|
|
rememberInstance(_type, GlobalArray[GlobalIndex]);
|
2022-11-18 06:37:04 -06:00
|
|
|
|
2023-02-25 20:52:40 -06:00
|
|
|
LOG_TST("Starting test #" << GlobalIndex + 1 << ": "
|
|
|
|
<< GlobalArray[GlobalIndex]->getTestname());
|
|
|
|
if (GlobalWSD)
|
|
|
|
GlobalWSD->configure(Poco::Util::Application::instance().config());
|
|
|
|
GlobalArray[GlobalIndex]->initialize();
|
2022-12-24 23:03:25 -06:00
|
|
|
}
|
2023-06-27 16:11:07 -05:00
|
|
|
|
|
|
|
// Wake-up so the previous test stops.
|
|
|
|
SocketPoll::wakeupWorld();
|
2022-12-24 23:03:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UnitWSD& UnitWSD::get()
|
|
|
|
{
|
|
|
|
assert(GlobalWSD);
|
|
|
|
return *GlobalWSD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnitWSD::onExitTest(TestResult result, const std::string&)
|
|
|
|
{
|
|
|
|
if (haveMoreTests())
|
|
|
|
{
|
|
|
|
if (result != TestResult::Ok && !GlobalTestOptions.getKeepgoing())
|
|
|
|
{
|
|
|
|
LOG_TST("Failing fast per options, even though there are more tests");
|
|
|
|
#if !MOBILEAPP
|
|
|
|
LOG_TST("Setting TerminationFlag as the Test Suite failed");
|
2023-07-14 15:24:42 -05:00
|
|
|
SigUtil::setTerminationFlag(); // and wake-up world.
|
2022-12-24 23:03:25 -06:00
|
|
|
#else
|
2022-11-24 07:49:47 -06:00
|
|
|
SocketPoll::wakeupWorld();
|
2022-12-24 23:03:25 -06:00
|
|
|
#endif
|
2022-11-18 06:37:04 -06:00
|
|
|
return;
|
|
|
|
}
|
2022-12-24 23:03:25 -06:00
|
|
|
|
|
|
|
LOG_TST("Have more tests. Waiting for the DocBroker to destroy before starting them");
|
|
|
|
return;
|
2022-11-12 17:32:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// We are done with all the tests.
|
2022-11-10 06:47:57 -06:00
|
|
|
TST_LOG_NAME("UnitBase", getTestname()
|
|
|
|
<< " was the last test. Finishing "
|
|
|
|
<< (GlobalResult == TestResult::Ok ? "SUCCESS" : "FAILED"));
|
2022-11-12 17:32:48 -06:00
|
|
|
|
2020-02-24 01:12:38 -06:00
|
|
|
#if !MOBILEAPP
|
2022-11-29 04:10:19 -06:00
|
|
|
LOG_TST("Setting TerminationFlag as there are no more tests");
|
2023-07-14 15:24:42 -05:00
|
|
|
SigUtil::setTerminationFlag(); // and wake-up world.
|
2021-01-10 15:44:24 -06:00
|
|
|
#else
|
2017-03-16 13:52:49 -05:00
|
|
|
SocketPoll::wakeupWorld();
|
2021-01-10 15:44:24 -06:00
|
|
|
#endif
|
2016-04-06 13:50:55 -05:00
|
|
|
}
|
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
UnitKit::UnitKit(const std::string& name)
|
|
|
|
: UnitBase(name, UnitType::Kit)
|
2016-04-08 11:36:08 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
UnitKit::~UnitKit() {}
|
|
|
|
|
|
|
|
UnitKit& UnitKit::get()
|
2016-04-06 13:50:55 -05:00
|
|
|
{
|
2022-12-24 23:03:25 -06:00
|
|
|
#if MOBILEAPP
|
|
|
|
if (!GlobalKit)
|
|
|
|
GlobalKit = new UnitKit("UnitKit");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
assert(GlobalKit);
|
|
|
|
return *GlobalKit;
|
2022-11-26 09:23:16 -06:00
|
|
|
}
|
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
void UnitKit::onExitTest(TestResult, const std::string&)
|
2022-11-26 09:23:16 -06:00
|
|
|
{
|
2022-12-24 23:03:25 -06:00
|
|
|
// coolforkit doesn't link with CPPUnit.
|
|
|
|
// LOK_ASSERT_MESSAGE("UnitKit doesn't yet support multiple tests", !haveMoreTests());
|
2016-04-06 13:50:55 -05:00
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
// // We are done with all the tests.
|
|
|
|
// TST_LOG_NAME("UnitBase", getTestname()
|
|
|
|
// << " was the last test. Finishing "
|
|
|
|
// << (GlobalResult == TestResult::Ok ? "SUCCESS" : "FAILED"));
|
2022-11-16 06:46:30 -06:00
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
#if !MOBILEAPP
|
|
|
|
// LOG_TST("Setting TerminationFlag as there are no more tests");
|
2023-07-14 15:24:42 -05:00
|
|
|
SigUtil::setTerminationFlag(); // and wake-up world.
|
2022-12-24 23:03:25 -06:00
|
|
|
#else
|
|
|
|
SocketPoll::wakeupWorld();
|
|
|
|
#endif
|
2016-04-06 13:50:55 -05:00
|
|
|
}
|
|
|
|
|
2016-04-05 11:41:10 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|