From 398ab9c7e29e4c8b75ccde2a62ddd492aeb5d45a Mon Sep 17 00:00:00 2001 From: heck Date: Sun, 4 Jul 2021 18:34:54 +0200 Subject: [PATCH] Test: PityTest - Abstract base for PityUnit This enables PityUnits of different context types in a single tree. --- src/AbstractPityUnit.cc | 468 +++++++++++++++++++++++++++++++++++++ src/AbstractPityUnit.hh | 156 +++++++++++++ src/PityTransport.cc | 6 +- src/PityUnit.hh | 122 +--------- src/PityUnit.hxx | 498 +--------------------------------------- 5 files changed, 642 insertions(+), 608 deletions(-) create mode 100644 src/AbstractPityUnit.cc create mode 100644 src/AbstractPityUnit.hh diff --git a/src/AbstractPityUnit.cc b/src/AbstractPityUnit.cc new file mode 100644 index 0000000..dce26a6 --- /dev/null +++ b/src/AbstractPityUnit.cc @@ -0,0 +1,468 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#include "AbstractPityUnit.hh" +#include "../../../src/std_utils.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pEp { + namespace PityTest11 { + // static + std::string AbstractPityUnit::_global_root_dir = "./pitytest_data/"; + // static + bool AbstractPityUnit::debug_log_enabled = false; + // static + int AbstractPityUnit::procUnitsCount = 0; + + AbstractPityUnit::AbstractPityUnit( + AbstractPityUnit *const parent, + const std::string &name, + ExecutionMode exec_mode) : + _parent{ parent }, + _name{ _normalizeName(name) }, _exec_mode{ exec_mode } + { + logger_debug.set_instancename(getPath()); + if (!_isRootUnit()) { + parent->_addChildUnit(*this); + // Inherit + procUnitNr = _parent->procUnitNr; + //Or update if procUnit + if (_isProcessUnit()) { + _createTransport(); + procUnitsCount++; + procUnitNr = procUnitsCount; + } + } else { + procUnitNr = procUnitsCount; + } + } + + std::string AbstractPityUnit::getName() const + { + return _name; + } + + // name is alphanumeric only (everything else will be replaced by an underscore) + // static + std::string AbstractPityUnit::_normalizeName(std::string name) + { + replace_if( + name.begin(), + name.end(), + [](char c) -> bool { return !isalnum(c); }, + '_'); + + return name; + } + + std::string AbstractPityUnit::getPath() const + { + std::string ret; + + if (!_isRootUnit()) { + ret = _parent->getPath() + "/" + getName(); + } else { + ret = getName(); + } + return ret; + } + + // For: + // RootUnit - "" + // ProcessUnit - ".../" + // When Process as dir. parent - "...//name" + // When no process as dir. parent - "...//.../name" + std::string AbstractPityUnit::getPathShort() const + { + std::string ret; + if (_isRootUnit()) { + ret = getName(); + } else { + if (_isProcessUnit()) { + ret += ".../" + getName(); + } else { + if (&(parentingProcessUnit()) == (_parent)) { + ret = parentingProcessUnit().getPathShort() + "/" + getName(); + } else { + ret = parentingProcessUnit().getPathShort() + "/.../" + getName(); + } + } + } + return ret; + } + + AbstractPityUnit *AbstractPityUnit::getParent() const + { + return _parent; + } + + // Every process has its own dir inside its rootUnitDir + // All other units inherit processDir from their Root/ProcessUnit + std::string AbstractPityUnit::processDir() + { + if (_isRootUnit()) { + return _rootUnitDir(); + } else { + if (_isProcessUnit()) { + return _rootUnitDir() + getName() + "/"; + } else { + return _parent->processDir(); + } + } + } + + // Every RootUnit has its own dir + std::string AbstractPityUnit::_rootUnitDir() + { + return getGlobalRootDir() + rootUnit()->getName() + "/"; + } + + // Every process has its own dir inside its rootUnitDir + // All other units inherit transportDir from their Root/ProcessUnit + std::string AbstractPityUnit::transportDir() + { + if (_isRootUnit()) { + throw std::runtime_error("No transport dir"); + } else { + if (_isProcessUnit()) { + return processDir() + "inbox/"; + } else { + return _parent->transportDir(); + } + } + } + + // static + void AbstractPityUnit::setGlobalRootDir(const std::string &dir) + { + AbstractPityUnit::_global_root_dir = dir; + } + + // static + std::string AbstractPityUnit::getGlobalRootDir() + { + return AbstractPityUnit::_global_root_dir; + } + + void AbstractPityUnit::run() + { + pEpLogClass("called"); + _log_mutex = std::make_shared("log.mutex"); + _log_mutex->release(); + + setenv("HOME", processDir().c_str(), true); + + if (_isRootUnit()) { + _init(); + } + + // Execute in fork and wait here until process ends + if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork + _executeInFork(std::bind(&AbstractPityUnit::_run, this), true); + // Execute in fork and go on, wait for process execution in the end + } else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { + _executeInFork(std::bind(&AbstractPityUnit::_run, this), false); + // Execute as normal function + } else if (_exec_mode == ExecutionMode::FUNCTION) { + _run(); + } else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { + throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); + } else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) { + throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); + } + + if (_isRootUnit()) { + _waitChildProcesses(); + } + } + + std::string AbstractPityUnit::to_string(bool recursive, int indent) + { + std::string ret; + std::stringstream builder; + builder << std::string(indent * 4, ' '); + + builder << getName(); + builder << " [ "; + builder << to_string(_exec_mode) << " - "; + builder << "\"" << processDir() << "\""; + builder << " ]"; + builder << std::endl; + ret = builder.str(); + + if (recursive) { + if (!_children.empty()) { + indent++; + for (const std::pair child : _children) { + ret += child.second.to_string(true, indent); + } + indent--; + } + } + return ret; + } + + std::string AbstractPityUnit::to_string(const ExecutionMode &emode) + { + switch (emode) { + case ExecutionMode::FUNCTION: + return "FUNCTION"; + case ExecutionMode::PROCESS_SEQUENTIAL: + return "PROC_SEQ"; + case ExecutionMode::PROCESS_PARALLEL: + return "PROC_PAR"; + case ExecutionMode::THREAD_SEQUENTIAL: + return "THREAD_S"; + case ExecutionMode::THREAD_PARALLEL: + return "THREAD_P"; + case ExecutionMode::INHERIT: + return "INHERIT"; + default: + return "UNDEFINED EXECUTION MODE"; + } + } + + void AbstractPityUnit::recreateDirsRecursively() + { + Utils::dir_recreate(processDir()); + if (!_children.empty()) { + for (const std::pair child : _children) { + child.second.recreateDirsRecursively(); + } + } + } + + void AbstractPityUnit::registerAsTransportEndpoint() + { + transportEndpoints().insert({ getName(), transportDir() }); + } + + Endpoints &AbstractPityUnit::transportEndpoints() + { + if (_isRootUnit()) { + return _transport_endpoints; + } else { + return rootUnit()->transportEndpoints(); + } + } + + void AbstractPityUnit::log(const std::string &msg) const + { + std::stringstream builder; + builder << "[ "; + builder << std::to_string(getpid()); + builder << " - "; + builder << getPathShort(); + builder << " ] - "; + builder << msg; + + _logRaw(builder.str()); + } + + void AbstractPityUnit::logH1(const std::string &msg) const + { + Adapter::pEpLog::logH1(msg, _termColor()); + } + + void AbstractPityUnit::logH2(const std::string &msg) const + { + Adapter::pEpLog::logH2(msg, _termColor()); + } + + void AbstractPityUnit::logH3(const std::string &msg) const + { + Adapter::pEpLog::logH3(msg, _termColor()); + } + + // PRIVATE --------------------------------------------------------------------------------- + void AbstractPityUnit::_init() + { + logH1("PityTest Starting..."); + _logRaw("RootUnit: " + getPathShort()); + _logRaw("GlobalRootDir: " + getGlobalRootDir()); + _logRaw("\nTestTree"); + _logRaw("--------"); + _logRaw(to_string()); + + logH3("INIT"); + Utils::dir_ensure(getGlobalRootDir()); + recreateDirsRecursively(); + logH3("INIT DONE"); + } + + void AbstractPityUnit::_run() + { + logH2(_status_string("STARTING")); + _runSelf(); + _runChildren(); + } + + void AbstractPityUnit::_runChildren() const + { + if (!_children.empty()) { + for (const std::pair child : _children) { + child.second.run(); + } + } + } + + void AbstractPityUnit::_executeInFork(std::function func, bool wait_child) const + { + pid_t pid; + pid = fork(); + if (pid == pid_t(0)) { + func(); + exit(0); + } else if (pid < pid_t(0)) { + throw std::runtime_error("Error forking"); + } + if (wait_child) { + _waitChildProcesses(); + } + } + + void AbstractPityUnit::_waitChildProcesses() const + { + int status; + pid_t pid; + while ((pid = wait(&status)) > 0) { + std::string color; + if (status == 0) { + color = "\033[1m\033[32m"; // Green + } else { + color = "\033[1m\033[31m"; // Red + } + logH3( + color + "PROCESS [ " + std::to_string((int)pid) + + " ] EXITED with status code: " + std::to_string(status) + + Utils::to_termcol(_termColor())); + } + } + + void AbstractPityUnit::_addChildUnit(AbstractPityUnit &unit) + { + _children.insert(std::pair(unit.getName(), unit)); + } + + bool AbstractPityUnit::_isProcessUnit() const + { + bool ret = false; + if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL || + _exec_mode == ExecutionMode::PROCESS_PARALLEL) { + ret = true; + } + return ret; + } + + bool AbstractPityUnit::_isRootUnit() const + { + if (_parent == nullptr) { + return true; + } else { + return false; + } + } + + AbstractPityUnit *AbstractPityUnit::rootUnit() + { + if (!_isRootUnit()) { + return _parent->rootUnit(); + } else { + return this; + } + } + + const AbstractPityUnit &AbstractPityUnit::parentingProcessUnit() const + { + if (_isRootUnit() || _isProcessUnit()) { + return *this; + } else { + return _parent->parentingProcessUnit(); + } + } + + + // Inherited (if null see parent recursively) + void AbstractPityUnit::_createTransport() + { + registerAsTransportEndpoint(); + _transport = std::make_shared(transportDir(), transportEndpoints()); + } + + // Inherited (if null see parent recursively) + PityTransport *AbstractPityUnit::transport() const + { + // pEpLogClass("called"); + PityTransport *ret = nullptr; + + if (_transport != nullptr) { + ret = _transport.get(); + } else { + if (!_isRootUnit()) { + ret = _parent->transport(); + } + } + return ret; + } + + + std::string AbstractPityUnit::_status_string(const std::string &msg) const + { + std::string ret; + ret = "[ " + to_string(_exec_mode) + ":" + std::to_string(getpid()) + " ] [ " + + getPathShort() + " ] [ " + msg + " ]"; + return ret; + } + + //static + Utils::Color AbstractPityUnit::_colForProcUnitNr(int procUnitNr) + { + int nrColors = 7; + switch (procUnitNr % nrColors) { + case 0: + return Utils::Color::WHITE; + case 1: + return Utils::Color::GREEN; + case 2: + return Utils::Color::YELLOW; + case 3: + return Utils::Color::CYAN; + case 4: + return Utils::Color::BLUE; + case 5: + return Utils::Color::MAGENTA; + case 6: + return Utils::Color::RED; + default: + return Utils::Color::WHITE; + } + } + + + Utils::Color AbstractPityUnit::_termColor() const + { + return _colForProcUnitNr(procUnitNr); + } + + void AbstractPityUnit::_logRaw(const std::string &msg) const + { + // fs-mutex to sync across processes + _log_mutex->aquire(); + Adapter::pEpLog::log(msg, _termColor()); + _log_mutex->release(); + } + + } // namespace PityTest11 +} // namespace pEp + diff --git a/src/AbstractPityUnit.hh b/src/AbstractPityUnit.hh new file mode 100644 index 0000000..4f664df --- /dev/null +++ b/src/AbstractPityUnit.hh @@ -0,0 +1,156 @@ +// This file is under GNU General Public License 3.0 +// see LICENSE.txt + +#ifndef PITYTEST_ABSTRACTPITYUNIT_HH +#define PITYTEST_ABSTRACTPITYUNIT_HH + +#include "../../../src/pEpLog.hh" +#include "../../../src/std_utils.hh" +#include "fs_mutex.hh" +#include "PityTransport.hh" +#include +#include +#include +#include +#include + +// Yes, the mem mgmt is purely static on purpose (so far) + +namespace pEp { + namespace PityTest11 { + class AbstractPityUnit { + public: + enum class ExecutionMode + { + FUNCTION, + PROCESS_SEQUENTIAL, + PROCESS_PARALLEL, + THREAD_SEQUENTIAL, // unimplemented + THREAD_PARALLEL, // unimplemented + INHERIT + }; + + AbstractPityUnit( + AbstractPityUnit* const parent, + const std::string& name, + ExecutionMode exec_mode = ExecutionMode::FUNCTION); + + // Read-Write + static void setGlobalRootDir(const std::string& dir); + static std::string getGlobalRootDir(); + + // Read-Only + std::string getName() const; + std::string getPath() const; + std::string getPathShort() const; + std::string processDir(); // own process dir + std::string transportDir(); + AbstractPityUnit* getParent() const; + bool _isRootUnit() const; // true if has no parent + + // Main funcs + void run(); + + std::string to_string(bool recursive = true, int indent = 0); + static std::string to_string(const ExecutionMode& emode); + + // logging service + void log(const std::string& msg) const; + void logH1(const std::string& msg) const; + void logH2(const std::string& msg) const; + void logH3(const std::string& msg) const; + + // Util + static std::string _normalizeName( + std::string name); //TODO HACK in PityTransport this should be private + void recreateDirsRecursively(); + + //Transport + PityTransport* transport() const; + void registerAsTransportEndpoint(); + Endpoints& transportEndpoints(); + + // internal logging + static bool debug_log_enabled; + Adapter::pEpLog::pEpLogger logger_debug{ "PityUnit", debug_log_enabled }; + + protected: + std::string _status_string(const std::string& msg) const; + static Utils::Color _colForProcUnitNr(int procUnitNr); + Utils::Color _termColor() const; + void _logRaw(const std::string& msg) const; + + // internal logging + Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; + + private: + // METHODS + // Execution + void _init(); + void _run(); + virtual void _runSelf() = 0; + void _runChildren() const; + void _executeInFork(std::function func, bool wait_child) const; + void _waitChildProcesses() const; + + + // Modify + void _addChildUnit(AbstractPityUnit& unit); + + AbstractPityUnit* rootUnit(); + const AbstractPityUnit& parentingProcessUnit() const; + + // Query + bool _isProcessUnit() const; // true if it forks + std::string _rootUnitDir(); + + // Transport + void _createTransport(); + + + // Fields + // ------ + AbstractPityUnit* _parent; //nullptr if RootUnit + std::map _children; // map to guarantee uniqueness of sibling-names + static std::string _global_root_dir; + const std::string _name; + int procUnitNr; + ExecutionMode _exec_mode; + static int procUnitsCount; // will be increased in every constructor + // transport + std::shared_ptr _transport; //only ever read via transport() + Endpoints _transport_endpoints; // only ever access via transportEndpoints() + + // fs-mutex to sync across processes + std::shared_ptr _log_mutex = nullptr; + }; + + class PityAssertException : public std::runtime_error { + public: + PityAssertException(const std::string& string) : runtime_error(string) {} + }; + +#ifndef PTASSERT + #define PTASSERT(condition, msg) \ + do { \ + if (!(condition)) { \ + throw PityAssertException(msg); \ + } \ + } while (0) +#endif + +#ifndef PTASSERT_EXCEPT + #define PTASSERT_EXCEPT(func) \ + do { \ + try { \ + (func); \ + PTASSERT(false); \ + } catch (const exception& e) { \ + } \ + } while (0) +#endif + + }; // namespace PityTest11 +}; // namespace pEp + +#endif diff --git a/src/PityTransport.cc b/src/PityTransport.cc index 8454651..8011054 100644 --- a/src/PityTransport.cc +++ b/src/PityTransport.cc @@ -22,14 +22,14 @@ namespace pEp { pEpLogClass("Address: " + nodename + " msg: " + msg); // HACK TODO - std::string nodename_normalize = PityUnit<>::_normalizeName(nodename); + std::string nodename_normalized = AbstractPityUnit::_normalizeName(nodename); bool found = false; std::string dir; try { - dir = _endpoints.at(nodename_normalize); + dir = _endpoints.at(nodename_normalized); } catch (std::out_of_range&) { - throw std::runtime_error("no such nodename: " + nodename_normalize); + throw std::runtime_error("no such nodename: " + nodename_normalized); } Utils::dir_ensure(dir); std::stringstream filename; diff --git a/src/PityUnit.hh b/src/PityUnit.hh index 7faffe3..1c02585 100644 --- a/src/PityUnit.hh +++ b/src/PityUnit.hh @@ -6,6 +6,7 @@ #include "../../../src/pEpLog.hh" #include "../../../src/std_utils.hh" +#include "AbstractPityUnit.hh" #include "fs_mutex.hh" #include "PityTransport.hh" #include @@ -14,150 +15,35 @@ #include #include -// Yes, the mem mgmt is purely static on purpose (so far) - namespace pEp { namespace PityTest11 { - template - class PityUnit { + class PityUnit : public AbstractPityUnit { public: // Test success if TestFunction: // * does not throw // * returns 0 using TestFunction = const std::function&, TestContext*)>; - enum class ExecutionMode - { - FUNCTION, - PROCESS_SEQUENTIAL, - PROCESS_PARALLEL, - THREAD_SEQUENTIAL, // unimplemented - THREAD_PARALLEL, // unimplemented - INHERIT - }; // Constructors are private PityUnit() = delete; explicit PityUnit( - PityUnit* parent, + AbstractPityUnit* const parent, const std::string& name, TestFunction test_func = nullptr, TestContext* perspective = nullptr, ExecutionMode exec_mode = ExecutionMode::FUNCTION); // Read-Only - std::string getName() const; - std::string getPath() const; - std::string getPathShort() const; - std::string processDir(); // own process dir - std::string transportDir(); - PityUnit* rootUnit(); TestContext* getPerspective() const; - const PityUnit& parentingProcessUnit() const; - - // Read-Write - static void setGlobalRootDir(const std::string& dir); - static std::string getGlobalRootDir(); - - // Main funcs - void run(); - std::string to_string(bool recursive = true, int indent = 0); - static std::string to_string(const ExecutionMode& emode); - - // Util - void recreateDirsRecursively(); - static std::string _normalizeName( - std::string name); //TODO HACK in PityTransport this should be private - - //Transport - PityTransport* transport() const; - void registerAsTransportEndpoint(); - Endpoints& transportEndpoints(); - - // logging service - void log(const std::string& msg) const; - void logH1(const std::string& msg) const; - void logH2(const std::string& msg) const; - void logH3(const std::string& msg) const; - - // internal logging - static bool debug_log_enabled; - Adapter::pEpLog::pEpLogger logger_debug{ "PityUnit", debug_log_enabled }; private: - // METHODS - // Execution - void _init(); - void _run(); void _runSelf(); - void _runChildren() const; - void _executeInFork(std::function func, bool wait_child) const; - void _waitChildProcesses() const; - - // Modify - void _addChildUnit(PityUnit& unit); - - // Transport - void _createTransport(); - - // Query - bool _isProcessUnit() const; // true if it forks - bool _isRootUnit() const; // true if has no parent - - std::string _rootUnitDir(); - - - // Util - std::string _status_string(const std::string& msg) const; - Utils::Color _colForProcUnitNr(int procUnitNr) const; - Utils::Color _termColor() const; - void _logRaw(const std::string& msg) const; // Fields - const std::string _name; - PityUnit* _parent; //nullptr if RootUnit - TestContext* _perspective; //nullptr if inherited + TestContext* _perspective; //nullptr if inherited TestFunction _test_func; - ExecutionMode _exec_mode; - static std::string _global_root_dir; - std::map&> _children; // map to guarantee uniqueness of sibling-names - int procUnitNr; - static int procUnitsCount; // will be increased in every constructor - std::shared_ptr _transport; //only ever read via transport() - Endpoints _transport_endpoints; // only ever access via transportEndpoints() - - // fs-mutex to sync across processes - std::shared_ptr _log_mutex = nullptr; - // internal logging - Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; }; - - class PityAssertException : public std::runtime_error { - public: - PityAssertException(const std::string& string) : runtime_error(string) {} - }; - - -#ifndef PTASSERT - #define PTASSERT(condition, msg) \ - do { \ - if (!(condition)) { \ - throw PityAssertException(msg); \ - } \ - } while (0) -#endif - -#ifndef PTASSERT_EXCEPT - #define PTASSERT_EXCEPT(func) \ - do { \ - try { \ - (func); \ - PTASSERT(false); \ - } catch (const exception& e) { \ - } \ - } while (0) -#endif - }; // namespace PityTest11 }; // namespace pEp diff --git a/src/PityUnit.hxx b/src/PityUnit.hxx index 6f9d271..c29c5b5 100644 --- a/src/PityUnit.hxx +++ b/src/PityUnit.hxx @@ -20,308 +20,17 @@ namespace pEp { namespace PityTest11 { - // static - template - std::string PityUnit::_global_root_dir = "./pitytest_data/"; - // static - template - bool PityUnit::debug_log_enabled = false; - // static - template - int PityUnit::procUnitsCount = 0; - - // CONSTRUCTOR - template - PityUnit::PityUnit( - PityUnit *const parent, - const std::string &name, - TestFunction test_func, - TestContext *perspective, - ExecutionMode exec_mode) : - _parent{ parent }, - _perspective{ perspective }, _name{ _normalizeName(name) }, _test_func{ test_func }, - _exec_mode{ exec_mode } - { - logger_debug.set_instancename(getPath()); - if (!_isRootUnit()) { - parent->_addChildUnit(*this); - // Inherit - procUnitNr = _parent->procUnitNr; - //Or update if procUnit - if (_isProcessUnit()) { - _createTransport(); - procUnitsCount++; - procUnitNr = procUnitsCount; - } - } else { - procUnitNr = procUnitsCount; - } - } - - template - std::string PityUnit::getName() const - { - return _name; - } - - template - std::string PityUnit::getPath() const - { - std::string ret; - - if (!_isRootUnit()) { - ret = _parent->getPath() + "/" + getName(); - } else { - ret = getName(); - } - return ret; - } - - // For: - // RootUnit - "" - // ProcessUnit - ".../" - // When Process as dir. parent - "...//name" - // When no process as dir. parent - "...//.../name" - template - std::string PityUnit::getPathShort() const - { - std::string ret; - if (_isRootUnit()) { - ret = getName(); - } else { - if (_isProcessUnit()) { - ret += ".../" + getName(); - } else { - if (&(parentingProcessUnit()) == (_parent)) { - ret = parentingProcessUnit().getPathShort() + "/" + getName(); - } else { - ret = parentingProcessUnit().getPathShort() + "/.../" + getName(); - } - } - } - return ret; - } - - - // Every RootUnit has its own dir - template - std::string PityUnit::_rootUnitDir() - { - return getGlobalRootDir() + rootUnit()->getName() + "/"; - } - - // Every process has its own dir inside its rootUnitDir - // All other units inherit processDir from their Root/ProcessUnit - template - std::string PityUnit::processDir() + // CONSTRUCTOR + template + PityUnit::PityUnit( + AbstractPityUnit *const parent, + const std::string &name, + TestFunction test_func, + TestContext *perspective, + ExecutionMode exec_mode) : + AbstractPityUnit(parent, name, exec_mode), + _perspective{ perspective }, _test_func{ test_func } { - if (_isRootUnit()) { - return _rootUnitDir(); - } else { - if (_isProcessUnit()) { - return _rootUnitDir() + getName() + "/"; - } else { - return _parent->processDir(); - } - } - } - - // Every process has its own dir inside its rootUnitDir - // All other units inherit transportDir from their Root/ProcessUnit - template - std::string PityUnit::transportDir() - { - if (_isRootUnit()) { - throw std::runtime_error("No transport dir"); - } else { - if (_isProcessUnit()) { - return processDir() + "inbox/"; - } else { - return _parent->transportDir(); - } - } - } - - // static - template - void PityUnit::setGlobalRootDir(const std::string &dir) - { - PityUnit::_global_root_dir = dir; - } - - // static - template - std::string PityUnit::getGlobalRootDir() - { - return PityUnit::_global_root_dir; - } - - template - void PityUnit::run() - { - pEpLogClass("called"); - _log_mutex = std::make_shared("log.mutex"); - _log_mutex->release(); - - setenv("HOME", processDir().c_str(), true); - - if (_isRootUnit()) { - _init(); - } - - // Execute in fork and wait here until process ends - if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork - _executeInFork(std::bind(&PityUnit::_run, this), true); - // Execute in fork and go on, wait for process execution in the end - } else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { - _executeInFork(std::bind(&PityUnit::_run, this), false); - // Execute as normal funciton - } else if (_exec_mode == ExecutionMode::FUNCTION) { - _run(); - } else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { - throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); - } else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) { - throw std::invalid_argument(to_string(_exec_mode) + " - not implemented"); - } - - if (_isRootUnit()) { - _waitChildProcesses(); - } - } - - template - std::string PityUnit::to_string(bool recursive, int indent) - { - std::string ret; - std::stringstream builder; - builder << std::string(indent * 4, ' '); - - builder << getName(); - builder << " [ "; - builder << to_string(_exec_mode) << " - "; - builder << "\"" << processDir() << "\""; - builder << " ]"; - builder << std::endl; - ret = builder.str(); - - if (recursive) { - if (!_children.empty()) { - indent++; - for (const std::pair &> child : _children) { - ret += child.second.to_string(true, indent); - } - indent--; - } - } - return ret; - } - - template - std::string PityUnit::to_string(const ExecutionMode &emode) - { - switch (emode) { - case ExecutionMode::FUNCTION: - return "FUNCTION"; - case ExecutionMode::PROCESS_SEQUENTIAL: - return "PROC_SEQ"; - case ExecutionMode::PROCESS_PARALLEL: - return "PROC_PAR"; - case ExecutionMode::THREAD_SEQUENTIAL: - return "THREAD_S"; - case ExecutionMode::THREAD_PARALLEL: - return "THREAD_P"; - case ExecutionMode::INHERIT: - return "INHERIT"; - default: - return "UNDEFINED EXECUTION MODE"; - } - } - - template - void PityUnit::recreateDirsRecursively() - { - Utils::dir_recreate(processDir()); - if (!_children.empty()) { - for (const std::pair &> child : _children) { - child.second.recreateDirsRecursively(); - } - } - } - - template - void PityUnit::registerAsTransportEndpoint() - { - transportEndpoints().insert({ getName(), transportDir() }); - } - - template - Endpoints &PityUnit::transportEndpoints() - { - if (_isRootUnit()) { - return _transport_endpoints; - } else { - return rootUnit()->transportEndpoints(); - } - } - - - template - void PityUnit::log(const std::string &msg) const - { - std::stringstream builder; - builder << "[ "; - builder << std::to_string(getpid()); - builder << " - "; - builder << getPathShort(); - builder << " ] - "; - builder << msg; - - _logRaw(builder.str()); - } - - - template - void PityUnit::logH1(const std::string &msg) const - { - Adapter::pEpLog::logH1(msg, _termColor()); - } - - template - void PityUnit::logH2(const std::string &msg) const - { - Adapter::pEpLog::logH2(msg, _termColor()); - } - - template - void PityUnit::logH3(const std::string &msg) const - { - Adapter::pEpLog::logH3(msg, _termColor()); - } - - - // PRIVATE --------------------------------------------------------------------------------- - template - void PityUnit::_init() - { - logH1("PityTest Starting..."); - _logRaw("RootUnit: " + getPathShort()); - _logRaw("GlobalRootDir: " + getGlobalRootDir()); - _logRaw("\nTestTree"); - _logRaw("--------"); - _logRaw(to_string()); - - logH3("INIT"); - Utils::dir_ensure(getGlobalRootDir()); - recreateDirsRecursively(); - logH3("INIT DONE"); - } - - template - void PityUnit::_run() - { - logH2(_status_string("STARTING")); - _runSelf(); - _runChildren(); } template @@ -340,103 +49,6 @@ namespace pEp { } } - template - void PityUnit::_runChildren() const - { - if (!_children.empty()) { - for (const std::pair &> child : _children) { - child.second.run(); - } - } - } - - template - void PityUnit::_executeInFork(std::function func, bool wait_child) const - { - pid_t pid; - pid = fork(); - if (pid == pid_t(0)) { - func(); - exit(0); - } else if (pid < pid_t(0)) { - throw std::runtime_error("Error forking"); - } - if (wait_child) { - _waitChildProcesses(); - } - } - - template - void PityUnit::_waitChildProcesses() const - { - int status; - pid_t pid; - while ((pid = wait(&status)) > 0) { - std::string color; - if(status == 0) { - color ="\033[1m\033[32m"; // Green - } else { - color ="\033[1m\033[31m"; // Red - } - logH3( - color + "PROCESS [ " + std::to_string((int)pid) + - " ] EXITED with status code: " + std::to_string(status) + - Utils::to_termcol(_termColor())); - } - } - - template - void PityUnit::_addChildUnit(PityUnit &unit) - { - _children.insert(std::pair &>(unit.getName(), unit)); - } - - template - bool PityUnit::_isProcessUnit() const - { - bool ret = false; - if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL || - _exec_mode == ExecutionMode::PROCESS_PARALLEL) { - ret = true; - } - return ret; - } - - template - bool PityUnit::_isRootUnit() const - { - if (_parent == nullptr) { - return true; - } else { - return false; - } - } - - template - PityUnit *PityUnit::rootUnit() - { - // const PityUnit* ret = nullptr; - if (!_isRootUnit()) { - return _parent->rootUnit(); - } else { - return this; - } - // assert(ret != nullptr); - // cant be null because for createChildUnit() you need to provide a TestUnit& and - // the only other way is using createRootUnit() which has parent == nullptr - // return *ret; - } - - template - const PityUnit &PityUnit::parentingProcessUnit() const - { - if (_isRootUnit() || _isProcessUnit()) { - return *this; - } else { - return _parent->parentingProcessUnit(); - } - } - // Inherited (if null see parent recursively) template TestContext *PityUnit::getPerspective() const @@ -448,99 +60,11 @@ namespace pEp { ret = _perspective; } else { if (!_isRootUnit()) { - ret = _parent->getPerspective(); + ret = (dynamic_cast *>(getParent()))->getPerspective(); } } return ret; } - - // Inherited (if null see parent recursively) - template - void PityUnit::_createTransport() - { - registerAsTransportEndpoint(); - _transport = std::make_shared(transportDir(), transportEndpoints()); - } - - // Inherited (if null see parent recursively) - template - PityTransport *PityUnit::transport() const - { - pEpLogClass("called"); - PityTransport *ret = nullptr; - - if (_transport.get() != nullptr) { - ret = _transport.get(); - } else { - if (!_isRootUnit()) { - ret = _parent->transport(); - } - } - return ret; - } - - // name is alphanumeric only (everything else will be replaced by an underscore) - // static - template - std::string PityUnit::_normalizeName(std::string name) - { - replace_if( - name.begin(), - name.end(), - [](char c) -> bool { return !isalnum(c); }, - '_'); - - return name; - } - - template - std::string PityUnit::_status_string(const std::string &msg) const - { - std::string ret; - ret = "[ " + to_string(_exec_mode) + ":" + std::to_string(getpid()) + " ] [ " + - getPathShort() + " ] [ " + msg + " ]"; - return ret; - } - - template - Utils::Color PityUnit::_colForProcUnitNr(int procUnitNr) const - { - int nrColors = 7; - switch (procUnitNr % nrColors) { - case 0: - return Utils::Color::WHITE; - case 1: - return Utils::Color::GREEN; - case 2: - return Utils::Color::YELLOW; - case 3: - return Utils::Color::CYAN; - case 4: - return Utils::Color::BLUE; - case 5: - return Utils::Color::MAGENTA; - case 6: - return Utils::Color::RED; - default: - return Utils::Color::WHITE; - } - } - - template - Utils::Color PityUnit::_termColor() const - { - return _colForProcUnitNr(procUnitNr); - } - - template - void PityUnit::_logRaw(const std::string &msg) const - { - // fs-mutex to sync across processes - _log_mutex->aquire(); - Adapter::pEpLog::log(msg, _termColor()); - _log_mutex->release(); - } - } // namespace PityTest11 } // namespace pEp