2016-04-05 11:41:10 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* 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/.
|
|
|
|
*/
|
2020-04-18 03:39:50 -05:00
|
|
|
|
|
|
|
#pragma once
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2016-04-08 11:36:08 -05:00
|
|
|
#include <atomic>
|
2016-08-30 02:06:39 -05:00
|
|
|
#include <cassert>
|
2020-12-14 13:00:55 -06:00
|
|
|
#include <chrono>
|
2016-10-29 20:15:00 -05:00
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
2022-02-15 16:45:01 -06:00
|
|
|
#include <vector>
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2022-04-01 20:04:41 -05:00
|
|
|
#include <common/StateEnum.hpp>
|
2022-05-03 06:50:24 -05:00
|
|
|
#include "Util.hpp"
|
2017-10-26 03:38:57 -05:00
|
|
|
#include "net/Socket.hpp"
|
2016-04-18 08:29:17 -05:00
|
|
|
|
2022-02-15 16:45:01 -06:00
|
|
|
#include <test/testlog.hpp>
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
class UnitBase;
|
|
|
|
class UnitWSD;
|
|
|
|
class UnitKit;
|
2016-04-08 11:36:08 -05:00
|
|
|
class UnitTimeout;
|
2016-04-07 15:59:27 -05:00
|
|
|
|
2017-10-26 03:38:57 -05:00
|
|
|
class WebSocketHandler;
|
2022-02-10 08:59:47 -06:00
|
|
|
class ClientSession;
|
2022-06-18 09:32:49 -05:00
|
|
|
class Message;
|
2017-10-26 03:38:57 -05:00
|
|
|
|
2016-04-16 13:37:38 -05:00
|
|
|
// Forward declaration to avoid pulling the world here.
|
2016-10-29 20:15:00 -05:00
|
|
|
namespace Poco
|
|
|
|
{
|
2018-02-08 12:51:54 -06:00
|
|
|
class MemoryInputStream;
|
|
|
|
|
2016-10-29 20:15:00 -05:00
|
|
|
namespace Net
|
|
|
|
{
|
2016-04-12 15:30:06 -05:00
|
|
|
class HTTPServerRequest;
|
|
|
|
class HTTPServerResponse;
|
2016-04-16 13:37:38 -05:00
|
|
|
}
|
|
|
|
|
2016-10-29 20:15:00 -05:00
|
|
|
namespace Util
|
|
|
|
{
|
2016-04-16 13:37:38 -05:00
|
|
|
class LayeredConfiguration;
|
|
|
|
}
|
|
|
|
}
|
2016-04-12 15:30:06 -05:00
|
|
|
|
2016-12-12 18:53:58 -06:00
|
|
|
class Session;
|
2016-04-07 15:59:27 -05:00
|
|
|
class StorageBase;
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
typedef UnitBase *(CreateUnitHooksFunction)();
|
2022-11-15 17:25:18 -06:00
|
|
|
typedef UnitBase**(CreateUnitHooksFunctionMulti)();
|
2016-04-09 11:30:48 -05:00
|
|
|
extern "C" { UnitBase *unit_create_wsd(void); }
|
2022-11-15 17:25:18 -06:00
|
|
|
extern "C" { UnitBase** unit_create_wsd_multi(void); }
|
2016-04-09 11:30:48 -05:00
|
|
|
extern "C" { UnitBase *unit_create_kit(void); }
|
2016-05-01 03:04:19 -05:00
|
|
|
extern "C" { typedef struct _LibreOfficeKit LibreOfficeKit; }
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
/// Derive your WSD unit test / hooks from me.
|
|
|
|
class UnitBase
|
2016-04-05 11:41:10 -05:00
|
|
|
{
|
2016-04-08 11:36:08 -05:00
|
|
|
friend UnitTimeout;
|
2016-04-09 11:30:48 -05:00
|
|
|
friend UnitWSD;
|
|
|
|
friend UnitKit;
|
2016-04-08 11:36:08 -05:00
|
|
|
|
2021-09-16 06:25:29 -05:00
|
|
|
public:
|
|
|
|
enum class UnitType
|
|
|
|
{
|
|
|
|
Wsd,
|
|
|
|
Kit,
|
|
|
|
Tool
|
|
|
|
};
|
|
|
|
|
2016-04-06 13:50:55 -05:00
|
|
|
protected:
|
2022-12-10 12:13:22 -06:00
|
|
|
/// The options used for the current TestSuite.
|
|
|
|
class TestOptions
|
|
|
|
{
|
|
|
|
public:
|
2022-12-11 07:30:53 -06:00
|
|
|
TestOptions()
|
|
|
|
: _keepgoing(false)
|
|
|
|
{
|
|
|
|
}
|
2022-12-10 12:13:22 -06:00
|
|
|
|
|
|
|
void setFilter(const std::string& filter) { _filter = filter; }
|
|
|
|
const std::string& getFilter() const { return _filter; }
|
|
|
|
|
2022-12-11 07:30:53 -06:00
|
|
|
void setKeepgoing(bool failfase) { _keepgoing = failfase; }
|
|
|
|
bool getKeepgoing() const { return _keepgoing; }
|
|
|
|
|
2022-12-10 12:13:22 -06:00
|
|
|
private:
|
|
|
|
/// The test filter string. Only run tests that match.
|
|
|
|
std::string _filter;
|
2022-12-11 07:30:53 -06:00
|
|
|
/// Don't run subsequent tests, if any, on failure.
|
|
|
|
bool _keepgoing;
|
2022-12-10 12:13:22 -06:00
|
|
|
};
|
|
|
|
|
2016-04-07 15:59:27 -05:00
|
|
|
// ---------------- Helper API ----------------
|
2016-04-08 11:36:08 -05:00
|
|
|
/// After this time we invoke 'timeout' default 30 seconds
|
2020-12-14 13:00:55 -06:00
|
|
|
void setTimeout(std::chrono::milliseconds timeoutMilliSeconds);
|
2016-04-08 11:36:08 -05:00
|
|
|
|
2022-11-26 08:04:14 -06:00
|
|
|
STATE_ENUM(TestResult, Failed, Ok, TimedOut);
|
2020-06-22 07:24:11 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
/// Encourages the process to exit with this value (unless hooked)
|
2022-11-17 18:24:31 -06:00
|
|
|
void exitTest(TestResult result, const std::string& reason = std::string());
|
2016-04-07 15:59:27 -05:00
|
|
|
|
2021-01-10 15:44:24 -06:00
|
|
|
/// Fail the test with the given reason.
|
|
|
|
void failTest(const std::string& reason)
|
|
|
|
{
|
2022-11-17 18:24:31 -06:00
|
|
|
exitTest(TestResult::Failed, reason);
|
2021-01-10 15:44:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Pass the test with the given optional reason.
|
|
|
|
void passTest(const std::string& reason = std::string())
|
|
|
|
{
|
2022-11-17 18:24:31 -06:00
|
|
|
exitTest(TestResult::Ok, reason);
|
2021-01-10 15:44:24 -06:00
|
|
|
}
|
|
|
|
|
2022-11-26 09:23:16 -06:00
|
|
|
/// Called when a test has eneded, to clean up.
|
|
|
|
virtual void endTest(const std::string& reason);
|
2022-11-26 07:27:07 -06:00
|
|
|
|
2021-04-12 14:14:49 -05:00
|
|
|
/// Construct a UnitBase instance with a default name.
|
2022-04-21 18:14:16 -05:00
|
|
|
explicit UnitBase(const std::string& name, UnitType type)
|
2022-11-09 06:53:17 -06:00
|
|
|
: _setRetValue(false)
|
2022-11-26 09:23:16 -06:00
|
|
|
, _result(TestResult::Ok)
|
2021-04-12 14:14:49 -05:00
|
|
|
, _timeoutMilliSeconds(std::chrono::seconds(30))
|
2022-12-11 08:09:12 -06:00
|
|
|
, _startTimeMilliSeconds(std::chrono::milliseconds::zero())
|
2021-09-16 06:25:29 -05:00
|
|
|
, _type(type)
|
2022-02-16 16:22:18 -06:00
|
|
|
, _socketPoll(std::make_shared<SocketPoll>(name))
|
2022-04-21 18:14:16 -05:00
|
|
|
, testname(name)
|
2020-12-20 21:11:33 -06:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
virtual ~UnitBase();
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Load unit test hook shared library from this path
|
2016-10-29 20:15:00 -05:00
|
|
|
static bool init(UnitType type, const std::string& unitLibPath);
|
2016-04-09 11:30:48 -05:00
|
|
|
|
2022-11-10 06:47:57 -06:00
|
|
|
/// Uninitialize the unit-test and return the global exit code.
|
|
|
|
/// Returns 0 on success.
|
|
|
|
static int uninit();
|
2022-11-09 06:53:17 -06:00
|
|
|
|
2016-10-22 10:35:30 -05:00
|
|
|
/// Do we have a unit test library hooking things & loaded
|
|
|
|
static bool isUnitTesting();
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
/// Tweak the return value from the process.
|
2016-10-29 20:15:00 -05:00
|
|
|
virtual void returnValue(int& /* retValue */);
|
2016-04-09 11:30:48 -05:00
|
|
|
|
2022-11-16 19:02:11 -06:00
|
|
|
/// Data-loss detection. Override if expected/intentional.
|
|
|
|
/// Returns true if we failed, false otherwise.
|
|
|
|
virtual bool onDataLoss(const std::string& reason)
|
2021-11-30 10:07:38 -06:00
|
|
|
{
|
2022-11-29 04:10:19 -06:00
|
|
|
LOG_TST("onDataLoss: " << reason);
|
2021-11-30 10:07:38 -06:00
|
|
|
failTest(reason);
|
2022-11-16 19:02:11 -06:00
|
|
|
return failed();
|
2021-11-30 10:07:38 -06:00
|
|
|
}
|
|
|
|
|
2016-12-07 15:32:08 -06:00
|
|
|
/// Input message either for WSD or Kit
|
2016-12-12 18:53:58 -06:00
|
|
|
virtual bool filterSessionInput(Session *, const char */* buffer */,
|
2016-12-07 15:32:08 -06:00
|
|
|
int /* length */,
|
|
|
|
std::unique_ptr< std::vector<char> > & /* replace */)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-26 03:38:57 -05:00
|
|
|
|
2022-06-18 09:32:49 -05:00
|
|
|
/// Message that LOKit sent (typically upon receipt in DocBroker).
|
|
|
|
/// To override, handle onFilterLOKitMessage.
|
|
|
|
/// Returns true to stop processing the message further.
|
|
|
|
bool filterLOKitMessage(const std::shared_ptr<Message>& message);
|
|
|
|
|
2017-10-26 03:38:57 -05:00
|
|
|
/// Message that is about to be sent via the websocket.
|
2022-06-14 05:27:24 -05:00
|
|
|
/// To override, handle onFilterSendWebSocketMessage or any of the onDocument...() handlers.
|
|
|
|
/// Returns true to stop processing the message further.
|
|
|
|
bool filterSendWebSocketMessage(const char* data, const std::size_t len, const WSOpCode code,
|
|
|
|
const bool flush, int& unitReturn);
|
2016-12-07 15:32:08 -06:00
|
|
|
|
2017-03-31 11:18:41 -05:00
|
|
|
/// Hook the disk space check
|
|
|
|
virtual bool filterCheckDiskSpace(const std::string & /* path */,
|
|
|
|
bool & /* newResult */)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-16 11:55:23 -05:00
|
|
|
/// Trap and filter alerting all users
|
|
|
|
virtual bool filterAlertAllusers(const std::string & /* msg */)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-08-09 15:02:29 -05:00
|
|
|
/// Custom response to a http request.
|
2021-01-04 17:35:43 -06:00
|
|
|
virtual bool handleHttpRequest(const Poco::Net::HTTPRequest& /*request*/,
|
|
|
|
Poco::MemoryInputStream& /*message*/,
|
|
|
|
std::shared_ptr<StreamSocket>& /*socket*/)
|
2017-08-09 15:02:29 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-04 17:35:43 -06:00
|
|
|
/// Called when the document has been loaded,
|
2022-06-14 05:27:24 -05:00
|
|
|
/// based on the "status:" message, in the context of filterSendWebSocketMessage.
|
2021-01-04 17:35:43 -06:00
|
|
|
/// Return true to stop further handling of messages.
|
|
|
|
virtual bool onDocumentLoaded(const std::string&) { return false; }
|
|
|
|
|
|
|
|
/// Called when the document's 'modified' status
|
|
|
|
/// changes to true.
|
|
|
|
/// Return true to stop further handling of messages.
|
|
|
|
virtual bool onDocumentModified(const std::string&) { return false; }
|
|
|
|
|
2022-12-17 14:12:40 -06:00
|
|
|
/// Called when the document's 'modified' status
|
|
|
|
/// changes to false. This happens after saving.
|
|
|
|
/// Return true to stop further handling of messages.
|
|
|
|
virtual bool onDocumentUnmodified(const std::string&) { return false; }
|
|
|
|
|
2021-01-04 17:35:43 -06:00
|
|
|
/// Called when the document has been saved.
|
|
|
|
/// Return true to stop further handling of messages.
|
2022-05-03 06:50:24 -05:00
|
|
|
virtual bool onDocumentSaved(const std::string&, bool, const std::string&) { return false; }
|
2021-01-04 17:35:43 -06:00
|
|
|
|
2023-01-11 17:06:16 -06:00
|
|
|
/// Called when the document has been uploaded.
|
|
|
|
virtual void onDocumentUploaded(bool) {}
|
|
|
|
|
2021-01-04 17:35:43 -06:00
|
|
|
/// Called when the document issues a 'statechanged:' message.
|
|
|
|
/// Return true to stop further handling of messages.
|
|
|
|
virtual bool onDocumentStateChanged(const std::string&) { return false; }
|
|
|
|
|
|
|
|
/// Called when the document issues an 'error:' message.
|
|
|
|
/// Return true to stop further handling of messages.
|
|
|
|
virtual bool onDocumentError(const std::string&) { return false; }
|
|
|
|
|
2017-03-16 13:52:49 -05:00
|
|
|
/// If the test times out this gets invoked, the default just exits.
|
|
|
|
virtual void timeout();
|
|
|
|
|
2022-02-15 20:19:26 -06:00
|
|
|
/// True iff exitTest is called.
|
2022-02-09 18:37:40 -06:00
|
|
|
bool isFinished() const { return _setRetValue; }
|
|
|
|
|
2022-02-15 20:19:26 -06:00
|
|
|
/// True iff exitTest was called with anything but TestResult::Ok.
|
|
|
|
/// Meaningful only when isFinished() is true.
|
2022-11-26 09:23:16 -06:00
|
|
|
bool failed() const { return _result != TestResult::Ok; }
|
2022-02-15 20:19:26 -06:00
|
|
|
|
2020-12-14 13:00:55 -06:00
|
|
|
std::chrono::milliseconds getTimeoutMilliSeconds() const
|
2017-03-16 13:52:49 -05:00
|
|
|
{
|
|
|
|
return _timeoutMilliSeconds;
|
|
|
|
}
|
|
|
|
|
2022-02-09 18:37:40 -06:00
|
|
|
void checkTimeout(const std::chrono::milliseconds elapsedTime)
|
|
|
|
{
|
2022-12-11 08:09:12 -06:00
|
|
|
if (_startTimeMilliSeconds == std::chrono::milliseconds::zero())
|
|
|
|
{
|
|
|
|
// Since we can't assume we are the first test to run,
|
|
|
|
// we need to capture *out* start so we can correctly
|
|
|
|
// calculate how long we've been running.
|
|
|
|
_startTimeMilliSeconds = elapsedTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isUnitTesting() && !isFinished() &&
|
|
|
|
(elapsedTime - _startTimeMilliSeconds) > getTimeoutMilliSeconds())
|
2022-02-09 18:37:40 -06:00
|
|
|
{
|
|
|
|
LOG_TST("ERROR Test exceeded its time limit of "
|
|
|
|
<< getTimeoutMilliSeconds() << ". It's been running for " << elapsedTime);
|
|
|
|
timeout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 15:32:08 -06:00
|
|
|
static UnitBase& get()
|
|
|
|
{
|
2022-12-10 12:26:36 -06:00
|
|
|
assert(GlobalArray && GlobalIndex >= 0 && GlobalArray[GlobalIndex] &&
|
|
|
|
"There are no tests to dereference");
|
2022-11-09 06:41:27 -06:00
|
|
|
return *GlobalArray[GlobalIndex];
|
2016-12-07 15:32:08 -06:00
|
|
|
}
|
|
|
|
|
2020-01-17 14:49:38 -06:00
|
|
|
static std::string getUnitLibPath() { return std::string(UnitLibPath); }
|
|
|
|
|
2022-02-16 16:22:18 -06:00
|
|
|
const std::string& getTestname() const { return testname; }
|
|
|
|
void setTestname(const std::string& name) { testname = name; }
|
2020-12-20 21:11:33 -06:00
|
|
|
|
2021-04-12 23:48:47 -05:00
|
|
|
std::shared_ptr<SocketPoll> socketPoll() { return _socketPoll; }
|
2021-04-12 16:22:08 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
private:
|
2022-11-12 07:18:59 -06:00
|
|
|
/// Initialize the test.
|
|
|
|
virtual void initialize();
|
2022-11-09 06:41:27 -06:00
|
|
|
|
|
|
|
/// Dynamically load the unit-test .so.
|
|
|
|
static UnitBase** linkAndCreateUnit(UnitType type, const std::string& unitLibPath);
|
2016-04-09 11:30:48 -05:00
|
|
|
|
2022-12-10 12:13:22 -06:00
|
|
|
/// Initialize the Test Suite options.
|
|
|
|
static void initTestSuiteOptions();
|
|
|
|
|
2022-11-17 18:23:36 -06:00
|
|
|
/// Based on COOL_TEST_OPTIONS envar, filter the tests.
|
|
|
|
static void filter();
|
|
|
|
|
2022-12-10 12:26:36 -06:00
|
|
|
/// Returns true iff there are more valid test instances to dereference.
|
|
|
|
static bool haveMoreTests()
|
|
|
|
{
|
|
|
|
return GlobalArray && GlobalIndex >= 0 && GlobalArray[GlobalIndex + 1];
|
|
|
|
}
|
|
|
|
|
2022-11-12 07:19:42 -06:00
|
|
|
/// Self-test.
|
|
|
|
static void selfTest();
|
|
|
|
|
2022-12-24 23:03:25 -06:00
|
|
|
/// Called when a test is finished with the given result and reason.
|
|
|
|
virtual void onExitTest(TestResult result, const std::string& reason = std::string()) = 0;
|
|
|
|
|
2022-06-18 09:32:49 -05:00
|
|
|
/// Handles messages from LOKit.
|
|
|
|
virtual bool onFilterLOKitMessage(const std::shared_ptr<Message>& /*message*/) { return false; }
|
|
|
|
|
2021-01-04 17:35:43 -06:00
|
|
|
/// Handles messages sent via WebSocket.
|
2022-06-14 05:27:24 -05:00
|
|
|
virtual bool onFilterSendWebSocketMessage(const char* /*data*/, const std::size_t /*len*/,
|
|
|
|
const WSOpCode /* code */, const bool /* flush */,
|
|
|
|
int& /*unitReturn*/)
|
2021-01-04 17:35:43 -06:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-09-16 06:25:29 -05:00
|
|
|
static UnitBase* get(UnitType type);
|
|
|
|
|
2021-09-14 10:05:31 -05:00
|
|
|
/// setup global instance for get() method
|
2021-09-16 06:25:29 -05:00
|
|
|
static void rememberInstance(UnitType type, UnitBase* instance);
|
2021-09-14 10:05:31 -05:00
|
|
|
|
2022-11-09 06:53:17 -06:00
|
|
|
static void* DlHandle; //< The handle to the unit-test .so.
|
2020-01-17 14:49:38 -06:00
|
|
|
static char *UnitLibPath;
|
2022-11-09 06:41:27 -06:00
|
|
|
static UnitBase** GlobalArray; //< All the tests.
|
|
|
|
static int GlobalIndex; //< The index of the current test.
|
2022-12-10 12:13:22 -06:00
|
|
|
static TestOptions GlobalTestOptions; //< The test options for this Test Suite.
|
2022-11-10 06:47:57 -06:00
|
|
|
static TestResult GlobalResult; //< The result of all tests. Latches at first failure.
|
2022-11-09 06:41:27 -06:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
bool _setRetValue;
|
2022-11-26 09:23:16 -06:00
|
|
|
TestResult _result;
|
2020-12-14 13:00:55 -06:00
|
|
|
std::chrono::milliseconds _timeoutMilliSeconds;
|
2022-12-11 08:09:12 -06:00
|
|
|
/// The time at which this particular test started, relative to the start of the Test Suite.
|
|
|
|
std::chrono::milliseconds _startTimeMilliSeconds;
|
2016-04-09 11:30:48 -05:00
|
|
|
UnitType _type;
|
2020-12-20 21:11:33 -06:00
|
|
|
|
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
|
|
|
std::mutex _lock; //< Used to protect cleanup functions.
|
2021-04-12 23:48:47 -05:00
|
|
|
std::shared_ptr<SocketPoll> _socketPoll; //< Poll thread for async http comm.
|
2022-02-16 16:22:18 -06:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
/// The name of the current test. Accessed from logs in derived classes.
|
|
|
|
std::string testname;
|
2016-04-09 11:30:48 -05:00
|
|
|
};
|
|
|
|
|
2021-11-13 05:49:35 -06:00
|
|
|
struct TileData;
|
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
/// Derive your WSD unit test / hooks from me.
|
|
|
|
class UnitWSD : public UnitBase
|
|
|
|
{
|
|
|
|
bool _hasKitHooks;
|
2016-10-29 20:15:00 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
public:
|
2022-04-21 18:14:16 -05:00
|
|
|
UnitWSD(const std::string& testname);
|
2020-12-20 21:11:33 -06:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
virtual ~UnitWSD();
|
|
|
|
|
2021-09-14 10:05:31 -05:00
|
|
|
static UnitWSD& get();
|
2016-04-09 11:30:48 -05:00
|
|
|
|
2022-04-21 18:48:14 -05:00
|
|
|
/// Applies the default config.
|
|
|
|
/// This is needed to initialize the logging subsystem early.
|
|
|
|
static void defaultConfigure(Poco::Util::LayeredConfiguration& /* config */);
|
|
|
|
|
2016-12-22 03:27:30 -06:00
|
|
|
enum class TestRequest
|
2016-10-29 20:15:00 -05:00
|
|
|
{
|
2016-12-22 03:27:30 -06:00
|
|
|
Client,
|
|
|
|
Prisoner
|
2016-10-29 20:15:00 -05:00
|
|
|
};
|
2021-10-08 15:51:41 -05:00
|
|
|
|
2016-04-09 11:30:48 -05:00
|
|
|
/// Do we have hooks for the Kit too
|
|
|
|
bool hasKitHooks() { return _hasKitHooks; }
|
|
|
|
/// set in your unit if you want to be injected into the kit too.
|
2017-01-16 04:59:03 -06:00
|
|
|
void setHasKitHooks() { _hasKitHooks = true; }
|
2016-04-05 11:41:10 -05:00
|
|
|
|
2016-04-09 12:26:33 -05:00
|
|
|
// ---------------- WSD hooks ----------------
|
2016-04-07 15:59:27 -05:00
|
|
|
|
2016-04-16 13:37:38 -05:00
|
|
|
/// Manipulate and modify the configuration before any usage.
|
2022-04-21 18:48:14 -05:00
|
|
|
virtual void configure(Poco::Util::LayeredConfiguration& /* config */) {}
|
2020-12-24 11:15:37 -06:00
|
|
|
|
|
|
|
/// Main-loop reached, time for testing.
|
2021-11-18 06:08:14 -06:00
|
|
|
/// Invoked from coolwsd's main thread.
|
2020-12-24 11:15:37 -06:00
|
|
|
void invokeTest()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Invoke the test, expect no exceptions.
|
2022-11-18 18:07:44 -06:00
|
|
|
if (!isFinished())
|
|
|
|
{
|
|
|
|
invokeWSDTest();
|
|
|
|
}
|
2020-12-24 11:15:37 -06:00
|
|
|
}
|
2021-05-01 15:33:09 -05:00
|
|
|
catch (const Poco::Exception& ex)
|
|
|
|
{
|
|
|
|
LOG_ERR("ERROR: unexpected exception while invoking WSD Test: : "
|
|
|
|
<< ex.displayText()
|
|
|
|
<< (ex.nested() ? "( " + ex.nested()->displayText() + ')' : ""));
|
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
}
|
2020-12-24 11:15:37 -06:00
|
|
|
catch (const std::exception& ex)
|
|
|
|
{
|
|
|
|
LOG_TST("ERROR: unexpected exception while invoking WSD Test: " << ex.what());
|
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
LOG_TST("ERROR: unexpected unknown exception while invoking WSD Test");
|
|
|
|
exitTest(TestResult::Failed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 13:50:55 -05:00
|
|
|
/// When a new child kit process reports
|
2017-03-16 13:32:12 -05:00
|
|
|
virtual void newChild(WebSocketHandler &/* socket */) {}
|
2016-04-07 15:59:27 -05:00
|
|
|
/// Intercept createStorage
|
2016-10-14 05:09:43 -05:00
|
|
|
virtual bool createStorage(const Poco::URI& /* uri */,
|
|
|
|
const std::string& /* jailRoot */,
|
2016-04-07 15:59:27 -05:00
|
|
|
const std::string& /* jailPath */,
|
2017-01-13 06:52:08 -06:00
|
|
|
std::unique_ptr<StorageBase>& /* storage */)
|
2016-10-29 20:15:00 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-20 21:31:53 -05:00
|
|
|
/// Child sent a message
|
|
|
|
virtual bool filterChildMessage(const std::vector<char>& /* payload */)
|
2016-10-29 20:15:00 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-20 21:31:53 -05:00
|
|
|
|
2016-05-01 09:24:31 -05:00
|
|
|
// ---------------- TileCache hooks ----------------
|
|
|
|
/// Called before the lookupTile call returns. Should always be called to fire events.
|
2022-08-30 00:27:44 -05:00
|
|
|
virtual void 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
|
|
|
|
2016-10-20 16:09:00 -05:00
|
|
|
// ---------------- DocumentBroker hooks ----------------
|
2016-10-29 20:15:00 -05:00
|
|
|
virtual bool filterLoad(const std::string& /* sessionId */,
|
|
|
|
const std::string& /* jailId */,
|
|
|
|
bool& /* result */)
|
2016-10-20 16:09:00 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-03 04:59:39 -05:00
|
|
|
/// To force the save operation being handled as auto-save from a unit test.
|
|
|
|
virtual bool isAutosave()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-21 05:47:07 -05:00
|
|
|
/// hook and allow through clipboard authentication
|
|
|
|
virtual bool filterClipboardAuth(const std::string & /* serverId */, const std::string &/* tag */)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-17 08:54:05 -05:00
|
|
|
// ---------------- WSD events ----------------
|
|
|
|
virtual void onChildConnected(const int /* pid */, const std::string& /* sessionId */) {}
|
2016-04-18 08:29:17 -05:00
|
|
|
/// When admin notify message is sent
|
|
|
|
virtual void onAdminNotifyMessage(const std::string& /* message */) {}
|
|
|
|
/// When admin message is sent in response to a query
|
|
|
|
virtual void onAdminQueryMessage(const std::string& /* message */) {}
|
2016-05-01 09:24:31 -05:00
|
|
|
|
2022-02-15 16:45:20 -06:00
|
|
|
// ---------------- DocBroker events ----------------
|
|
|
|
|
|
|
|
/// Called when a DocumentBroker is created (from the constructor).
|
|
|
|
/// Useful to detect track the beginning of a document's life cycle.
|
|
|
|
virtual void onDocBrokerCreate(const std::string&) {}
|
|
|
|
|
2022-03-30 20:09:18 -05:00
|
|
|
/// Called when the Kit process is attached to a DocBroker.
|
|
|
|
virtual void onDocBrokerAttachKitProcess(const std::string&, int) {}
|
|
|
|
|
2022-02-15 16:45:20 -06:00
|
|
|
/// Called when a new client session is added to a DocumentBroker.
|
|
|
|
virtual void onDocBrokerAddSession(const std::string&, const std::shared_ptr<ClientSession>&) {}
|
|
|
|
|
|
|
|
/// Called when a client session is removed to a DocumentBroker.
|
|
|
|
virtual void onDocBrokerRemoveSession(const std::string&, const std::shared_ptr<ClientSession>&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-12-24 17:40:29 -06:00
|
|
|
protected:
|
2022-02-15 16:45:20 -06:00
|
|
|
/// Called when a DocumentBroker is destroyed (from the destructor).
|
|
|
|
/// Useful to detect when unloading was clean and to (re)load again.
|
|
|
|
virtual void onDocBrokerDestroy(const std::string&) {}
|
|
|
|
|
2022-12-24 17:40:29 -06:00
|
|
|
public:
|
|
|
|
/// Called when a DocumentBroker is destroyed (from the destructor).
|
|
|
|
/// Useful to detect when unloading was clean and to (re)load again.
|
|
|
|
/// Handle by overriding onDocBrokerDestroy.
|
|
|
|
void DocBrokerDestroy(const std::string&);
|
|
|
|
|
2022-04-04 21:36:05 -05:00
|
|
|
/// Called when a new view is loaded.
|
|
|
|
virtual void onDocBrokerViewLoaded(const std::string&, const std::shared_ptr<ClientSession>&) {}
|
|
|
|
|
2016-05-01 09:24:31 -05:00
|
|
|
// ---------------- TileCache events ----------------
|
2022-08-30 00:27:44 -05:00
|
|
|
virtual void onTileCacheHit(int /*part*/, int /*mode*/,
|
|
|
|
int /*width*/, int /*height*/,
|
2016-05-01 09:24:31 -05:00
|
|
|
int /*tilePosX*/, int /*tilePosY*/,
|
|
|
|
int /*tileWidth*/, int /*tileHeight*/) {}
|
2022-08-30 00:27:44 -05:00
|
|
|
virtual void onTileCacheMiss(int /*part*/, int /*mode*/,
|
|
|
|
int /*width*/, int /*height*/,
|
2016-05-01 09:24:31 -05:00
|
|
|
int /*tilePosX*/, int /*tilePosY*/,
|
|
|
|
int /*tileWidth*/, int /*tileHeight*/) {}
|
2022-08-30 00:27:44 -05:00
|
|
|
virtual void onTileCacheSubscribe(int /*part*/, int /*mode*/,
|
|
|
|
int /*width*/, int /*height*/,
|
2016-05-01 09:24:31 -05:00
|
|
|
int /*tilePosX*/, int /*tilePosY*/,
|
|
|
|
int /*tileWidth*/, int /*tileHeight*/) {}
|
2020-12-24 11:15:37 -06:00
|
|
|
private:
|
|
|
|
/// The actual test implementation.
|
|
|
|
virtual void invokeWSDTest() {}
|
2022-12-24 23:03:25 -06:00
|
|
|
|
|
|
|
void onExitTest(TestResult result, const std::string& reason = std::string()) override;
|
2016-04-09 11:30:48 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Derive your Kit unit test / hooks from me.
|
|
|
|
class UnitKit : public UnitBase
|
|
|
|
{
|
|
|
|
public:
|
2022-04-21 18:14:16 -05:00
|
|
|
explicit UnitKit(const std::string& testname);
|
2016-04-09 11:30:48 -05:00
|
|
|
virtual ~UnitKit();
|
2021-09-14 10:05:31 -05:00
|
|
|
static UnitKit& get();
|
2016-04-09 12:26:33 -05:00
|
|
|
|
|
|
|
// ---------------- ForKit hooks ----------------
|
|
|
|
|
|
|
|
/// main-loop reached, time for testing
|
|
|
|
virtual void invokeForKitTest() {}
|
|
|
|
|
2016-04-12 15:30:06 -05:00
|
|
|
/// Post fork hook - just after we fork to init the child kit
|
|
|
|
virtual void launchedKit(int /* pid */) {}
|
|
|
|
|
2016-04-09 12:26:33 -05:00
|
|
|
// ---------------- Kit hooks ----------------
|
|
|
|
|
|
|
|
/// Post fork hook - just before we init the child kit
|
|
|
|
virtual void postFork() {}
|
|
|
|
|
|
|
|
/// Kit got a message
|
2018-11-07 17:00:32 -06:00
|
|
|
virtual bool filterKitMessage(WebSocketHandler *, std::string &/* message */ )
|
2016-10-29 20:15:00 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-01 03:04:19 -05:00
|
|
|
|
2019-06-21 05:47:07 -05:00
|
|
|
/// LOKit (and some synthetic internal) callbacks
|
|
|
|
virtual bool filterLoKitCallback(const int /* type */, const std::string& /* payload */)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-01 03:04:19 -05:00
|
|
|
/// Allow a custom LibreOfficeKit wrapper
|
|
|
|
virtual LibreOfficeKit *lok_init(const char * /* instdir */,
|
|
|
|
const char * /* userdir */)
|
2016-10-29 20:15:00 -05:00
|
|
|
{
|
2016-12-22 08:04:07 -06:00
|
|
|
return nullptr;
|
2016-10-29 20:15:00 -05:00
|
|
|
}
|
2022-12-24 23:03:25 -06:00
|
|
|
|
|
|
|
private:
|
|
|
|
void onExitTest(TestResult result, const std::string& reason = std::string()) override;
|
2016-04-05 11:41:10 -05:00
|
|
|
};
|
|
|
|
|
2021-08-10 22:41:02 -05:00
|
|
|
/// Derive your Tool unit test / hooks from me.
|
|
|
|
class UnitTool : public UnitBase
|
|
|
|
{
|
|
|
|
public:
|
2022-04-21 18:14:16 -05:00
|
|
|
explicit UnitTool(const std::string& name)
|
|
|
|
: UnitBase(name, UnitType::Tool)
|
2022-03-30 22:17:16 -05:00
|
|
|
{
|
|
|
|
}
|
2022-12-24 23:03:25 -06:00
|
|
|
|
|
|
|
private:
|
|
|
|
void onExitTest(TestResult, const std::string& = std::string()) override {}
|
2021-08-10 22:41:02 -05:00
|
|
|
};
|
|
|
|
|
2021-11-26 17:09:16 -06:00
|
|
|
/// Transition the test state of VAR to STATE, with a prefix message, and resume the test.
|
|
|
|
/// This will wake up all polls and the new state may be processed in parallel.
|
|
|
|
#define TRANSITION_STATE_MSG(VAR, STATE, MSG) \
|
|
|
|
do \
|
|
|
|
{ \
|
2022-01-28 07:43:44 -06:00
|
|
|
LOG_TST(MSG << ' ' << name(VAR) << " -> " #STATE); \
|
2021-11-26 17:09:16 -06:00
|
|
|
VAR = STATE; \
|
|
|
|
SocketPoll::wakeupWorld(); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
/// Transition the test state of VAR to STATE and resume the test.
|
|
|
|
/// This will wake up all polls and the new state may be processed in parallel.
|
2022-01-28 07:43:44 -06:00
|
|
|
#define TRANSITION_STATE(VAR, STATE) TRANSITION_STATE_MSG(VAR, STATE, "Transitioning " #VAR " from")
|
|
|
|
|
|
|
|
#define LOK_ASSERT_STATE(VAR, STATE) \
|
|
|
|
LOK_ASSERT_MESSAGE("Expected " #VAR " to be in " #STATE " but was " + toString(VAR), \
|
2022-04-03 12:25:19 -05:00
|
|
|
VAR == STATE)
|
2021-11-26 17:09:16 -06:00
|
|
|
|
2016-04-05 11:41:10 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|