loolwsd/LOOLForKit.cpp | 19 +++++++ loolwsd/LOOLWSD.cpp | 17 ++++--- loolwsd/Makefile.am | 2 loolwsd/Storage.cpp | 2 loolwsd/Unit.cpp | 93 +++++++++++++++++++++++++++++--------- loolwsd/Unit.hpp | 103 ++++++++++++++++++++++++++++++------------- loolwsd/test/UnitPrefork.cpp | 4 - loolwsd/test/UnitStorage.cpp | 8 +-- loolwsd/test/UnitTimeout.cpp | 20 +++++++- 9 files changed, 197 insertions(+), 71 deletions(-)
New commits: commit b308792801f18eabfb6a62e3cbd2f59e38faa23c Author: Michael Meeks <michael.me...@collabora.com> Date: Sat Apr 9 17:30:48 2016 +0100 Add infrastructure to inject test pieces into loolforkit. diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp index e6f6c15..5529bc7 100644 --- a/loolwsd/LOOLForKit.cpp +++ b/loolwsd/LOOLForKit.cpp @@ -31,6 +31,7 @@ #include "IoUtil.hpp" #include "LOOLKit.hpp" #include "Util.hpp" +#include "Unit.hpp" #include "ChildProcessSession.hpp" using Poco::Path; @@ -40,6 +41,7 @@ using Poco::Thread; using Poco::Timestamp; using Poco::Util::Application; +static std::string UnitTestLibrary; static std::atomic<unsigned> ForkCounter( 0 ); static int pipeFd = -1; @@ -181,6 +183,11 @@ int main(int argc, char** argv) eq = std::strchr(cmd, '='); ClientPortNumber = std::stoll(std::string(eq+1)); } + else if (std::strstr(cmd, "--unitlib=") == cmd) + { + eq = std::strchr(cmd, '='); + UnitTestLibrary = std::string(eq+1); + } } if (loSubPath.empty() || sysTemplate.empty() || @@ -190,6 +197,13 @@ int main(int argc, char** argv) return 1; } + if (!UnitBase::init(UnitBase::UnitType::TYPE_KIT, + UnitTestLibrary)) + { + Log::error("Failed to load kit unit test library"); + return Application::EXIT_USAGE; + } + if (!std::getenv("LD_BIND_NOW")) Log::info("Note: LD_BIND_NOW is not set."); @@ -256,8 +270,11 @@ int main(int argc, char** argv) close(pipeFd); + int returnValue = Application::EXIT_OK; + UnitKit::get().returnValue(returnValue); + Log::info("ForKit process finished."); - return Application::EXIT_OK; + return returnValue; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index b8becd1..b70d110 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -165,7 +165,7 @@ static void preForkChildren() { std::unique_lock<std::mutex> lock(newChildrenMutex); int numPreSpawn = LOOLWSD::NumPreSpawnedChildren; - UnitHooks::get().preSpawnCount(numPreSpawn); + UnitWSD::get().preSpawnCount(numPreSpawn); forkChildren(numPreSpawn); } @@ -676,7 +676,7 @@ public: newChildren.emplace_back(std::make_shared<ChildProcess>(pid, ws)); Log::info("Have " + std::to_string(newChildren.size()) + " children."); newChildrenCV.notify_one(); - UnitHooks::get().newChild(); + UnitWSD::get().newChild(); return; } @@ -1231,6 +1231,8 @@ Process::PID LOOLWSD::createForKit() args.push_back("--lotemplate=" + LoTemplate); args.push_back("--childroot=" + ChildRoot); args.push_back("--clientport=" + std::to_string(ClientPortNumber)); + if (UnitWSD::get().hasKitHooks()) + args.push_back("--unitlib=" + UnitTestLibrary); const std::string forKitPath = Path(Application::instance().commandPath()).parent().toString() + "loolforkit"; @@ -1252,9 +1254,10 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) return Application::EXIT_USAGE; } - if (!UnitHooks::init(UnitTestLibrary)) + if (!UnitWSD::init(UnitWSD::UnitType::TYPE_WSD, + UnitTestLibrary)) { - Log::error("Failed to load unit test library"); + Log::error("Failed to load wsd unit test library"); return Application::EXIT_USAGE; } #ifdef ENABLE_SSL @@ -1416,7 +1419,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) int status = 0; while (!TerminationFlag && !LOOLWSD::DoTest) { - UnitHooks::get().invokeTest(); + UnitWSD::get().invokeTest(); const pid_t pid = waitpid(forKitPid, &status, WUNTRACED | WNOHANG); if (pid > 0) @@ -1570,12 +1573,12 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) Log::info("Process [loolwsd] finished."); int returnValue = Application::EXIT_OK; - UnitHooks::get().returnValue(returnValue); + UnitWSD::get().returnValue(returnValue); return returnValue; } -void UnitHooks::testHandleRequest(TestRequest type, UnitHTTPServerRequest& request, UnitHTTPServerResponse& response) +void UnitWSD::testHandleRequest(TestRequest type, UnitHTTPServerRequest& request, UnitHTTPServerResponse& response) { switch (type) { diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index 943331c..c35b39c 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -15,6 +15,7 @@ shared_sources = ChildProcessSession.cpp \ LOOLProtocol.cpp \ LOOLSession.cpp \ MessageQueue.cpp \ + Unit.cpp \ Util.cpp loolwsd_SOURCES = Admin.cpp \ @@ -25,7 +26,6 @@ loolwsd_SOURCES = Admin.cpp \ MasterProcessSession.cpp \ Storage.cpp \ TileCache.cpp \ - Unit.cpp \ $(shared_sources) noinst_PROGRAMS = connect \ diff --git a/loolwsd/Storage.cpp b/loolwsd/Storage.cpp index 849148c..1d17599 100644 --- a/loolwsd/Storage.cpp +++ b/loolwsd/Storage.cpp @@ -56,7 +56,7 @@ std::unique_ptr<StorageBase> StorageBase::create(const std::string& jailRoot, co { std::unique_ptr<StorageBase> storage; - if (UnitHooks::get().createStorage(jailRoot, jailPath, uri, storage)) + if (UnitWSD::get().createStorage(jailRoot, jailPath, uri, storage)) Log::info("Storage load hooked"); else if (uri.isRelative() || uri.getScheme() == "file") { diff --git a/loolwsd/Unit.cpp b/loolwsd/Unit.cpp index abafa12..1c4f5fa 100644 --- a/loolwsd/Unit.cpp +++ b/loolwsd/Unit.cpp @@ -16,11 +16,11 @@ #include <Poco/Thread.h> #include <Poco/Util/Application.h> -UnitHooks *UnitHooks::_global = nullptr; +UnitBase *UnitBase::_global = nullptr; static Poco::Thread TimeoutThread("unit timeout"); -UnitHooks *UnitHooks::linkAndCreateUnit(const std::string &unitLibPath) +UnitBase *UnitBase::linkAndCreateUnit(UnitType type, const std::string &unitLibPath) { void *dlHandle = dlopen(unitLibPath.c_str(), RTLD_GLOBAL|RTLD_NOW); if (!dlHandle) @@ -29,14 +29,24 @@ UnitHooks *UnitHooks::linkAndCreateUnit(const std::string &unitLibPath) return NULL; } + const char *symbol = NULL; + switch (type) + { + case TYPE_WSD: + symbol = "unit_create_wsd"; + break; + case TYPE_KIT: + symbol = "unit_create_kit"; + break; + } CreateUnitHooksFunction* createHooks; - createHooks = (CreateUnitHooksFunction *)dlsym(dlHandle, CREATE_UNIT_HOOKS_SYMBOL); + createHooks = reinterpret_cast<CreateUnitHooksFunction *>(dlsym(dlHandle, symbol)); if (!createHooks) { - Log::error("No " CREATE_UNIT_HOOKS_SYMBOL " symbol in " + unitLibPath); + Log::error("No " + std::string(symbol) + " symbol in " + unitLibPath); return NULL; } - UnitHooks *pHooks = createHooks(); + UnitBase *pHooks = createHooks(); if (pHooks) pHooks->setHandle(dlHandle); @@ -44,40 +54,62 @@ UnitHooks *UnitHooks::linkAndCreateUnit(const std::string &unitLibPath) return pHooks; } -bool UnitHooks::init(const std::string &unitLibPath) +bool UnitBase::init(UnitType type, const std::string &unitLibPath) { + assert(!_global); if (!unitLibPath.empty()) { - _global = linkAndCreateUnit(unitLibPath); - TimeoutThread.startFunc([](){ - TimeoutThread.trySleep(_global->_timeoutMilliSeconds); - if (!_global->_timeoutShutdown) - { - Log::error("Timeout"); - _global->timeout(); - } - }); + _global = linkAndCreateUnit(type, unitLibPath); + if (_global) + { + TimeoutThread.startFunc([](){ + TimeoutThread.trySleep(_global->_timeoutMilliSeconds); + if (!_global->_timeoutShutdown) + { + Log::error("Timeout"); + _global->timeout(); + } + }); + } } else - _global = new UnitHooks(); + { + switch (type) + { + case TYPE_WSD: + _global = new UnitWSD(); + break; + case TYPE_KIT: + _global = new UnitKit(); + break; + default: + assert(false); + break; + } + } + + if (_global) + _global->_type = type; return _global != NULL; } -void UnitHooks::setTimeout(int timeoutMilliSeconds) +void UnitBase::setTimeout(int timeoutMilliSeconds) { assert(!TimeoutThread.isRunning()); _timeoutMilliSeconds = timeoutMilliSeconds; } -UnitHooks::UnitHooks() +UnitBase::UnitBase() : _dlHandle(NULL), + _setRetValue(false), + _retValue(0), _timeoutMilliSeconds(30 * 1000), _timeoutShutdown(false) { } -UnitHooks::~UnitHooks() +UnitBase::~UnitBase() { // FIXME: we should really clean-up properly. // if (_dlHandle) @@ -85,7 +117,24 @@ UnitHooks::~UnitHooks() _dlHandle = NULL; } -void UnitHooks::exitTest(TestResult result) +UnitWSD::UnitWSD() + : _hasKitHooks(false) +{ +} + +UnitWSD::~UnitWSD() +{ +} + +UnitKit::UnitKit() +{ +} + +UnitKit::~UnitKit() +{ +} + +void UnitBase::exitTest(TestResult result) { _setRetValue = true; _retValue = result == TestResult::TEST_OK ? @@ -94,12 +143,12 @@ void UnitHooks::exitTest(TestResult result) TerminationFlag = true; } -void UnitHooks::timeout() +void UnitBase::timeout() { exitTest(TestResult::TEST_TIMED_OUT); } -void UnitHooks::returnValue(int &retValue) +void UnitBase::returnValue(int &retValue) { if (_setRetValue) retValue = _retValue; diff --git a/loolwsd/Unit.hpp b/loolwsd/Unit.hpp index 0a16d34..7e11a33 100644 --- a/loolwsd/Unit.hpp +++ b/loolwsd/Unit.hpp @@ -12,55 +12,88 @@ #include <string> #include <memory> #include <atomic> +#include <assert.h> -class UnitHooks; +class UnitBase; +class UnitWSD; +class UnitKit; class UnitTimeout; class UnitHTTPServerRequest; class UnitHTTPServerResponse; class StorageBase; -#define CREATE_UNIT_HOOKS_SYMBOL "unit_create" -typedef UnitHooks *(CreateUnitHooksFunction)(); -extern "C" { UnitHooks *unit_create(void); } +typedef UnitBase *(CreateUnitHooksFunction)(); +extern "C" { UnitBase *unit_create_wsd(void); } +extern "C" { UnitBase *unit_create_kit(void); } -/// Derive your unit test / hooks from me. -class UnitHooks +/// Derive your WSD unit test / hooks from me. +class UnitBase { friend UnitTimeout; + friend UnitWSD; + friend UnitKit; - void *_dlHandle; - bool _setRetValue; - int _retValue; - int _timeoutMilliSeconds; - std::atomic<bool> _timeoutShutdown; - static UnitHooks *_global; - - void setHandle(void *dlHandle) { _dlHandle = dlHandle; } - static UnitHooks *linkAndCreateUnit(const std::string &unitLibPath); protected: - // ---------------- Helper API ---------------- - /// After this time we invoke 'timeout' default 30 seconds void setTimeout(int timeoutMilliSeconds); + /// If the test times out this gets invoked, the default just exits. + virtual void timeout(); + enum TestResult { TEST_FAILED, TEST_OK, TEST_TIMED_OUT }; - /// Encourages loolwsd to exit with this value (unless hooked) + + /// Encourages the process to exit with this value (unless hooked) void exitTest(TestResult result); + UnitBase(); + virtual ~UnitBase(); + +public: + enum UnitType { TYPE_WSD, TYPE_KIT }; + /// Load unit test hook shared library from this path + static bool init(UnitType type, const std::string &unitLibPath); + + /// Tweak the return value from the process. + virtual void returnValue(int & /* retValue */); + +private: + void setHandle(void *dlHandle) { _dlHandle = dlHandle; } + static UnitBase *linkAndCreateUnit(UnitType type, const std::string &unitLibPath); + + void *_dlHandle; + bool _setRetValue; + int _retValue; + int _timeoutMilliSeconds; + std::atomic<bool> _timeoutShutdown; + static UnitBase *_global; + UnitType _type; +}; + +/// Derive your WSD unit test / hooks from me. +class UnitWSD : public UnitBase +{ + bool _hasKitHooks; +public: + UnitWSD(); + virtual ~UnitWSD(); + + static UnitWSD &get() + { + assert (_global && _global->_type == UnitType::TYPE_WSD); + return *static_cast<UnitWSD *>(_global); + } + enum TestRequest { TEST_REQ_CLIENT, TEST_REQ_PRISONER }; /// Simulate an incoming request void testHandleRequest(TestRequest type, UnitHTTPServerRequest& request, UnitHTTPServerResponse& response); - -public: - UnitHooks(); - virtual ~UnitHooks(); - static UnitHooks &get() { return *_global; } - /// Load unit test hook shared library from this path - static bool init(const std::string &unitLibPath); + /// 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. + void setHasKitHooks(bool hasHooks) { _hasKitHooks = hasHooks; } // ---------------- Hooks ---------------- @@ -68,17 +101,27 @@ public: virtual void invokeTest() {} /// Tweak the count of pre-spawned kits. virtual void preSpawnCount(int & /* numPrefork */) {} - /// Tweak the return value from LOOLWSD. - virtual void returnValue(int & /* retValue */); /// When a new child kit process reports virtual void newChild() {} - /// If the test times out this gets invoked, default exits. - virtual void timeout(); /// Intercept createStorage virtual bool createStorage(const std::string& /* jailRoot */, const std::string& /* jailPath */, const Poco::URI& /* uri */, - std::unique_ptr<StorageBase> & /*rStorage */) { return false; } + std::unique_ptr<StorageBase> & /*rStorage */) + { return false; } +}; + +/// Derive your Kit unit test / hooks from me. +class UnitKit : public UnitBase +{ +public: + UnitKit(); + virtual ~UnitKit(); + static UnitKit &get() + { + assert (_global && _global->_type == UnitType::TYPE_KIT); + return *static_cast<UnitKit *>(_global); + } }; #endif diff --git a/loolwsd/test/UnitPrefork.cpp b/loolwsd/test/UnitPrefork.cpp index 4133468..6094b0c 100644 --- a/loolwsd/test/UnitPrefork.cpp +++ b/loolwsd/test/UnitPrefork.cpp @@ -18,7 +18,7 @@ #include <Poco/Timestamp.h> using Poco::Timestamp; -class UnitPrefork : public UnitHooks +class UnitPrefork : public UnitWSD { int _numStarted; const int _numToPrefork; @@ -48,7 +48,7 @@ public: } }; -UnitHooks *unit_create(void) +UnitBase *unit_create_wsd(void) { return new UnitPrefork(); } diff --git a/loolwsd/test/UnitStorage.cpp b/loolwsd/test/UnitStorage.cpp index 91989f4..eba5f74 100644 --- a/loolwsd/test/UnitStorage.cpp +++ b/loolwsd/test/UnitStorage.cpp @@ -16,7 +16,7 @@ #include "Unit.hpp" #include "UnitHTTP.hpp" -class UnitStorage : public UnitHooks +class UnitStorage : public UnitWSD { public: virtual bool createStorage(const std::string& /* jailRoot */, @@ -33,12 +33,12 @@ public: exitTest(TestResult::TEST_OK); UnitHTTPServerResponse response; UnitHTTPServerRequest request(response, std::string(CHILD_URI)); - UnitHooks::testHandleRequest(TestRequest::TEST_REQ_PRISONER, - request, response); + UnitWSD::testHandleRequest(TestRequest::TEST_REQ_PRISONER, + request, response); } }; -UnitHooks *unit_create(void) +UnitBase *unit_create_wsd(void) { return new UnitStorage(); } diff --git a/loolwsd/test/UnitTimeout.cpp b/loolwsd/test/UnitTimeout.cpp index 7c400b5..f29bf73 100644 --- a/loolwsd/test/UnitTimeout.cpp +++ b/loolwsd/test/UnitTimeout.cpp @@ -19,7 +19,7 @@ #include <Poco/Util/Application.h> using Poco::Timestamp; -class UnitTimeout : public UnitHooks +class UnitTimeout : public UnitWSD { std::atomic<bool> _timedOut; public: @@ -31,7 +31,7 @@ public: virtual void timeout() override { _timedOut = true; - UnitHooks::timeout(); + UnitBase::timeout(); } virtual void returnValue(int & retValue) override { @@ -48,10 +48,24 @@ public: retValue = Poco::Util::Application::EXIT_OK; } } + + // sanity check the non-unit-test paths + static void testDefaultKits() + { + bool madeWSD = init(UnitType::TYPE_WSD, std::string()); + assert(madeWSD); + delete UnitBase::_global; + UnitBase::_global = NULL; + bool madeKit = init(UnitType::TYPE_KIT, std::string()); + assert(madeKit); + delete UnitBase::_global; + UnitBase::_global = NULL; + } }; -UnitHooks *unit_create(void) +UnitBase *unit_create_wsd(void) { + UnitTimeout::testDefaultKits(); return new UnitTimeout(); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits