Browse Source

pEpTestTree - loads of improvements and func

LIB-11
heck 4 years ago
parent
commit
4a38564ce6
  1. 360
      test/pEpTest/src/pEpTestTree.cc
  2. 118
      test/pEpTest/src/pEpTestTree.hh
  3. 379
      test/pEpTest/src/pEpTestUnit.cc
  4. 106
      test/pEpTest/src/pEpTestUnit.hh
  5. 55
      test/pEpTest/test/test_pEpTest_basic.cc
  6. 30
      test/pEpTest/test/test_transport.cc

360
test/pEpTest/src/pEpTestTree.cc

@ -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

118
test/pEpTest/src/pEpTestTree.hh

@ -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

379
test/pEpTest/src/pEpTestUnit.cc

@ -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

106
test/pEpTest/src/pEpTestUnit.hh

@ -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

55
test/pEpTest/test/test_pEpTest_basic.cc

@ -1,4 +1,4 @@
#include "../src/pEpTestUnit.hh" #include "../src/pEpTestTree.hh"
#include "../../framework/utils.hh" #include "../../framework/utils.hh"
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
@ -8,12 +8,13 @@ using namespace pEp;
using namespace pEp::Test; using namespace pEp::Test;
void print_and_sleep(pEpTestUnit& myself, int sleepmilis, int rep_count) void printHomeDir(pEpTestTree& myself, int sleepmilis, int rep_count)
{ {
// TESTLOGH1("HYA FROM:" + myself.getFQName()); // TESTLOGH1("HYA FROM:" + myself.getFQName());
int i = 0; int i = 0;
while (i < rep_count) { while (i < rep_count) {
TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid()) + " - " + to_string(i))); myself.log(myself.getNodeName() + " - " + to_string(i));
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid()) + " - " + to_string(i)));
sleep_millis(sleepmilis); sleep_millis(sleepmilis);
i++; i++;
} }
@ -24,30 +25,48 @@ int main(int argc, char* argv[])
string dummy; string dummy;
pEpTestModel model{ "pEpTestModel" }; pEpTestModel model{ "pEpTestModel" };
{ {
// pEpTestUnit::setDefaultExecutionMode(pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_SERIAL); // DEBUG Logging of pEpTestTree itself
pEpTestUnit root = pEpTestUnit::createRootNode( pEpTestTree::debug_log_enabled = true;
// Configure DataRoot for all TestNodes
pEpTestTree::setDataRoot("./basic_data_root");
// The RootNode is the
pEpTestTree root = pEpTestTree::createRootNode(
model, model,
"DistributedTest", "Test Execution Model",
[](pEpTestUnit mynode) { print_and_sleep(mynode, 200, 5); }, [](pEpTestTree mynode) { printHomeDir(mynode, 200, 5); });
pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_PARALLEL);
pEpTestUnit test1 = pEpTestUnit::createChildNode(root, "node1", [](pEpTestUnit mynode) { // Subprocess 1
print_and_sleep(mynode, 200, 10); pEpTestTree test1 = pEpTestTree::createChildNode(
root,
"node1",
[](pEpTestTree mynode) { printHomeDir(mynode, 200, 10); },
pEp::Test::pEpTestTree::ExecutionMode::PROCESS_PARALLEL);
pEpTestTree test1_1 = pEpTestTree::createChildNode(test1, "test1.1", [](pEpTestTree mynode) {
printHomeDir(mynode, 200, 10);
}); });
pEpTestUnit test2 = pEpTestUnit::createChildNode(root, "node2", [](pEpTestUnit mynode) { pEpTestTree test1_2 = pEpTestTree::createChildNode(test1, "test1.2", [](pEpTestTree mynode) {
print_and_sleep(mynode, 200, 10); printHomeDir(mynode, 200, 10);
}); });
pEpTestUnit test1_1 = pEpTestUnit::createChildNode(test1, "test1.1", [](pEpTestUnit mynode) { // Subprocess 2
print_and_sleep(mynode, 200, 10); pEpTestTree test2 = pEpTestTree::createChildNode(
root,
"node2",
[](pEpTestTree mynode) { printHomeDir(mynode, 200, 10); },
pEp::Test::pEpTestTree::ExecutionMode::PROCESS_PARALLEL);
pEpTestTree test2_1 = pEpTestTree::createChildNode(test2, "test2.1", [](pEpTestTree mynode) {
printHomeDir(mynode, 200, 10);
}); });
pEpTestUnit test2_1 = pEpTestUnit::createChildNode(test2, "test2.1", [](pEpTestUnit mynode) { pEpTestTree test2_2 = pEpTestTree::createChildNode(test2, "test2.2", [](pEpTestTree mynode) {
print_and_sleep(mynode, 200, 10); printHomeDir(mynode, 200, 10);
}); });
// cout << root.to_string() << endl;
root.run(); root.run();
} }
} }

