Browse Source

Test: pEpTestTree - made generic for the model type

LIB-11
heck 4 years ago
parent
commit
774022cb49
  1. 68
      test/pEpTest/src/pEpTestTree.hh
  2. 260
      test/pEpTest/src/pEpTestTree.hxx

68
test/pEpTest/src/pEpTestTree.hh

@ -8,12 +8,13 @@
#include <functional> #include <functional>
#include <map> #include <map>
#include "../../../src/pEpLog.hh" #include "../../../src/pEpLog.hh"
#include "pEpTestModel.hh" //#include "pEpTestModel.hh"
// Yes, the mem mgmt is purely static on purpose (so far) // Yes, the mem mgmt is purely static on purpose (so far)
namespace pEp { namespace pEp {
namespace Test { namespace Test {
template<class T = void>
class pEpTestTree { class pEpTestTree {
public: public:
using NodeFunc = std::function<void(const pEpTestTree&)>; using NodeFunc = std::function<void(const pEpTestTree&)>;
@ -21,42 +22,38 @@ namespace pEp {
enum class ExecutionMode enum class ExecutionMode
{ {
FUNCTION, FUNCTION,
PROCESS_SERIAL, PROCESS_SEQUENTIAL,
PROCESS_PARALLEL, PROCESS_PARALLEL,
THREAD_SERIAL, // unimplemented THREAD_SEQUENTIAL, // unimplemented
THREAD_PARALLEL, // unimplemented THREAD_PARALLEL, // unimplemented
INHERIT INHERIT
}; };
// Constructors are private // Constructors are private
pEpTestTree() = delete; pEpTestTree() = delete;
explicit pEpTestTree(
// Modify pEpTestTree* parent,
static pEpTestTree createRootNode(
pEpTestModel& model,
const std::string& name,
const NodeFunc& test_func,
ExecutionMode exec_mode = ExecutionMode::FUNCTION);
static pEpTestTree createChildNode(
pEpTestTree& parent,
const std::string& name, const std::string& name,
const NodeFunc& test_func, const NodeFunc test_func = nullptr,
T* model = nullptr,
ExecutionMode exec_mode = ExecutionMode::FUNCTION); ExecutionMode exec_mode = ExecutionMode::FUNCTION);
// Read-Only // Read-Only
std::string getNodeName() const; // name only std::string getNodeName() const;
std::string getNodePath() const; // full path (is an ID) std::string getNodePath() const;
std::string getNodePathShort() const; // parent process + name std::string getNodePathShort() const;
pEpTestModel& getModel() const; T* getModel() const;
std::string getDataDir() const; std::string rootNodeDir() const;
std::string processDir() const; // own process dir
// Read-Write // Read-Write
static void setDataRoot(const std::string& dir); void setExecutionMode(ExecutionMode mode);
static std::string getDataRoot(); static void setGlobalRootDir(const std::string& dir);
static std::string getGlobalRootDir();
// Main funcs // Main funcs
void run(const pEpTestTree* caller = nullptr) const; void run() const;
std::string to_string(bool recursive = true, int indent = 0) const; std::string to_string(bool recursive = true, int indent = 0) const;
static std::string to_string(const ExecutionMode& emode); static std::string to_string(const ExecutionMode& emode);
@ -68,17 +65,14 @@ namespace pEp {
Adapter::pEpLog::pEpLogger logger_debug{ "pEpTestTree", debug_log_enabled }; Adapter::pEpLog::pEpLogger logger_debug{ "pEpTestTree", debug_log_enabled };
private: private:
// CONSTRUCGTORS // CONSTRUCTORS
explicit pEpTestTree(
pEpTestTree* parent,
pEpTestModel* model,
const std::string& name,
const NodeFunc& test_func,
ExecutionMode exec_mode);
// METHODS // METHODS
// Execution // Execution
void _runRootNode() const;
void _run() const; void _run() const;
void _runSelf() const;
void _runChildren() const;
void _executeInFork(std::function<void(void)> func, bool wait_child) const; void _executeInFork(std::function<void(void)> func, bool wait_child) const;
void _waitChildProcesses() const; void _waitChildProcesses() const;
@ -88,8 +82,8 @@ namespace pEp {
// Query // Query
bool _isProcessNode() const; bool _isProcessNode() const;
bool _isRootNode() const; bool _isRootNode() const;
const pEpTestTree& _getRootNode() const; const pEpTestTree& _rootNode() const;
const pEpTestTree& _getParentingProcessNode() const; const pEpTestTree& _parentingProcessNode() const;
// Util // Util
std::string _normalizeName(std::string name) const; std::string _normalizeName(std::string name) const;
@ -102,10 +96,10 @@ namespace pEp {
// Fields // Fields
const std::string _name; const std::string _name;
const pEpTestTree* _parent; //nullptr if RootUnit const pEpTestTree* _parent; //nullptr if RootUnit
pEpTestModel* _model; //nullptr if inherited T* _model; //nullptr if inherited
const NodeFunc& _test_func; const NodeFunc _test_func;
const ExecutionMode _exec_mode; ExecutionMode _exec_mode;
static std::string _data_root; static std::string _global_root_dir;
std::map<const std::string, pEpTestTree&> _children; // map to guarantee uniqueness of sibling-names std::map<const std::string, pEpTestTree&> _children; // map to guarantee uniqueness of sibling-names
@ -115,4 +109,6 @@ namespace pEp {
}; // namespace Test }; // namespace Test
}; // namespace pEp }; // namespace pEp
#include "pEpTestTree.hxx"
#endif // LIBPEPADAPTER_PEPTEST_PEPTESTTREE_HH #endif // LIBPEPADAPTER_PEPTEST_PEPTESTTREE_HH

260
test/pEpTest/src/pEpTestTree.cc → test/pEpTest/src/pEpTestTree.hxx

@ -16,38 +16,36 @@ using namespace pEp::Utils;
namespace pEp { namespace pEp {
namespace Test { namespace Test {
string pEpTestTree::_data_root = "./peptest"; template<class T>
bool pEpTestTree::debug_log_enabled = false; string pEpTestTree<T>::_global_root_dir = "./peptest";
template<class T>
// PUBIC CONCSTRUCTORS / FACTORY ----------------------------------------------------------- bool pEpTestTree<T>::debug_log_enabled = false;
// static
pEpTestTree pEpTestTree::createRootNode( // PUBLIC CONCSTRUCTORS / FACTORY -----------------------------------------------------------
pEpTestModel& model, template<class T>
const string& name, pEpTestTree<T>::pEpTestTree(
const NodeFunc& test_func, pEpTestTree* const parent,
ExecutionMode exec_mode)
{
pEpTestTree ret(nullptr, &model, name, test_func, exec_mode);
return ret;
}
// static
pEpTestTree pEpTestTree::createChildNode(
pEpTestTree& parent,
const string& name, const string& name,
const NodeFunc& test_func, const NodeFunc test_func,
ExecutionMode exec_mode) T* model,
ExecutionMode exec_mode) :
_parent(parent),
_model(model), _name(_normalizeName(name)), _test_func(test_func), _exec_mode(exec_mode)
{ {
pEpTestTree ret(&parent, nullptr, name, test_func, exec_mode); logger_debug.set_instancename(getNodePath());
return ret; if (!_isRootNode()) {
parent->_addChildNode(*this);
}
} }
string pEpTestTree::getNodeName() const template<class T>
string pEpTestTree<T>::getNodeName() const
{ {
return _name; return _name;
} }
string pEpTestTree::getNodePath() const template<class T>
string pEpTestTree<T>::getNodePath() const
{ {
pEpLogClass("called"); pEpLogClass("called");
string ret; string ret;
@ -65,7 +63,8 @@ namespace pEp {
// ProcessNode - ".../<proc>" // ProcessNode - ".../<proc>"
// When Process as dir. parent - ".../<proc>/name" // When Process as dir. parent - ".../<proc>/name"
// When no process as dir. parent - ".../<proc>/.../name" // When no process as dir. parent - ".../<proc>/.../name"
std::string pEpTestTree::getNodePathShort() const template<class T>
std::string pEpTestTree<T>::getNodePathShort() const
{ {
string ret; string ret;
if (_isRootNode()) { if (_isRootNode()) {
@ -74,10 +73,10 @@ namespace pEp {
if (_isProcessNode()) { if (_isProcessNode()) {
ret += ".../" + getNodeName(); ret += ".../" + getNodeName();
} else { } else {
if (&(_getParentingProcessNode()) == (_parent)) { if (&(_parentingProcessNode()) == (_parent)) {
ret = _getParentingProcessNode().getNodePathShort() + "/" + getNodeName(); ret = _parentingProcessNode().getNodePathShort() + "/" + getNodeName();
} else { } else {
ret = _getParentingProcessNode().getNodePathShort() + "/.../" + getNodeName(); ret = _parentingProcessNode().getNodePathShort() + "/.../" + getNodeName();
} }
} }
} }
@ -85,94 +84,124 @@ namespace pEp {
} }
// Inherited (if null see parent recursively) // Inherited (if null see parent recursively)
pEpTestModel& pEpTestTree::getModel() const template<class T>
T* pEpTestTree<T>::getModel() const
{ {
pEpLogClass("called"); pEpLogClass("called");
pEpTestModel* ret = nullptr; T* ret = nullptr;
if (_model == nullptr) {
ret = &(_parent->getModel()); if (_model != nullptr) {
} else {
ret = _model; ret = _model;
} else {
if (!_isRootNode()) {
ret = _parent->getModel();
}
} }
assert(ret != nullptr); return ret;
// cant be null because for createChildNode() you have to provide TestNode& instance,
// and the only other way to get one is by createRootNode() which in turn requires a TestModel&
return *ret;
} }
// RootNodes have their own data_dir // RootNodes have their own data_dir
// ProcessNodes have their own data_dir inside their RootNote dir (nameclash prossible) // ProcessNodes have their own data_dir inside their RootNote dir (nameclash prossible)
// All other nodes inherit data_dir from their Root/ProcessNode // All other nodes inherit data_dir from their Root/ProcessNode
string pEpTestTree::getDataDir() const // string pEpTestTree::dataDir() const
// {
// pEpLogClass("called");
// string ret;
// if(!_isRootNode()) {
// ret = getRootNodesDir() + _getRootNode().getNodeName() + "/" + _getParentingProcessNode().getNodeName() + "/";
// } else {
// ret = getRootNodesDir() + _getRootNode().getNodeName() + "/";
// }
// return ret;
// }
//
// Every RootNode has its own dir
template<class T>
string pEpTestTree<T>::rootNodeDir() const
{
return getGlobalRootDir() + _rootNode().getNodeName() + "/";
}
// Every process has its own dir inside its rootNodeDir
// The Root node has its own processDir for future use
template<class T>
string pEpTestTree<T>::processDir() const
{ {
pEpLogClass("called");
string ret;
if (_isRootNode()) { if (_isRootNode()) {
ret = getDataRoot() + getNodeName() + "/"; return rootNodeDir() + "rootnode_data";
} else { } else {
if (_parent->_exec_mode == ExecutionMode::PROCESS_SERIAL || if (&_parentingProcessNode() == &_rootNode()) {
_parent->_exec_mode == ExecutionMode::PROCESS_PARALLEL) { return rootNodeDir() + getNodeName() + "/";
ret = _parent->getDataDir() + getNodeName();
} else { } else {
// inherit return rootNodeDir() + _parentingProcessNode().getNodeName() + "/";
ret = _parent->getDataDir(); };
}
} }
return ret;
} }
// static template<class T>
void pEpTestTree::setDataRoot(const string& dir) void pEpTestTree<T>::setExecutionMode(ExecutionMode mode)
{ {
pEpTestTree::_data_root = dir; _exec_mode = mode;
} }
// static // static
string pEpTestTree::getDataRoot() template<>
void pEpTestTree<void>::setGlobalRootDir(const string& dir)
{ {
return pEpTestTree::_data_root; pEpTestTree::_global_root_dir = dir;
} }
// static
template<class T>
string pEpTestTree<T>::getGlobalRootDir()
{
return pEpTestTree::_global_root_dir + "/";
}
void pEpTestTree::run(const pEpTestTree* caller) const template<class T>
void pEpTestTree<T>::run() const
{ {
pEpLogClass("called"); pEpLogClass("called");
// caller is never nullptr if called by another pEpTestTree // caller is never nullptr if called by another pEpTestTree
if (caller == nullptr) { if (_isRootNode()) {
pEpLog::logH1("Starting pEpTestTree from node: " + getNodePathShort()); pEpLog::logH1("Starting pEpTestTree from node: " + getNodePathShort());
pEpLog::log(to_string()); pEpLog::log(to_string());
} }
pEpLog::logH2(
"[ " + to_string(_exec_mode) + " / " + getNodePathShort() + "]");
// Execute in fork and wait here until process ends // Execute in fork and wait here until process ends
if (_exec_mode == ExecutionMode::PROCESS_SERIAL) { // fork if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork
pEpLog::logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + "]");
_executeInFork(bind(&pEpTestTree::_run, this), true); _executeInFork(bind(&pEpTestTree::_run, this), true);
// Execute in fork and go on, wait for process execution in the end // Execute in fork and go on, wait for process execution in the end
} else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { } else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) {
pEpLog::logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + "]");
_executeInFork(bind(&pEpTestTree::_run, this), false); _executeInFork(bind(&pEpTestTree::_run, this), false);
// Execute as normal funciton // Execute as normal funciton
} else if (_exec_mode == ExecutionMode::FUNCTION) { } else if (_exec_mode == ExecutionMode::FUNCTION) {
pEpLog::logH3("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + "]");
_run(); _run();
} else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { } else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) {
throw invalid_argument(to_string(_exec_mode) + " - not implemented"); throw invalid_argument(to_string(_exec_mode) + " - not implemented");
} else if (_exec_mode == ExecutionMode::THREAD_SERIAL) { } else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) {
throw invalid_argument(to_string(_exec_mode) + " - not implemented"); throw invalid_argument(to_string(_exec_mode) + " - not implemented");
} }
if (caller == nullptr) { _waitChildProcesses();
_waitChildProcesses();
}
} }
string pEpTestTree::to_string(bool recursive, int indent) const template<class T>
string pEpTestTree<T>::to_string(bool recursive, int indent) const
{ {
string ret; string ret;
stringstream builder; stringstream builder;
builder << string(indent, '\t'); builder << string(indent * 4, ' ');
builder << getNodeName(); builder << getNodeName();
builder << "[" << to_string(_exec_mode) << "]"; builder << " [ ";
builder << to_string(_exec_mode) << " - ";
builder << "\"" << processDir() << "\"";
builder << " ]";
builder << endl; builder << endl;
ret = builder.str(); ret = builder.str();
@ -186,19 +215,20 @@ namespace pEp {
return ret; return ret;
} }
string pEpTestTree::to_string(const ExecutionMode& emode) template<class T>
string pEpTestTree<T>::to_string(const ExecutionMode& emode)
{ {
switch (emode) { switch (emode) {
case ExecutionMode::FUNCTION: case ExecutionMode::FUNCTION:
return "FUNCTION"; return "FUNCTION";
case ExecutionMode::PROCESS_SERIAL: case ExecutionMode::PROCESS_SEQUENTIAL:
return "PROCESS_SERIAL"; return "PROC_SEQ";
case ExecutionMode::PROCESS_PARALLEL: case ExecutionMode::PROCESS_PARALLEL:
return "PROCESS_PARALLEL"; return "PROC_PAR";
case ExecutionMode::THREAD_SERIAL: case ExecutionMode::THREAD_SEQUENTIAL:
return "THREAD_SERIAL"; return "THREAD_S";
case ExecutionMode::THREAD_PARALLEL: case ExecutionMode::THREAD_PARALLEL:
return "THREAD_PARALLEL"; return "THREAD_P";
case ExecutionMode::INHERIT: case ExecutionMode::INHERIT:
return "INHERIT"; return "INHERIT";
default: default:
@ -207,7 +237,8 @@ namespace pEp {
} }
//Well, ok, lets just add some little convenience logging service in here, too //Well, ok, lets just add some little convenience logging service in here, too
void pEpTestTree::log(const string& msg) const template<class T>
void pEpTestTree<T>::log(const string& msg) const
{ {
stringstream builder; stringstream builder;
builder << "["; builder << "[";
@ -222,36 +253,35 @@ namespace pEp {
// PRIVATE --------------------------------------------------------------------------------- // PRIVATE ---------------------------------------------------------------------------------
pEpTestTree::pEpTestTree( template<class T>
pEpTestTree* const parent, void pEpTestTree<T>::_run() const
pEpTestModel* model,
const string& name,
const NodeFunc& test_func,
ExecutionMode exec_mode) :
_parent(parent),
_model(model), _name(_normalizeName(name)), _test_func(test_func), _exec_mode(exec_mode)
{ {
logger_debug.set_instancename(getNodePath()); _runSelf();
if (!_isRootNode()) { _runChildren();
parent->_addChildNode(*this);
}
} }
void pEpTestTree::_run() const template<class T>
void pEpTestTree<T>::_runSelf() const
{ {
if (_test_func) { if (_test_func != nullptr) {
_test_func(*this); _test_func(*this);
} else { } else {
pEpLog::log("No function to execute"); pEpLog::log("No function to execute");
} }
}
template<class T>
void pEpTestTree<T>::_runChildren() const
{
if (!_children.empty()) { if (!_children.empty()) {
for (const pair<string, pEpTestTree&> child : _children) { for (const pair<string, pEpTestTree&> child : _children) {
child.second.run(this); child.second.run();
} }
} }
} }
void pEpTestTree::_executeInFork(function<void(void)> func, bool wait_child) const template<class T>
void pEpTestTree<T>::_executeInFork(function<void(void)> func, bool wait_child) const
{ {
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
@ -266,7 +296,8 @@ namespace pEp {
} }
} }
void pEpTestTree::_waitChildProcesses() const template<class T>
void pEpTestTree<T>::_waitChildProcesses() const
{ {
int status; int status;
pid_t pid; pid_t pid;
@ -277,35 +308,39 @@ namespace pEp {
} }
} }
void pEpTestTree::_addChildNode(pEpTestTree& node) template<class T>
void pEpTestTree<T>::_addChildNode(pEpTestTree& node)
{ {
_children.insert(pair<string, pEpTestTree&>(node.getNodeName(), node)); _children.insert(pair<string, pEpTestTree&>(node.getNodeName(), node));
} }
bool pEpTestTree::_isProcessNode() const template<class T>
bool pEpTestTree<T>::_isProcessNode() const
{ {
bool ret = false; bool ret = false;
if (_exec_mode == ExecutionMode::PROCESS_SERIAL || if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL ||
_exec_mode == ExecutionMode::PROCESS_PARALLEL) { _exec_mode == ExecutionMode::PROCESS_PARALLEL) {
ret = true; ret = true;
} }
return ret; return ret;
} }
bool pEpTestTree::_isRootNode() const template<class T>
bool pEpTestTree<T>::_isRootNode() const
{ {
bool ret = false;
if (_parent == nullptr) { if (_parent == nullptr) {
ret = true; return true;
} else {
return false;
} }
return ret;
} }
const pEpTestTree& pEpTestTree::_getRootNode() const template<class T>
const pEpTestTree<T>& pEpTestTree<T>::_rootNode() const
{ {
const pEpTestTree* ret = nullptr; const pEpTestTree* ret = nullptr;
if (!_isRootNode()) { if (!_isRootNode()) {
ret = &(_parent->_getRootNode()); ret = &(_parent->_rootNode());
} else { } else {
ret = this; ret = this;
} }
@ -315,17 +350,19 @@ namespace pEp {
return *ret; return *ret;
} }
const pEpTestTree& pEpTestTree::_getParentingProcessNode() const template<class T>
const pEpTestTree<T>& pEpTestTree<T>::_parentingProcessNode() const
{ {
if (_isRootNode() || _isProcessNode()) { if (_isRootNode() || _isProcessNode()) {
return *this; return *this;
} else { } else {
return _parent->_getParentingProcessNode(); return _parent->_parentingProcessNode();
} }
} }
// name is alphanumeric only (everything else will be replaced by an underscore) // name is alphanumeric only (everything else will be replaced by an underscore)
string pEpTestTree::_normalizeName(string name) const template<class T>
string pEpTestTree<T>::_normalizeName(string name) const
{ {
replace_if( replace_if(
name.begin(), name.begin(),
@ -336,22 +373,25 @@ namespace pEp {
return name; return name;
} }
void pEpTestTree::_data_dir_create() template<class T>
void pEpTestTree<T>::_data_dir_create()
{ {
// Utils::dir_create(getDataDir()); // Utils::dir_create(dataDir());
pEpLog::log("creating dir:" + getDataRoot()); pEpLog::log("creating dir:" + getGlobalRootDir());
} }
void pEpTestTree::_data_dir_delete() template<class T>
void pEpTestTree<T>::_data_dir_delete()
{ {
try { try {
Utils::path_delete_all(getDataRoot()); Utils::path_delete_all(getGlobalRootDir());
} catch (const exception& e) { } catch (const exception& e) {
pEpLog::log("DistTest: - could not delete data dir: " + getDataRoot()); pEpLog::log("DistTest: - could not delete data dir: " + getGlobalRootDir());
} }
} }
void pEpTestTree::_data_dir_recreate() template<class T>
void pEpTestTree<T>::_data_dir_recreate()
{ {
_data_dir_delete(); _data_dir_delete();
_data_dir_create(); _data_dir_create();
Loading…
Cancel
Save