Browse Source

Test: PityTest11 dir rename

master
heck 4 years ago
commit
e50ed656d7
  1. 29
      Makefile
  2. 16
      src/PityModel.cc
  3. 26
      src/PityModel.hh
  4. 113
      src/PityUnit.hh
  5. 390
      src/PityUnit.hxx
  6. 65
      test/test_execmodes.cc
  7. 55
      test/test_processdirs.cc

29
Makefile

@ -0,0 +1,29 @@
LDLIBS=-lstdc++ -lpEpAdapter
LDFLAGS=-L../../src/
CXXFLAGS=-std=c++11 -g
CXXFLAGS+=-I./src
TEST_EXTRA_OBJS=../framework/utils.o
# Src
SRC=$(wildcard src/*.cc)
OBJ=$(subst .cc,.o,$(SRC))
# Tests
TEST_SRC=$(wildcard test/*.cc)
TEST_OBJ=$(subst .cc,,$(TEST_SRC))
.PHONY: all clean rmtestdata
.DEFAULT_GOAL := all
all: $(TEST_OBJ)
$(TEST_OBJ): $(OBJ) $(TEST_EXTRA_OBJS)
clean:
rm -f $(OBJ)
rm -f $(TEST_OBJ)
rm -rf src/*.dSYM
rm -rf test/*.dSYM

16
src/PityModel.cc

@ -0,0 +1,16 @@
#include "PityModel.hh"
#include "iostream"
using namespace std;
namespace pEp {
namespace PityTest11 {
bool PityModel::log_enabled = true;
PityModel::PityModel(const string& name) : name(name) {}
const std::string& PityModel::getName() const
{
return name;
}
} // namespace Test
} // namespace pEp

26
src/PityModel.hh

@ -0,0 +1,26 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef PITYTEST_PITYMODEL_HH
#define PITYTEST_PITYMODEL_HH
#include "../../../src/pEpLog.hh"
namespace pEp {
namespace PityTest11 {
class PityModel {
public:
PityModel() = delete;
PityModel(const std::string& name);
virtual const std::string& getName() const;
private:
const std::string name;
static bool log_enabled;
Adapter::pEpLog::pEpLogger logger{ "PityModel", log_enabled };
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger;
};
}; // namespace Test
}; // namespace pEp
#endif // PITYTEST_PITYMODEL_HH

113
src/PityUnit.hh

@ -0,0 +1,113 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef PITYTEST_PITYUNIT_HH
#define PITYTEST_PITYUNIT_HH
#include <string>
#include <functional>
#include <map>
#include "../../../src/pEpLog.hh"
// Yes, the mem mgmt is purely static on purpose (so far)
namespace pEp {
namespace PityTest11 {
template<class T = void>
class PityUnit {
public:
using NodeFunc = std::function<void(const PityUnit&)>;
enum class ExecutionMode
{
FUNCTION,
PROCESS_SEQUENTIAL,
PROCESS_PARALLEL,
THREAD_SEQUENTIAL, // unimplemented
THREAD_PARALLEL, // unimplemented
INHERIT
};
// Constructors are private
PityUnit() = delete;
explicit PityUnit(
PityUnit* parent,
const std::string& name,
const NodeFunc test_func = nullptr,
T* model = nullptr,
ExecutionMode exec_mode = ExecutionMode::FUNCTION);
// Read-Only
std::string getNodeName() const;
std::string getNodePath() const;
std::string getNodePathShort() const;
T* getModel() const;
std::string rootNodeDir() const;
std::string processDir() const; // own process dir
// Read-Write
void setExecutionMode(ExecutionMode mode);
static void setGlobalRootDir(const std::string& dir);
static std::string getGlobalRootDir();
// Main funcs
void run() 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{ "PityUnit", debug_log_enabled };
private:
// CONSTRUCTORS
// METHODS
// Execution
void _runRootNode() const;
void _run() const;
void _runSelf() const;
void _runChildren() const;
void _executeInFork(std::function<void(void)> func, bool wait_child) const;
void _waitChildProcesses() const;
// Modify
void _addChildNode(PityUnit& node);
// Query
bool _isProcessNode() const;
bool _isRootNode() const;
const PityUnit& _rootNode() const;
const PityUnit& _parentingProcessNode() 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 PityUnit* _parent; //nullptr if RootUnit
T* _model; //nullptr if inherited
const NodeFunc _test_func;
ExecutionMode _exec_mode;
static std::string _global_root_dir;
std::map<const std::string, PityUnit&> _children; // map to guarantee uniqueness of sibling-names
// internal logging
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger_debug;
};
}; // namespace Test
}; // namespace pEp
#include "PityUnit.hxx"
#endif // PITYTEST_PITYUNIT_HH

390
src/PityUnit.hxx

@ -0,0 +1,390 @@
// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef PITYTEST_PITYUNIT_HXX
#define PITYTEST_PITYUNIT_HXX
#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 pEp::Adapter::pEpLog;
namespace pEp {
namespace PityTest11 {
template<class T>
std::string PityUnit<T>::_global_root_dir = "./pitytest";
template<class T>
bool PityUnit<T>::debug_log_enabled = false;
// PUBLIC CONCSTRUCTORS / FACTORY -----------------------------------------------------------
template<class T>
PityUnit<T>::PityUnit(
PityUnit* const parent,
const std::string& name,
const NodeFunc test_func,
T* model,
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);
}
}
template<class T>
std::string PityUnit<T>::getNodeName() const
{
return _name;
}
template<class T>
std::string PityUnit<T>::getNodePath() const
{
std::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"
template<class T>
std::string PityUnit<T>::getNodePathShort() const
{
std::string ret;
if (_isRootNode()) {
ret = getNodeName();
} else {
if (_isProcessNode()) {
ret += ".../" + getNodeName();
} else {
if (&(_parentingProcessNode()) == (_parent)) {
ret = _parentingProcessNode().getNodePathShort() + "/" + getNodeName();
} else {
ret = _parentingProcessNode().getNodePathShort() + "/.../" + getNodeName();
}
}
}
return ret;
}
// Inherited (if null see parent recursively)
template<class T>
T* PityUnit<T>::getModel() const
{
pEpLogClass("called");
T* ret = nullptr;
if (_model != nullptr) {
ret = _model;
} else {
if (!_isRootNode()) {
ret = _parent->getModel();
}
}
return ret;
}
// Every RootNode has its own dir
template<class T>
std::string PityUnit<T>::rootNodeDir() const
{
return getGlobalRootDir() + _rootNode().getNodeName() + "/";
}
// Every process has its own dir inside its rootNodeDir
// All other nodes inherit processDir from their Root/ProcessNode
template<class T>
std::string PityUnit<T>::processDir() const
{
if (_isRootNode()) {
return rootNodeDir();
} else {
if (_isProcessNode()) {
return rootNodeDir() + getNodeName() + "/";
} else{
return _parent->processDir();
}
}
}
template<class T>
void PityUnit<T>::setExecutionMode(ExecutionMode mode)
{
_exec_mode = mode;
}
// static
template<>
void PityUnit<void>::setGlobalRootDir(const std::string& dir)
{
PityUnit::_global_root_dir = dir;
}
// static
template<class T>
std::string PityUnit<T>::getGlobalRootDir()
{
return PityUnit::_global_root_dir;
}
template<class T>
void PityUnit<T>::run() const
{
pEpLogClass("called");
// caller is never nullptr if called by another PityUnit
if (_isRootNode()) {
logH1("Starting PityUnit from node: " + getNodePathShort());
log(to_string());
}
// Execute in fork and wait here until process ends
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL) { // fork
logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]");
_executeInFork(std::bind(&PityUnit::_run, this), true);
// Execute in fork and go on, wait for process execution in the end
} else if (_exec_mode == ExecutionMode::PROCESS_PARALLEL) {
logH2("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]");
_executeInFork(std::bind(&PityUnit::_run, this), false);
// Execute as normal funciton
} else if (_exec_mode == ExecutionMode::FUNCTION) {
logH3("[ " + to_string(_exec_mode) + " / " + getNodePathShort() + " ]");
_run();
} else if (_exec_mode == ExecutionMode::THREAD_PARALLEL) {
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented");
} else if (_exec_mode == ExecutionMode::THREAD_SEQUENTIAL) {
throw std::invalid_argument(to_string(_exec_mode) + " - not implemented");
}
if(_isRootNode()) {
_waitChildProcesses();
}
}
template<class T>
std::string PityUnit<T>::to_string(bool recursive, int indent) const
{
std::string ret;
std::stringstream builder;
builder << std::string(indent * 4, ' ');
builder << getNodeName();
builder << " [ ";
builder << to_string(_exec_mode) << " - ";
builder << "\"" << processDir() << "\"";
builder << " ]";
builder << std::endl;
ret = builder.str();
if (recursive) {
indent++;
for (const std::pair<std::string, const PityUnit&> child : _children) {
ret += child.second.to_string(true, indent);
}
indent--;
}
return ret;
}
template<class T>
std::string PityUnit<T>::to_string(const ExecutionMode& emode)
{
switch (emode) {
case ExecutionMode::FUNCTION:
return "FUNCTION";
case ExecutionMode::PROCESS_SEQUENTIAL:
return "PROC_SEQ";
case ExecutionMode::PROCESS_PARALLEL:
return "PROC_PAR";
case ExecutionMode::THREAD_SEQUENTIAL:
return "THREAD_S";
case ExecutionMode::THREAD_PARALLEL:
return "THREAD_P";
case ExecutionMode::INHERIT:
return "INHERIT";
default:
return "UNDEFINED EXECUTION MODE";
}
}
//Well, ok, lets just add some little convenience logging service in here, too
template<class T>
void PityUnit<T>::log(const std::string& msg) const
{
std::stringstream builder;
builder << "[";
builder << std::to_string(getpid());
builder << " - ";
builder << getNodePathShort();
builder << "] - ";
builder << msg;
builder << std::endl;
std::cout << builder.str();
}
// PRIVATE ---------------------------------------------------------------------------------
template<class T>
void PityUnit<T>::_run() const
{
_runSelf();
_runChildren();
}
template<class T>
void PityUnit<T>::_runSelf() const
{
if (_test_func != nullptr) {
_test_func(*this);
} else {
log("No function to execute");
}
}
template<class T>
void PityUnit<T>::_runChildren() const
{
if (!_children.empty()) {
for (const std::pair<std::string, PityUnit&> child : _children) {
child.second.run();
}
}
}
template<class T>
void PityUnit<T>::_executeInFork(std::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 std::runtime_error("Error forking");
}
if (wait_child) {
_waitChildProcesses();
}
}
template<class T>
void PityUnit<T>::_waitChildProcesses() const
{
int status;
pid_t pid;
while ((pid = wait(&status)) > 0) {
log(
"process[" + std::to_string((int)pid) +
"] terminated with status: " + std::to_string(status));
}
}
template<class T>
void PityUnit<T>::_addChildNode(PityUnit& node)
{
_children.insert(std::pair<std::string, PityUnit&>(node.getNodeName(), node));
}
template<class T>
bool PityUnit<T>::_isProcessNode() const
{
bool ret = false;
if (_exec_mode == ExecutionMode::PROCESS_SEQUENTIAL ||
_exec_mode == ExecutionMode::PROCESS_PARALLEL) {
ret = true;
}
return ret;
}
template<class T>
bool PityUnit<T>::_isRootNode() const
{
if (_parent == nullptr) {
return true;
} else {
return false;
}
}
template<class T>
const PityUnit<T>& PityUnit<T>::_rootNode() const
{
const PityUnit* ret = nullptr;
if (!_isRootNode()) {
ret = &(_parent->_rootNode());
} 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;
}
template<class T>
const PityUnit<T>& PityUnit<T>::_parentingProcessNode() const
{
if (_isRootNode() || _isProcessNode()) {
return *this;
} else {
return _parent->_parentingProcessNode();
}
}
// name is alphanumeric only (everything else will be replaced by an underscore)
template<class T>
std::string PityUnit<T>::_normalizeName(std::string name) const
{
replace_if(
name.begin(),
name.end(),
[](char c) -> bool { return !isalnum(c); },
'_');
return name;
}
template<class T>
void PityUnit<T>::_data_dir_create()
{
// Utils::dir_create(dataDir());
log("creating dir:" + getGlobalRootDir());
}
template<class T>
void PityUnit<T>::_data_dir_delete()
{
try {
Utils::path_delete_all(getGlobalRootDir());
} catch (const std::exception& e) {
log("DistTest: - could not delete data dir: " + getGlobalRootDir());
}
}
template<class T>
void PityUnit<T>::_data_dir_recreate()
{
_data_dir_delete();
_data_dir_create();
};
} // namespace Test
} // namespace pEp
#endif // PITYTEST_PITYUNIT_HXX

65
test/test_execmodes.cc

@ -0,0 +1,65 @@
#include "../src/PityUnit.hh"
#include <iostream>
using namespace std;
using namespace pEp::PityTest11;
void printHomeDir(const PityUnit<>& myself, int sleepmilis, int rep_count)
{
int i = 0;
while (i < rep_count) {
myself.log(myself.getNodeName() + " - " + to_string(i));
sleep_millis(sleepmilis);
i++;
}
}
int main(int argc, char* argv[])
{
{
// DEBUG Logging of PityTestUnit itself
PityUnit<>::debug_log_enabled = false;
// Configure DataRoot for all TestNodes
PityUnit<>::setGlobalRootDir("./basic_data_root");
// The RootNode is the
PityUnit<> root = PityUnit<>{ nullptr, "Test Execution Model" };
// Subprocess 1
PityUnit<> test1 = PityUnit<>{ &root,
"node1",
[](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
},
nullptr,
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL };
PityUnit<> test1_1 = PityUnit<>{ &test1, "test1.1", [](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
} };
PityUnit<> test1_2 = PityUnit<>{ &test1, "test1.2", [](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
} };
// Subprocess 2
PityUnit<> test2 = PityUnit<>{ &root,
"node2",
[](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
},
nullptr,
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL };
PityUnit<> test2_1 = PityUnit<>{ &test2, "test2.1", [](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
} };
PityUnit<> test2_2 = PityUnit<>{ &test2, "test2.2", [](const PityUnit<>& mynode) {
printHomeDir(mynode, 200, 10);
} };
test1.run();
}
}

55
test/test_processdirs.cc

@ -0,0 +1,55 @@
#include "../src/PityUnit.hh"
#include "../../framework/utils.hh"
#include <iostream>
#include <algorithm>
using namespace std;
using namespace pEp::PityTest11;
void printHomeDir(const PityUnit<>& myself)
{
// TESTLOG(string(myself.getFQName() + " - PID: " + to_string(getpid())));
// cout << "[" << to_string(getpid()) << "/" << myself.getFQName() << "] - " << endl;
setenv("HOME", myself.processDir().c_str(), 1);
myself.log("HOME=" + string(getenv("HOME")));
}
void ptAssert(bool condition) {
if(!condition) {
}
}
int main(int argc, char* argv[])
{
PityUnit<>::debug_log_enabled = false;
PityUnit<>::setGlobalRootDir("./");
PityUnit<> root = PityUnit<>{ nullptr, "rootnode" };
PityUnit<> test1 = PityUnit<>{ &root, "node 1", [](const PityUnit<>& mynode) {
assert(mynode.processDir() == "./rootnode/");
} };
PityUnit<> test1_1 = PityUnit<>{ &test1, "node 1.1", [](const PityUnit<>& mynode) {
assert(mynode.processDir() == "./rootnode/");
} };
PityUnit<> test2 = PityUnit<>{ &root, "node 2", [](const PityUnit<>& mynode) {
assert(mynode.processDir() == "./rootnode/");
} };
PityUnit<> test2_1 = PityUnit<>{ &test2,
"node 2.1",
[](const PityUnit<>& mynode) {
assert(mynode.processDir() == "./rootnode/");
},
nullptr,
pEp::PityTest11::PityUnit<>::ExecutionMode::PROCESS_PARALLEL };
PityUnit<> test2_1_1 = PityUnit<>{ &test2_1, "node 2.1.1", [](PityUnit<> mynode) {
assert(mynode.processDir() == "./rootnode/");
} };
root.run();
}
Loading…
Cancel
Save