30
test/pEpTest/test/test_transport.cc

@ -1,4 +1,4 @@
#include "../src/pEpTestUnit.hh" #include "../src/pEpTestTree.hh"
#include "../../framework/utils.hh" #include "../../framework/utils.hh"
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
@ -11,7 +11,7 @@ using namespace pEp;
using namespace pEp::Test; using namespace pEp::Test;
void printHomeDir(pEpTestUnit& myself) void printHomeDir(pEpTestTree& myself)
{ {
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid()))); // TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid())));
// cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl; // cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl;
@ -22,34 +22,34 @@ void printHomeDir(pEpTestUnit& myself)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
pEpTestModel model{ "TestTransport" }; pEpTestModel model{ "TestTransport" };
pEpTestUnit::log_enabled = false; // pEpTestTree::debug_log_enabled = true;
pEpTestUnit::setDefaultDataRoot("./testdata/"); pEpTestTree::setDataRoot("./testdata/");
{ {
pEpTestUnit root = pEpTestUnit::createRootNode( pEpTestTree root = pEpTestTree::createRootNode(
model, model,
"root node nr.1", "root node nr.1",
[](pEpTestUnit mynode) { printHomeDir(mynode); }, [](pEpTestTree mynode) { printHomeDir(mynode); },
pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_PARALLEL); pEp::Test::pEpTestTree::ExecutionMode::PROCESS_PARALLEL);
pEpTestUnit test1 = pEpTestUnit::createChildNode(root, "node 1", [](pEpTestUnit mynode) { pEpTestTree test1 = pEpTestTree::createChildNode(root, "node 1", [](pEpTestTree mynode) {
printHomeDir(mynode); printHomeDir(mynode);
}); });
pEpTestUnit test1_1 = pEpTestUnit::createChildNode(test1, "node 1_1", [](pEpTestUnit mynode) { pEpTestTree test1_1 = pEpTestTree::createChildNode(test1, "node 1.1", [](pEpTestTree mynode) {
printHomeDir(mynode); printHomeDir(mynode);
}); });
pEpTestUnit test2 = pEpTestUnit::createChildNode(root, "node 2", [](pEpTestUnit mynode) { pEpTestTree test2 = pEpTestTree::createChildNode(root, "node 2", [](pEpTestTree mynode) {
printHomeDir(mynode); printHomeDir(mynode);
}); });
pEpTestUnit test2_1 = pEpTestUnit::createChildNode( pEpTestTree test2_1 = pEpTestTree::createChildNode(
test2, test2,
"node 2_1", "node 2.1",
[](pEpTestUnit mynode) { printHomeDir(mynode); }, [](pEpTestTree mynode) { printHomeDir(mynode); },
pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_PARALLEL); pEp::Test::pEpTestTree::ExecutionMode::PROCESS_PARALLEL);
pEpTestUnit test2_1_1 = pEpTestUnit::createChildNode(test2_1, "node 1", [](pEpTestUnit mynode) { pEpTestTree test2_1_1 = pEpTestTree::createChildNode(test2_1, "node 2.1.1", [](pEpTestTree mynode) {
printHomeDir(mynode); printHomeDir(mynode);
}); });

Loading…
Cancel
Save