
6 changed files with 530 additions and 518 deletions
@ -0,0 +1,360 @@ |
|||
#include "pEpTestTree.hh" |
|||
#include "../../../src/std_utils.hh" |
|||
#include "../../framework/utils.hh" |
|||
#include <iostream> |
|||
#include <unistd.h> |
|||
#include <cstdlib> |
|||
#include <sys/stat.h> |
|||
#include <functional> |
|||
#include <algorithm> |
|||
#include <sstream> |
|||
|
|||
|
|||
using namespace std; |
|||
using namespace pEp::Adapter; |
|||
using namespace pEp::Utils; |
|||
|
|||
namespace pEp { |
|||
namespace Test { |
|||
string pEpTestTree::_data_root = "./peptest"; |
|||
bool pEpTestTree::debug_log_enabled = false; |
|||
|
|||
// PUBIC CONCSTRUCTORS / FACTORY -----------------------------------------------------------
|
|||
// static
|
|||
pEpTestTree pEpTestTree::createRootNode( |
|||
pEpTestModel& model, |
|||
const string& name, |
|||
const NodeFunc& test_func, |
|||
ExecutionMode exec_mode) |
|||
{ |
|||
pEpTestTree ret(nullptr, &model, name, test_func, exec_mode); |
|||
return ret; |
|||
} |
|||
|
|||
// static
|
|||
pEpTestTree pEpTestTree::createChildNode( |
|||
pEpTestTree& parent, |
|||
const string& name, |
|||
const NodeFunc& test_func, |
|||
ExecutionMode exec_mode) |
|||
{ |
|||
pEpTestTree ret(&parent, nullptr, name, test_func, exec_mode); |
|||
return ret; |
|||
} |
|||
|
|||
string pEpTestTree::getNodeName() const |
|||
{ |
|||
return _name; |
|||
} |
|||
|
|||
string pEpTestTree::getNodePath() const |
|||
{ |
|||
pEpLogClass("called"); |
|||
string ret; |
|||
|
|||
if (!_isRootNode()) { |
|||
ret = _parent->getNodePath() + "/" + getNodeName(); |
|||
} else { |
|||
ret = getNodeName(); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// For:
|
|||
// RootNode - "<name>"
|
|||
// ProcessNode - ".../<proc>"
|
|||
// When Process as dir. parent - ".../<proc>/name"
|
|||
// When no process as dir. parent - ".../<proc>/.../name"
|
|||
std::string pEpTestTree::getNodePathShort() const |
|||
{ |
|||
string ret; |
|||
if (_isRootNode()) { |
|||
ret = getNodeName(); |
|||
} else { |
|||
if (_isProcessNode()) { |
|||
ret += ".../" + getNodeName(); |
|||
} else { |
|||
if (&(_getParentingProcessNode()) == (_parent)) { |
|||
ret = _getParentingProcessNode().getNodePathShort() + "/" + getNodeName(); |
|||
} else { |
|||
ret = _getParentingProcessNode().getNodePathShort() + "/.../" + getNodeName(); |
|||
} |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// Inherited (if null see parent recursively)
|
|||
pEpTestModel& pEpTestTree::getModel() const |
|||
{ |
|||
pEpLogClass("called"); |
|||
pEpTestModel* ret = nullptr; |
|||
if (_model == nullptr) { |
|||
ret = &(_parent->getModel()); |
|||
} else { |
|||
ret = _model; |
|||
} |
|||
assert(ret != nullptr); |
|||
// 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
|
|||
// ProcessNodes have their own data_dir inside their RootNote dir (nameclash prossible)
|
|||
// All other nodes inherit data_dir from their Root/ProcessNode
|
|||
string pEpTestTree::getDataDir() const |
|||
{ |
|||
pEpLogClass("called"); |
|||
string ret; |
|||
if (_isRootNode()) { |
|||
ret = getDataRoot() + getNodeName() + "/"; |
|||
} else { |
|||
if (_parent->_exec_mode == ExecutionMode::PROCESS_SERIAL || |
|||
_parent->_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
|||
|
|||
ret = _parent->getDataDir() + getNodeName(); |
|||
} else { |
|||
// inherit
|
|||
ret = _parent->getDataDir(); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// static
|
|||
void pEpTestTree::setDataRoot(const string& dir) |
|||
{ |
|||
pEpTestTree::_data_root = dir; |
|||
} |
|||
|
|||
// static
|
|||
string pEpTestTree::getDataRoot() |
|||
{ |
|||
return pEpTestTree::_data_root; |
|||
} |
|||
|
|||
|
|||
void pEpTestTree::run(const pEpTestTree* caller) const |
|||
{ |
|||
pEpLogClass("called"); |
|||
// caller is never nullptr if called by another pEpTestTree
|
|||
if (caller == nullptr) { |
|||
pEpLog::logH1("Starting pEpTestTree from node: " + getNodePathShort()); |
|||
pEpLog::log(to_string()); |
|||
} |
|||
|
|||
pEpLog::logH2( |
|||
"[ " + to_string(_exec_mode) + " / " + getNodePathShort() + "]"); |
|||
// Execute in fork and wait here until process ends
|
|||
if (_exec_mode == ExecutionMode::PROCESS_SERIAL) { // fork
|
|||
_executeInFork(bind(&pEpTestTree::_run, this), true); |
|||
// Execute in fork and go on, wait for process execution in the end
|
|||
} else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
|||
_executeInFork(bind(&pEpTestTree::_run, this), false); |
|||
// Execute as normal funciton
|
|||
} else if (_exec_mode == ExecutionMode::FUNCTION) { |
|||
_run(); |
|||
} else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) { |
|||
throw invalid_argument(to_string(_exec_mode) + " - not implemented"); |
|||
} else if (_exec_mode == ExecutionMode::THREAD_SERIAL) { |
|||
throw invalid_argument(to_string(_exec_mode) + " - not implemented"); |
|||
} |
|||
|
|||
if (caller == nullptr) { |
|||
_waitChildProcesses(); |
|||
} |
|||
} |
|||
|
|||
string pEpTestTree::to_string(bool recursive, int indent) const |
|||
{ |
|||
string ret; |
|||
stringstream builder; |
|||
builder << string(indent, '\t'); |
|||
builder << getNodeName(); |
|||
builder << "[" << to_string(_exec_mode) << "]"; |
|||
builder << endl; |
|||
ret = builder.str(); |
|||
|
|||
if (recursive) { |
|||
indent++; |
|||
for (const pair<string, const pEpTestTree&> child : _children) { |
|||
ret += child.second.to_string(true, indent); |
|||
} |
|||
indent--; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
string pEpTestTree::to_string(const ExecutionMode& emode) |
|||
{ |
|||
switch (emode) { |
|||
case ExecutionMode::FUNCTION: |
|||
return "FUNCTION"; |
|||
case ExecutionMode::PROCESS_SERIAL: |
|||
return "PROCESS_SERIAL"; |
|||
case ExecutionMode::PROCESS_PARALLEL: |
|||
return "PROCESS_PARALLEL"; |
|||
case ExecutionMode::THREAD_SERIAL: |
|||
return "THREAD_SERIAL"; |
|||
case ExecutionMode::THREAD_PARALLEL: |
|||
return "THREAD_PARALLEL"; |
|||
case ExecutionMode::INHERIT: |
|||
return "INHERIT"; |
|||
default: |
|||
return "UNDEFINED EXECUTION MODE"; |
|||
} |
|||
} |
|||
|
|||
//Well, ok, lets just add some little convenience logging service in here, too
|
|||
void pEpTestTree::log(const string& msg) const |
|||
{ |
|||
stringstream builder; |
|||
builder << "["; |
|||
builder << std::to_string(getpid()); |
|||
builder << " - "; |
|||
builder << getNodePathShort(); |
|||
builder << "] - "; |
|||
builder << msg; |
|||
builder << endl; |
|||
cout << builder.str(); |
|||
} |
|||
|
|||
// PRIVATE ---------------------------------------------------------------------------------
|
|||
|
|||
pEpTestTree::pEpTestTree( |
|||
pEpTestTree* const parent, |
|||
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()); |
|||
if (!_isRootNode()) { |
|||
parent->_addChildNode(*this); |
|||
} |
|||
} |
|||
|
|||
void pEpTestTree::_run() const |
|||
{ |
|||
if (_test_func) { |
|||
_test_func(*this); |
|||
} else { |
|||
pEpLog::log("No function to execute"); |
|||
} |
|||
if (!_children.empty()) { |
|||
for (const pair<string, pEpTestTree&> child : _children) { |
|||
child.second.run(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pEpTestTree::_executeInFork(function<void(void)> 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 runtime_error("Error forking"); |
|||
} |
|||
if (wait_child) { |
|||
_waitChildProcesses(); |
|||
} |
|||
} |
|||
|
|||
void pEpTestTree::_waitChildProcesses() const |
|||
{ |
|||
int status; |
|||
pid_t pid; |
|||
while ((pid = wait(&status)) > 0) { |
|||
pEpLog::log( |
|||
"process[" + std::to_string((int)pid) + |
|||
"] terminated with status: " + std::to_string(status)); |
|||
} |
|||
} |
|||
|
|||
void pEpTestTree::_addChildNode(pEpTestTree& node) |
|||
{ |
|||
_children.insert(pair<string, pEpTestTree&>(node.getNodeName(), node)); |
|||
} |
|||
|
|||
bool pEpTestTree::_isProcessNode() const |
|||
{ |
|||
bool ret = false; |
|||
if (_exec_mode == ExecutionMode::PROCESS_SERIAL || |
|||
_exec_mode == ExecutionMode::PROCESS_PARALLEL) { |
|||
ret = true; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
bool pEpTestTree::_isRootNode() const |
|||
{ |
|||
bool ret = false; |
|||
if (_parent == nullptr) { |
|||
ret = true; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
const pEpTestTree& pEpTestTree::_getRootNode() const |
|||
{ |
|||
const pEpTestTree* ret = nullptr; |
|||
if (!_isRootNode()) { |
|||
ret = &(_parent->_getRootNode()); |
|||
} else { |
|||
ret = this; |
|||
} |
|||
assert(ret != nullptr); |
|||
// cant be null because for createChildNode() you need to provide a TestNode& and
|
|||
// the only other way is using createRootNode() which has parent == nullptr
|
|||
return *ret; |
|||
} |
|||
|
|||
const pEpTestTree& pEpTestTree::_getParentingProcessNode() const |
|||
{ |
|||
if (_isRootNode() || _isProcessNode()) { |
|||
return *this; |
|||
} else { |
|||
return _parent->_getParentingProcessNode(); |
|||
} |
|||
} |
|||
|
|||
// name is alphanumeric only (everything else will be replaced by an underscore)
|
|||
string pEpTestTree::_normalizeName(string name) const |
|||
{ |
|||
replace_if( |
|||
name.begin(), |
|||
name.end(), |
|||
[](char c) -> bool { return !isalnum(c); }, |
|||
'_'); |
|||
|
|||
return name; |
|||
} |
|||
|
|||
void pEpTestTree::_data_dir_create() |
|||
{ |
|||
// Utils::dir_create(getDataDir());
|
|||
pEpLog::log("creating dir:" + getDataRoot()); |
|||
} |
|||
|
|||
void pEpTestTree::_data_dir_delete() |
|||
{ |
|||
try { |
|||
Utils::path_delete_all(getDataRoot()); |
|||
} catch (const exception& e) { |
|||
pEpLog::log("DistTest: - could not delete data dir: " + getDataRoot()); |
|||
} |
|||
} |
|||
|
|||
void pEpTestTree::_data_dir_recreate() |
|||
{ |
|||
_data_dir_delete(); |
|||
_data_dir_create(); |
|||
}; |
|||
} // namespace Test
|
|||
} // namespace pEp
|
@ -0,0 +1,118 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef LIBPEPADAPTER_PEPTEST_PEPTESTTREE_HH |
|||
#define LIBPEPADAPTER_PEPTEST_PEPTESTTREE_HH |
|||
|
|||
#include <string> |
|||
#include <functional> |
|||
#include <map> |
|||
#include "../../../src/pEpLog.hh" |
|||
#include "pEpTestModel.hh" |
|||
|
|||
// Yes, the mem mgmt is purely static on purpose (so far)
|
|||
|
|||
namespace pEp { |
|||
namespace Test { |
|||
class pEpTestTree { |
|||
public: |
|||
using NodeFunc = std::function<void(const pEpTestTree&)>; |
|||
|
|||
enum class ExecutionMode |
|||
{ |
|||
FUNCTION, |
|||
PROCESS_SERIAL, |
|||
PROCESS_PARALLEL, |
|||
THREAD_SERIAL, // unimplemented
|
|||
THREAD_PARALLEL, // unimplemented
|
|||
INHERIT |
|||
}; |
|||
|
|||
// Constructors are private
|
|||
pEpTestTree() = delete; |
|||
|
|||
// Modify
|
|||
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 NodeFunc& test_func, |
|||
ExecutionMode exec_mode = ExecutionMode::FUNCTION); |
|||
|
|||
// Read-Only
|
|||
std::string getNodeName() const; // name only
|
|||
std::string getNodePath() const; // full path (is an ID)
|
|||
std::string getNodePathShort() const; // parent process + name
|
|||
pEpTestModel& getModel() const; |
|||
std::string getDataDir() const; |
|||
|
|||
// Read-Write
|
|||
static void setDataRoot(const std::string& dir); |
|||
static std::string getDataRoot(); |
|||
|
|||
// Main funcs
|
|||
void run(const pEpTestTree* caller = nullptr) const; |
|||
std::string to_string(bool recursive = true, int indent = 0) const; |
|||
static std::string to_string(const ExecutionMode& emode); |
|||
|
|||
// logging service
|
|||
void log(const std::string& msg) const; |
|||
|
|||
// internal logging
|
|||
static bool debug_log_enabled; |
|||
Adapter::pEpLog::pEpLogger logger_debug{ "pEpTestTree", debug_log_enabled }; |
|||
|
|||
private: |
|||
// CONSTRUCGTORS
|
|||
explicit pEpTestTree( |
|||
pEpTestTree* parent, |
|||
pEpTestModel* model, |
|||
const std::string& name, |
|||
const NodeFunc& test_func, |
|||
ExecutionMode exec_mode); |
|||
|
|||
// METHODS
|
|||
// Execution
|
|||
void _run() const; |
|||
void _executeInFork(std::function<void(void)> func, bool wait_child) const; |
|||
void _waitChildProcesses() const; |
|||
|
|||
// Modify
|
|||
void _addChildNode(pEpTestTree& node); |
|||
|
|||
// Query
|
|||
bool _isProcessNode() const; |
|||
bool _isRootNode() const; |
|||
const pEpTestTree& _getRootNode() const; |
|||
const pEpTestTree& _getParentingProcessNode() const; |
|||
|
|||
// Util
|
|||
std::string _normalizeName(std::string name) const; |
|||
|
|||
// TODO
|
|||
void _data_dir_delete(); |
|||
void _data_dir_create(); |
|||
void _data_dir_recreate(); |
|||
|
|||
// Fields
|
|||
const std::string _name; |
|||
const pEpTestTree* _parent; //nullptr if RootUnit
|
|||
pEpTestModel* _model; //nullptr if inherited
|
|||
const NodeFunc& _test_func; |
|||
const ExecutionMode _exec_mode; |
|||
static std::string _data_root; |
|||
|
|||
std::map<const std::string, pEpTestTree&> _children; // map to guarantee uniqueness of sibling-names
|
|||
|
|||
// internal logging
|
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug; |
|||
}; |
|||
}; // namespace Test
|
|||
}; // namespace pEp
|
|||
|
|||
#endif // LIBPEPADAPTER_PEPTEST_PEPTESTTREE_HH
|
@ -1,379 +0,0 @@ |
|||
#include "pEpTestUnit.hh" |
|||
#include "../../../src/std_utils.hh" |
|||
#include "../../framework/utils.hh" |
|||
#include <iostream> |
|||
#include <unistd.h> |
|||
#include <cstdlib> |
|||
#include <sys/stat.h> |
|||
#include <functional> |
|||
#include <algorithm> |
|||
#include <sstream> |
|||
|
|||
using namespace std; |
|||
|
|||
namespace pEp { |
|||
namespace Test { |
|||
bool pEpTestUnit::log_enabled = true; |
|||
string pEpTestUnit::data_root = "./peptest"; |
|||
pEpTestUnit::ExecutionMode pEpTestUnit::emode_default = pEpTestUnit::ExecutionMode::FUNCTION; |
|||
|
|||
// RootNode factory
|
|||
// static
|
|||
pEpTestUnit pEpTestUnit::createRootNode( |
|||
pEpTestModel& model, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children) |
|||
{ |
|||
pEpTestUnit ret(nullptr, &model, name, test_func, emode_children); |
|||
return ret; |
|||
} |
|||
|
|||
// ChildNode factory
|
|||
// static
|
|||
pEpTestUnit pEpTestUnit::createChildNode( |
|||
pEpTestUnit& parent, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children) |
|||
{ |
|||
pEpTestUnit ret(&parent, nullptr, name, test_func, emode_children); |
|||
return ret; |
|||
} |
|||
|
|||
|
|||
// private
|
|||
pEpTestUnit::pEpTestUnit( |
|||
pEpTestUnit* const parent, |
|||
pEpTestModel* model, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children) : |
|||
parent(parent), |
|||
model(model), name(normalizeName(name)), test_func(test_func), emode_chld(emode_children) |
|||
{ |
|||
logger.set_instancename(getFQName()); |
|||
if (!isRootNode()) { |
|||
parent->addChildNode(*this); |
|||
} |
|||
} |
|||
|
|||
// static
|
|||
void pEpTestUnit::setDefaultDataRoot(const std::string& dir) |
|||
{ |
|||
pEpTestUnit::data_root = dir; |
|||
} |
|||
|
|||
// static
|
|||
std::string pEpTestUnit::getDataRoot() |
|||
{ |
|||
return pEpTestUnit::data_root; |
|||
} |
|||
|
|||
void pEpTestUnit::init(const pEpTestUnit* caller) const |
|||
{ |
|||
//caller is never nullptr if called from another unit
|
|||
if (caller == nullptr) {} |
|||
|
|||
// for (const pair<string, pEpTestUnit&> elem : testnodes) {
|
|||
// string home_dir = evalHomeDir(elem.second);
|
|||
// pEpLogClass("creating home dir for '" + elem.second.getName() + "' - " + home_dir); mkdir(home_dir.c_str(), 0770);
|
|||
// }
|
|||
} |
|||
|
|||
void pEpTestUnit::addChildNode(pEpTestUnit& node) |
|||
{ |
|||
children.insert(pair<string, pEpTestUnit&>(node.getName(), node)); |
|||
} |
|||
|
|||
// name is alphanumeric only (everything else will be replaced by an underscore)
|
|||
// private
|
|||
string pEpTestUnit::normalizeName(string name) const |
|||
{ |
|||
replace_if( |
|||
name.begin(), |
|||
name.end(), |
|||
[](char c) -> bool { return !isalnum(c); }, |
|||
'_'); |
|||
|
|||
return name; |
|||
} |
|||
|
|||
string pEpTestUnit::getName() const |
|||
{ |
|||
return name; |
|||
} |
|||
|
|||
// RootNodes have their own data_dir
|
|||
// ProcessNodes have their own data_dir inside their RootNote dir (nameclash prossible)
|
|||
// All other nodes inherit data_dir from their Root/ProcessNode
|
|||
string pEpTestUnit::getDataDir() const |
|||
{ |
|||
string ret; |
|||
if (isRootNode()) { |
|||
ret = getDataRoot() + getName() + "/"; |
|||
} else { |
|||
if (parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_SERIAL || |
|||
parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_PARALLEL) { |
|||
|
|||
ret = parent->getDataDir() + getName(); |
|||
} else { |
|||
// inherit
|
|||
ret = parent->getDataDir(); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
void pEpTestUnit::run(const pEpTestUnit* caller) |
|||
{ |
|||
pEpLogClass("called"); |
|||
// caller is never nullptr if called by another pEpTestUnit
|
|||
if (caller == nullptr) { |
|||
pEpLogClass("\n" + to_string()); |
|||
} |
|||
|
|||
if (test_func) { |
|||
test_func(*this); |
|||
} else { |
|||
pEpLogClass("No function to execute"); |
|||
} |
|||
executeChildren(); |
|||
} |
|||
|
|||
// private
|
|||
void pEpTestUnit::executeChildren() const |
|||
{ |
|||
if (!children.empty()) { |
|||
const ExecutionMode& emode = getEffectiveExecutionMode(); |
|||
for (const pair<string, pEpTestUnit&> elem : children) { |
|||
// Execute in fork and wait here until process ends
|
|||
if (emode == ExecutionMode::PROCESS_SERIAL) { // fork
|
|||
executeForked(elem.second); |
|||
waitChildProcesses(); |
|||
// Execute in fork and go on, wait for process execution in the end
|
|||
} else if (emode == ExecutionMode::PROCESS_PARALLEL) { |
|||
executeForked(elem.second); |
|||
// Execute as normal funciton
|
|||
} else if (emode == ExecutionMode::FUNCTION) { |
|||
elem.second.run(this); |
|||
} else if (emode == ExecutionMode::THREAD_PARALLEL) { |
|||
throw runtime_error(to_string(emode) + " - not implemented"); |
|||
} else if (emode == ExecutionMode::THREAD_SERIAL) { |
|||
throw runtime_error(to_string(emode) + " - not implemented"); |
|||
} |
|||
} |
|||
if (emode == ExecutionMode::PROCESS_PARALLEL) { |
|||
waitChildProcesses(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// private
|
|||
void pEpTestUnit::executeForked(pEpTestUnit& unit) const |
|||
{ |
|||
pid_t pid; |
|||
pid = fork(); |
|||
if (pid == pid_t(0)) { |
|||
// setenv("HOME", evalHomeDir().c_str(), 1);
|
|||
unit.run(this); |
|||
exit(0); |
|||
} else if (pid < pid_t(0)) { |
|||
pEpLogClass("Error forking"); |
|||
} |
|||
} |
|||
|
|||
// private
|
|||
void pEpTestUnit::waitChildProcesses() const |
|||
{ |
|||
int status; |
|||
pid_t pid; |
|||
while ((pid = wait(&status)) > 0) { |
|||
pEpLogClass( |
|||
"process[" + to_string((int)pid) + |
|||
"] terminated with status: " + to_string(status)); |
|||
} |
|||
} |
|||
|
|||
// Inherited (if null see parent recursively)
|
|||
pEpTestModel& pEpTestUnit::getModel() const |
|||
{ |
|||
// pEpLogClass("called");
|
|||
pEpTestModel* ret = nullptr; |
|||
if (model == nullptr) { |
|||
ret = &parent->getModel(); |
|||
} else { |
|||
ret = model; |
|||
} |
|||
assert(ret != nullptr); |
|||
// 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; |
|||
} |
|||
|
|||
const pEpTestUnit& pEpTestUnit::getRoot() const |
|||
{ |
|||
// pEpLogClass("called");
|
|||
const pEpTestUnit* ret = nullptr; |
|||
if (!isRootNode()) { |
|||
ret = &parent->getRoot(); |
|||
} else { |
|||
ret = this; |
|||
} |
|||
assert(ret != nullptr); |
|||
// cant be null because for createChildNode() you need to provide a TestNode& and
|
|||
// the only other way is using createRootNode() which has parent == nullptr
|
|||
return *ret; |
|||
} |
|||
|
|||
string pEpTestUnit::getFQNameNormalized() const |
|||
{ |
|||
return normalizeName(getFQName()); |
|||
} |
|||
|
|||
string pEpTestUnit::getFQName() const |
|||
{ |
|||
// pEpLogClass("called");
|
|||
string ret; |
|||
|
|||
if (!isRootNode()) { |
|||
ret = parent->getFQName() + "/" + getName(); |
|||
} else { |
|||
ret = getName(); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// // A process node is a node that spawns its own process
|
|||
// bool pEpTestUnit::isProcessNode() const
|
|||
// {
|
|||
// bool ret = false;
|
|||
// if (isRootNode() ||
|
|||
// parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_PARALLEL ||
|
|||
// parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_SERIAL) {
|
|||
// ret = true;
|
|||
// }
|
|||
// return ret;
|
|||
// }
|
|||
|
|||
bool pEpTestUnit::isRootNode() const |
|||
{ |
|||
bool ret = false; |
|||
if (parent == nullptr) { |
|||
ret = true; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
void pEpTestUnit::data_dir_delete() |
|||
{ |
|||
try { |
|||
Utils::path_delete_all(getDataRoot()); |
|||
} catch (const exception& e) { |
|||
pEpLogClass("DistTest: - could not delete data dir: " + getDataRoot()); |
|||
} |
|||
} |
|||
|
|||
void pEpTestUnit::data_dir_create() |
|||
{ |
|||
// Utils::dir_create(getDataDir());
|
|||
pEpLogClass("creating dir:" + getDataRoot()); |
|||
} |
|||
|
|||
void pEpTestUnit::data_dir_recreate() |
|||
{ |
|||
data_dir_delete(); |
|||
data_dir_create(); |
|||
}; |
|||
|
|||
// static
|
|||
void pEpTestUnit::setDefaultExecutionMode(ExecutionMode emode) |
|||
{ |
|||
pEpTestUnit::emode_default = emode; |
|||
} |
|||
|
|||
pEpTestUnit::ExecutionMode pEpTestUnit::getExecutionMode() const |
|||
{ |
|||
return emode_chld; |
|||
} |
|||
|
|||
pEpTestUnit::ExecutionMode pEpTestUnit::getEffectiveExecutionMode() const |
|||
{ |
|||
ExecutionMode ret{ emode_default }; |
|||
if (getExecutionMode() == ExecutionMode::INHERIT) { |
|||
if (!isRootNode()) { |
|||
// get from parent until not inherit
|
|||
ret = parent->getEffectiveExecutionMode(); |
|||
} |
|||
} else { |
|||
ret = getExecutionMode(); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
string pEpTestUnit::to_string(const ExecutionMode& emode) |
|||
{ |
|||
switch (emode) { |
|||
case ExecutionMode::FUNCTION: |
|||
return "FUNCTION"; |
|||
case ExecutionMode::PROCESS_SERIAL: |
|||
return "PROCESS_SERIAL"; |
|||
case ExecutionMode::PROCESS_PARALLEL: |
|||
return "PROCESS_PARALLEL"; |
|||
case ExecutionMode::THREAD_SERIAL: |
|||
return "THREAD_SERIAL"; |
|||
case ExecutionMode::THREAD_PARALLEL: |
|||
return "THREAD_PARALLEL"; |
|||
case ExecutionMode::INHERIT: |
|||
return "INHERIT"; |
|||
default: |
|||
return "UNDEFINED EXECUTION MODE"; |
|||
} |
|||
} |
|||
|
|||
string pEpTestUnit::to_string(bool recursive, int indent) const |
|||
{ |
|||
string ret; |
|||
stringstream builder; |
|||
builder << string(indent, '\t') << getName(); |
|||
builder << "[children=" << to_string(getEffectiveExecutionMode()) + "]"; |
|||
// builder << "/" << getModel().getName();
|
|||
builder << endl; |
|||
ret = builder.str(); |
|||
|
|||
if (recursive) { |
|||
indent++; |
|||
for (const pair<string, const pEpTestUnit&> elem : children) { |
|||
ret += elem.second.to_string(true, indent); |
|||
} |
|||
indent--; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
const pEpTestUnit& pEpTestUnit::getParentProcessUnit() const |
|||
{ |
|||
if (!isRootNode()) { |
|||
if (parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_PARALLEL || |
|||
parent->getEffectiveExecutionMode() == ExecutionMode::PROCESS_SERIAL || |
|||
parent->isRootNode()) { |
|||
return *this; |
|||
} else { |
|||
return parent->getParentProcessUnit(); |
|||
} |
|||
} else { |
|||
return *this; |
|||
} |
|||
} |
|||
|
|||
//Well, ok, lets just add some little convenience logging service in here, too
|
|||
void pEpTestUnit::log(const string& msg) const |
|||
{ |
|||
stringstream builder; |
|||
builder << "[" << std::to_string(getpid()) << "/" << getParentProcessUnit().getFQName() |
|||
<< "] - "; |
|||
builder << msg << endl; |
|||
cout << builder.str(); |
|||
} |
|||
} // namespace Test
|
|||
} // namespace pEp
|
@ -1,106 +0,0 @@ |
|||
// This file is under GNU General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#ifndef LIBPEPADAPTER_PEPTESTUNIT_HH |
|||
#define LIBPEPADAPTER_PEPTESTUNIT_HH |
|||
|
|||
#include <string> |
|||
#include <functional> |
|||
#include <map> |
|||
#include "../../../src/pEpLog.hh" |
|||
#include "pEpTestModel.hh" |
|||
|
|||
namespace pEp { |
|||
namespace Test { |
|||
class pEpTestUnit { |
|||
public: |
|||
using TestUnitFunction = std::function<void(const pEpTestUnit&)>; |
|||
|
|||
enum class ExecutionMode |
|||
{ |
|||
FUNCTION, |
|||
PROCESS_SERIAL, |
|||
PROCESS_PARALLEL, |
|||
THREAD_SERIAL, // unimplemented
|
|||
THREAD_PARALLEL, // unimplemented
|
|||
INHERIT |
|||
}; |
|||
static std::string to_string(const ExecutionMode& emode); |
|||
|
|||
// Constructors
|
|||
pEpTestUnit() = delete; |
|||
|
|||
// Methods
|
|||
static pEpTestUnit createRootNode( |
|||
pEpTestModel& model, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children = emode_default); |
|||
|
|||
static pEpTestUnit createChildNode( |
|||
pEpTestUnit& parent, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children = emode_default); |
|||
|
|||
void init(const pEpTestUnit* caller = nullptr) const; |
|||
static void setDefaultDataRoot(const std::string& dir); |
|||
static std::string getDataRoot(); |
|||
void addChildNode(pEpTestUnit& node); |
|||
void run(const pEpTestUnit* caller = nullptr); |
|||
std::string getName() const; |
|||
std::string getFQName() const; |
|||
std::string getFQNameNormalized() const; |
|||
pEpTestModel& getModel() const; |
|||
std::string getDataDir() const; |
|||
const pEpTestUnit& getParentProcessUnit() const; |
|||
std::string to_string(bool recursive = true, int indent = 0) const; |
|||
static void setDefaultExecutionMode(ExecutionMode emode); |
|||
|
|||
//logging service
|
|||
void log(const std::string& msg) const; |
|||
|
|||
// internal logging
|
|||
static bool log_enabled; |
|||
Adapter::pEpLog::pEpLogger logger{ "pEpTestUnit", log_enabled }; |
|||
|
|||
private: |
|||
// Constructors
|
|||
explicit pEpTestUnit( |
|||
pEpTestUnit* parent, |
|||
pEpTestModel* model, |
|||
const std::string& name, |
|||
const TestUnitFunction& test_func, |
|||
ExecutionMode emode_children); |
|||
|
|||
// Methods
|
|||
const pEpTestUnit& getRoot() const; |
|||
void executeChildren() const; |
|||
void executeForked(pEpTestUnit& unit) const; |
|||
void waitChildProcesses() const; |
|||
ExecutionMode getExecutionMode() const; |
|||
ExecutionMode getEffectiveExecutionMode() const; |
|||
void data_dir_delete(); |
|||
void data_dir_create(); |
|||
void data_dir_recreate(); |
|||
bool isRootNode() const; |
|||
// bool isProcessNode() const;
|
|||
std::string normalizeName(std::string name) const; |
|||
|
|||
// Fields
|
|||
const pEpTestUnit* parent; //nullptr if rootnode
|
|||
const std::string name; |
|||
pEpTestModel* model; //nullptr if inherited
|
|||
const TestUnitFunction& test_func; |
|||
const ExecutionMode emode_chld; |
|||
static ExecutionMode emode_default; |
|||
std::map<const std::string, pEpTestUnit&> children; |
|||
static std::string data_root; |
|||
|
|||
// logger
|
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
|||
}; |
|||
}; // namespace Test
|
|||
}; // namespace pEp
|
|||
|
|||
#endif // LIBPEPADAPTER_PEPTESTUNIT_HH
|
Loading…
Reference in new issue