Browse Source

Tests: pEpTest changes, its getting there... wait for it.

LIB-11
heck 4 years ago
parent
commit
ba34baa2eb
  1. 222
      test/pEpTest/src/pEpTestUnit.cc
  2. 42
      test/pEpTest/src/pEpTestUnit.hh
  3. 58
      test/pEpTest/test/test_transport.cc

222
test/pEpTest/src/pEpTestUnit.cc

@ -6,95 +6,97 @@
#include <cstdlib> #include <cstdlib>
#include <sys/stat.h> #include <sys/stat.h>
#include <functional> #include <functional>
#include <algorithm>
#include <sstream>
using namespace std; using namespace std;
namespace pEp { namespace pEp {
namespace Test { namespace Test {
bool pEpTestUnit::log_enabled = true; bool pEpTestUnit::log_enabled = true;
string pEpTestUnit::data_dir = "./"; string pEpTestUnit::data_root = "./peptest";
pEpTestUnit::ExecutionMode pEpTestUnit::emode_default = pEpTestUnit::ExecutionMode::FUNCTION; pEpTestUnit::ExecutionMode pEpTestUnit::emode_default = pEpTestUnit::ExecutionMode::FUNCTION;
// RootNode factory // RootNode factory
//static // static
pEpTestUnit pEpTestUnit::createRootNode( pEpTestUnit pEpTestUnit::createRootNode(
pEpTestModel& model, pEpTestModel& model,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children) ExecutionMode emode_children)
{ {
pEpTestUnit ret(nullptr, &model, name, main_f, emode_children); pEpTestUnit ret(nullptr, &model, name, test_func, emode_children);
return ret; return ret;
} }
// ChildNode factory // ChildNode factory
//static // static
pEpTestUnit pEpTestUnit::createChildNode( pEpTestUnit pEpTestUnit::createChildNode(
pEpTestUnit& parent, pEpTestUnit& parent,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children) ExecutionMode emode_children)
{ {
pEpTestUnit ret(&parent, nullptr, name, main_f, emode_children); pEpTestUnit ret(&parent, nullptr, name, test_func, emode_children);
return ret; return ret;
} }
//private
// private
pEpTestUnit::pEpTestUnit( pEpTestUnit::pEpTestUnit(
pEpTestUnit* const parent, pEpTestUnit* const parent,
pEpTestModel* model, pEpTestModel* model,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children) : ExecutionMode emode_children) :
parent(parent), parent(parent),
model(model), name(name), main_func(main_f), emode_chld(emode_children) model(model), name(normalizeName(name)), test_func(test_func), emode_chld(emode_children)
{ {
logger.set_instancename(getFQName()); logger.set_instancename(getFQName());
if (parent != nullptr) { if (!isRootNode()) {
parent->addChildNode(*this); parent->addChildNode(*this);
} }
// data_dir_recreate();
} }
//static // static
void pEpTestUnit::setDefaultDataDir(const std::string& dir) void pEpTestUnit::setDefaultDataRoot(const std::string& dir)
{ {
pEpTestUnit::data_dir = dir; pEpTestUnit::data_root = dir;
} }
//static // static
std::string pEpTestUnit::getDataDir() std::string pEpTestUnit::getDataRoot()
{ {
return pEpTestUnit::data_dir; return pEpTestUnit::data_root;
} }
// void TestNode::init() const void pEpTestUnit::init(const pEpTestUnit* caller) const
// { {
// pEpLogClassH2("DistTest - init"); //caller is never nullptr if called from another unit
// for (const pair<string, TestNode> elem : testnodes) { if (caller == nullptr) {}
// string home_dir = getHomeDir(elem.second);
// pEpLogClass("creating home dir for '" + elem.second.getName() + "' - " + home_dir);
// mkdir(home_dir.c_str(), 0770);
// }
// }
// 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::waitChildProcesses() const void pEpTestUnit::addChildNode(pEpTestUnit& node)
{ {
pEpLogClass("Waiting for child processes to terminate..."); children.insert(pair<string, pEpTestUnit&>(node.getName(), node));
int status;
pid_t pid;
while ((pid = wait(&status)) > 0) {
pEpLogClass(
"process[" + std::to_string((int)pid) +
"] terminated with status: " + std::to_string(status));
}
pEpLogClass("All child processes terminated");
} }
void pEpTestUnit::addChildNode(const pEpTestUnit& node) // name is alphanumeric only (everything else will be replaced by an underscore)
// private
string pEpTestUnit::normalizeName(string name) const
{ {
children.insert(pair<string, const pEpTestUnit&>(node.getName(), node)); replace_if(
name.begin(),
name.end(),
[](char c) -> bool { return !isalnum(c); },
'_');
return name;
} }
string pEpTestUnit::getName() const string pEpTestUnit::getName() const
@ -102,40 +104,59 @@ namespace pEp {
return name; return name;
} }
void pEpTestUnit::run(const pEpTestUnit* caller) const // 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"); pEpLogClass("called");
// caller is never nullptr if called by another pEpTestUnit // caller is never nullptr if called by another pEpTestUnit
if(caller == nullptr) { if (caller == nullptr) {
pEpLogClass("\n" + to_string()); pEpLogClass("\n" + to_string());
} }
if (main_func) { if (test_func) {
main_func(*this); test_func(*this);
} else { } else {
pEpLogClass("No function to execute"); pEpLogClass("No function to execute");
} }
executeChildren(); executeChildren();
} }
//private // private
void pEpTestUnit::executeChildren() const void pEpTestUnit::executeChildren() const
{ {
if (!children.empty()) { if (!children.empty()) {
const ExecutionMode& emode = getEffectiveExecutionMode(); const ExecutionMode& emode = getEffectiveExecutionMode();
pEpLogClass(string("Executing children as: " + to_string(emode))); for (const pair<string, pEpTestUnit&> elem : children) {
for (const pair<string, const pEpTestUnit&> elem : children) { // Execute in fork and wait here until process ends
// Execute in fork and go on, wait for process execution in the end if (emode == ExecutionMode::PROCESS_SERIAL) { // fork
if (emode == ExecutionMode::PROCESS_PARALLEL) { // fork executeForked(elem.second);
executeForked(elem.second, false); waitChildProcesses();
// Execute in fork and wait here until process ends // Execute in fork and go on, wait for process execution in the end
} else if (emode == ExecutionMode::PROCESS_SERIAL) { } else if (emode == ExecutionMode::PROCESS_PARALLEL) {
executeForked(elem.second, true); executeForked(elem.second);
// Execute as normal funciton // Execute as normal funciton
} else if (emode == ExecutionMode::FUNCTION) { } else if (emode == ExecutionMode::FUNCTION) {
pEpLogClass("Executing in same process and thread");
elem.second.run(this); elem.second.run(this);
pEpLogClass("Execution ended");
} else if (emode == ExecutionMode::THREAD_PARALLEL) { } else if (emode == ExecutionMode::THREAD_PARALLEL) {
throw runtime_error(to_string(emode) + " - not implemented"); throw runtime_error(to_string(emode) + " - not implemented");
} else if (emode == ExecutionMode::THREAD_SERIAL) { } else if (emode == ExecutionMode::THREAD_SERIAL) {
@ -148,25 +169,33 @@ namespace pEp {
} }
} }
//private // private
void pEpTestUnit::executeForked(const pEpTestUnit& unit, bool wait) const void pEpTestUnit::executeForked(pEpTestUnit& unit) const
{ {
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
if (pid == pid_t(0)) { if (pid == pid_t(0)) {
pEpLogClass(string("In pid: [" + std::to_string(getpid()) + "] - starting...")); // setenv("HOME", evalHomeDir().c_str(), 1);
setenv("HOME", getHomeDir().c_str(), 1);
unit.run(this); unit.run(this);
pEpLogClass(string("In pid: [" + std::to_string(getpid()) + "] - ended."));
exit(0); exit(0);
} else if (pid < pid_t(0)) { } else if (pid < pid_t(0)) {
pEpLogClass("Error forking"); pEpLogClass("Error forking");
} }
if (wait) { }
waitChildProcesses();
// 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 pEpTestModel& pEpTestUnit::getModel() const
{ {
// pEpLogClass("called"); // pEpLogClass("called");
@ -186,7 +215,7 @@ namespace pEp {
{ {
// pEpLogClass("called"); // pEpLogClass("called");
const pEpTestUnit* ret = nullptr; const pEpTestUnit* ret = nullptr;
if (parent != nullptr) { if (!isRootNode()) {
ret = &parent->getRoot(); ret = &parent->getRoot();
} else { } else {
ret = this; ret = this;
@ -197,20 +226,41 @@ namespace pEp {
return *ret; return *ret;
} }
string pEpTestUnit::getHomeDir() const string pEpTestUnit::getFQNameNormalized() const
{ {
return getDataDir() + "/" + getName(); return normalizeName(getFQName());
} }
string pEpTestUnit::getFQName() const string pEpTestUnit::getFQName() const
{ {
string ret;
// pEpLogClass("called"); // pEpLogClass("called");
string ret;
if (parent != nullptr) { if (!isRootNode()) {
ret = parent->getFQName() + "/" + getName(); ret = parent->getFQName() + "/" + getName();
} else { } else {
ret = "/" + getName(); 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; return ret;
} }
@ -218,15 +268,16 @@ namespace pEp {
void pEpTestUnit::data_dir_delete() void pEpTestUnit::data_dir_delete()
{ {
try { try {
Utils::path_delete_all(getDataDir()); Utils::path_delete_all(getDataRoot());
} catch (const exception& e) { } catch (const exception& e) {
pEpLogClass("DistTest: - could not delete data dir: " + getDataDir()); pEpLogClass("DistTest: - could not delete data dir: " + getDataRoot());
} }
} }
void pEpTestUnit::data_dir_create() void pEpTestUnit::data_dir_create()
{ {
Utils::dir_create(getDataDir()); // Utils::dir_create(getDataDir());
pEpLogClass("creating dir:" + getDataRoot());
} }
void pEpTestUnit::data_dir_recreate() void pEpTestUnit::data_dir_recreate()
@ -235,7 +286,7 @@ namespace pEp {
data_dir_create(); data_dir_create();
}; };
//static // static
void pEpTestUnit::setDefaultExecutionMode(ExecutionMode emode) void pEpTestUnit::setDefaultExecutionMode(ExecutionMode emode)
{ {
pEpTestUnit::emode_default = emode; pEpTestUnit::emode_default = emode;
@ -250,7 +301,7 @@ namespace pEp {
{ {
ExecutionMode ret{ emode_default }; ExecutionMode ret{ emode_default };
if (getExecutionMode() == ExecutionMode::INHERIT) { if (getExecutionMode() == ExecutionMode::INHERIT) {
if (parent != nullptr) { if (!isRootNode()) {
// get from parent until not inherit // get from parent until not inherit
ret = parent->getEffectiveExecutionMode(); ret = parent->getEffectiveExecutionMode();
} }
@ -280,7 +331,7 @@ namespace pEp {
} }
} }
std::string pEpTestUnit::to_string(bool recursive, int indent) const string pEpTestUnit::to_string(bool recursive, int indent) const
{ {
string ret; string ret;
stringstream builder; stringstream builder;
@ -299,5 +350,30 @@ namespace pEp {
} }
return ret; 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 Test
} // namespace pEp } // namespace pEp

42
test/pEpTest/src/pEpTestUnit.hh

@ -34,62 +34,70 @@ namespace pEp {
static pEpTestUnit createRootNode( static pEpTestUnit createRootNode(
pEpTestModel& model, pEpTestModel& model,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children = emode_default); ExecutionMode emode_children = emode_default);
static pEpTestUnit createChildNode( static pEpTestUnit createChildNode(
pEpTestUnit& parent, pEpTestUnit& parent,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children = emode_default); ExecutionMode emode_children = emode_default);
void init(const pEpTestUnit* caller = nullptr) const;
static void setDefaultDataDir(const std::string& dir); static void setDefaultDataRoot(const std::string& dir);
static std::string getDataDir(); static std::string getDataRoot();
void addChildNode(const pEpTestUnit& node); void addChildNode(pEpTestUnit& node);
void run(const pEpTestUnit* caller = nullptr) const; void run(const pEpTestUnit* caller = nullptr);
std::string getName() const; std::string getName() const;
std::string getFQName() const; std::string getFQName() const;
std::string getFQNameNormalized() const;
pEpTestModel& getModel() const; pEpTestModel& getModel() const;
std::string getHomeDir() const; std::string getDataDir() const;
const pEpTestUnit& getParentProcessUnit() const;
std::string to_string(bool recursive = true, int indent = 0) const; std::string to_string(bool recursive = true, int indent = 0) const;
static void setDefaultExecutionMode(ExecutionMode emode); 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: private:
// Constructors // Constructors
explicit pEpTestUnit( explicit pEpTestUnit(
pEpTestUnit* parent, pEpTestUnit* parent,
pEpTestModel* model, pEpTestModel* model,
const std::string& name, const std::string& name,
const TestUnitFunction& main_f, const TestUnitFunction& test_func,
ExecutionMode emode_children); ExecutionMode emode_children);
// Methods // Methods
void init() const;
const pEpTestUnit& getRoot() const; const pEpTestUnit& getRoot() const;
void executeChildren() const; void executeChildren() const;
void executeForked(const pEpTestUnit& unit, bool wait) const; void executeForked(pEpTestUnit& unit) const;
void waitChildProcesses() const; void waitChildProcesses() const;
ExecutionMode getExecutionMode() const; ExecutionMode getExecutionMode() const;
ExecutionMode getEffectiveExecutionMode() const; ExecutionMode getEffectiveExecutionMode() const;
void data_dir_delete(); void data_dir_delete();
void data_dir_create(); void data_dir_create();
void data_dir_recreate(); void data_dir_recreate();
bool isRootNode() const;
// bool isProcessNode() const;
std::string normalizeName(std::string name) const;
// Fields // Fields
const pEpTestUnit* parent; //nullptr if rootnode const pEpTestUnit* parent; //nullptr if rootnode
const std::string name; const std::string name;
pEpTestModel* model; //nullptr if inherited pEpTestModel* model; //nullptr if inherited
const TestUnitFunction& main_func; const TestUnitFunction& test_func;
const ExecutionMode emode_chld; const ExecutionMode emode_chld;
static ExecutionMode emode_default; static ExecutionMode emode_default;
std::map<const std::string, const pEpTestUnit&> children; std::map<const std::string, pEpTestUnit&> children;
static std::string data_dir; static std::string data_root;
// logger // logger
static bool log_enabled;
Adapter::pEpLog::pEpLogger logger{ "pEpTestUnit", log_enabled };
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger;
}; };
}; // namespace Test }; // namespace Test

58
test/pEpTest/test/test_transport.cc

@ -0,0 +1,58 @@
#include "../src/pEpTestUnit.hh"
#include "../../framework/utils.hh"
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <algorithm>
//#include <regex>
using namespace std;
using namespace pEp;
using namespace pEp::Test;
void printHomeDir(pEpTestUnit& myself)
{
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid())));
// cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl;
setenv("HOME", myself.getDataDir().c_str(), 1);
myself.log("HOME=" + string(getenv("HOME")));
}
int main(int argc, char* argv[])
{
pEpTestModel model{ "TestTransport" };
pEpTestUnit::log_enabled = false;
pEpTestUnit::setDefaultDataRoot("./testdata/");
{
pEpTestUnit root = pEpTestUnit::createRootNode(
model,
"root node nr.1",
[](pEpTestUnit mynode) { printHomeDir(mynode); },
pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_PARALLEL);
pEpTestUnit test1 = pEpTestUnit::createChildNode(root, "node 1", [](pEpTestUnit mynode) {
printHomeDir(mynode);
});
pEpTestUnit test1_1 = pEpTestUnit::createChildNode(test1, "node 1_1", [](pEpTestUnit mynode) {
printHomeDir(mynode);
});
pEpTestUnit test2 = pEpTestUnit::createChildNode(root, "node 2", [](pEpTestUnit mynode) {
printHomeDir(mynode);
});
pEpTestUnit test2_1 = pEpTestUnit::createChildNode(
test2,
"node 2_1",
[](pEpTestUnit mynode) { printHomeDir(mynode); },
pEp::Test::pEpTestUnit::ExecutionMode::PROCESS_PARALLEL);
pEpTestUnit test2_1_1 = pEpTestUnit::createChildNode(test2_1, "node 1", [](pEpTestUnit mynode) {
printHomeDir(mynode);
});
root.run();
}
}
Loading…
Cancel
Save