logic issue being worked, "independent test 1" should be throwing an exception with current settings. Is ignoring the throw call.
parent
19c465bdaf
commit
9e4c88262a
|
@ -2,35 +2,35 @@
|
||||||
"units": [
|
"units": [
|
||||||
{
|
{
|
||||||
"name": "independent test 1",
|
"name": "independent test 1",
|
||||||
"target": "(>&2 echo 'error is a doodle day')",
|
|
||||||
"rectifier": "/usr/bin/true",
|
|
||||||
"active": true,
|
|
||||||
"required": true,
|
|
||||||
"rectify": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "independent test 2",
|
|
||||||
"target": "/usr/bin/false",
|
"target": "/usr/bin/false",
|
||||||
"rectifier": "/usr/bin/true",
|
"rectifier": "/usr/bin/true",
|
||||||
"active": true,
|
"active": true,
|
||||||
"required": true,
|
"required": true,
|
||||||
"rectify": false
|
"rectify": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "independent test 2",
|
||||||
|
"target": "/usr/bin/false",
|
||||||
|
"rectifier": "/usr/bin/false",
|
||||||
|
"active": true,
|
||||||
|
"required": false,
|
||||||
|
"rectify": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "A DEFINITION THAT IS NOT USED",
|
"name": "A DEFINITION THAT IS NOT USED",
|
||||||
"target": "/usr/bin/false",
|
"target": "/usr/bin/false",
|
||||||
"rectifier": "/usr/bin/true",
|
"rectifier": "/usr/bin/false",
|
||||||
"active": true,
|
"active": true,
|
||||||
"required": true,
|
"required": true,
|
||||||
"rectify": false
|
"rectify": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "dependent test",
|
"name": "dependent test",
|
||||||
"target": "/usr/bin/false",
|
"target": "/usr/bin/false",
|
||||||
"rectifier": "/usr/bin/true",
|
"rectifier": "/usr/bin/false",
|
||||||
"active": true,
|
"active": true,
|
||||||
"required": true,
|
"required": true,
|
||||||
"rectify": false
|
"rectify": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ class Task_NotReady: public std::runtime_error { public:
|
||||||
Task_NotReady(): std::runtime_error("Task: Attempted to access a unit of a Task that is not defined.") {}
|
Task_NotReady(): std::runtime_error("Task: Attempted to access a unit of a Task that is not defined.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed.
|
||||||
|
class Task_RequiredButFailedTask: public std::runtime_error { public:
|
||||||
|
Task_RequiredButFailedTask(): std::runtime_error("Task: Attempted to access a unit of a Task that failed, but was required, and the corresponding rectification target also failed..") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed but returned with a zero exit code (dont try to fool the check).
|
||||||
|
class Task_RequiredButRectifierDoesNotHeal: public std::runtime_error { public:
|
||||||
|
Task_RequiredButRectifierDoesNotHeal(): std::runtime_error("Task: The rectification script was executed and reported success, but did not actually heal the faulty condition of the Task target.") {}
|
||||||
|
};
|
||||||
|
|
||||||
/// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to
|
/// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to
|
||||||
/// execute, and its dependencies on other units to have already been completed successfully.
|
/// execute, and its dependencies on other units to have already been completed successfully.
|
||||||
|
@ -86,33 +95,130 @@ bool Task::has_definition() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Task::execute - execute a task's unit definition.
|
/// Task::execute - execute a task's unit definition.
|
||||||
|
/// See the design document for what flow control needs to look like here.
|
||||||
|
/// \param verbose - Verbosity level - not implemented yet.
|
||||||
void Task::execute( bool verbose )
|
void Task::execute( bool verbose )
|
||||||
{
|
{
|
||||||
// throw if unit not coupled
|
// DUFFING
|
||||||
|
|
||||||
|
// PREWORK
|
||||||
|
// throw if unit not coupled to all necessary values since Task is stateful (stateful is okay)
|
||||||
if (! this->has_definition() ) { throw Task_NotReady(); }
|
if (! this->has_definition() ) { throw Task_NotReady(); }
|
||||||
|
|
||||||
|
// get the name
|
||||||
|
std::string task_name = this->definition.get_name();
|
||||||
|
// END PREWORK
|
||||||
|
|
||||||
|
|
||||||
|
// get the target execution command
|
||||||
|
std::string target_command = this->definition.get_target();
|
||||||
|
|
||||||
|
// if we're in verbose mode, do some verbose things
|
||||||
if ( verbose )
|
if ( verbose )
|
||||||
{
|
{
|
||||||
std::cout << "\t Using unit \"" << this->definition.get_name() << "\"." << std::endl;
|
std::cout << "\tUsing unit \"" << task_name << "\"." << std::endl;
|
||||||
std::cout << "\t Executing target \"" << this->definition.get_target() << "\"." << std::endl;
|
std::cout << "\tExecuting target \"" << target_command << "\"." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string executionString = this->definition.get_target();
|
// execute target
|
||||||
std::string rectifierString = this->definition.get_rectifier();
|
int return_code = Sproc::execute( target_command );
|
||||||
|
|
||||||
int return_code = Sproc::execute( executionString );
|
// d[0] check exit code of target
|
||||||
|
if (return_code == 0)
|
||||||
if ( return_code )
|
|
||||||
{
|
{
|
||||||
std::cout << "Process failed with exit code " << return_code << "." << std::endl;
|
// Zero d[0] return from target execution, good to return
|
||||||
|
if ( verbose )
|
||||||
std::cout << "Performing rectification: " << rectifierString << "." << std::endl;
|
|
||||||
int rectifier_error = Sproc::execute( rectifierString );
|
|
||||||
|
|
||||||
if ( rectifier_error )
|
|
||||||
{
|
{
|
||||||
std::cout << "Designated rectification script failed with error " << rectifier_error << "." << std::endl;
|
std::cout << "\tTarget " << task_name << " succeeded." << std::endl;
|
||||||
}
|
}
|
||||||
|
// next
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Non-Zero d[0] from initial target execution, get to d[1]
|
||||||
|
std::cout << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
|
||||||
|
|
||||||
|
// check if rectify pattern is enabled d[1]
|
||||||
|
if ( this->definition.get_rectify() )
|
||||||
|
{
|
||||||
|
// yes d[1]
|
||||||
|
std::cout << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
|
||||||
|
// execute RECTIFIER
|
||||||
|
std::string rectifier_command = this->definition.get_rectifier();
|
||||||
|
std::cout << "\tExecuting rectification: " << rectifier_command << "." << std::endl;
|
||||||
|
int rectifier_error = Sproc::execute( rectifier_command );
|
||||||
|
|
||||||
|
// d[3] check exit code of rectifier
|
||||||
|
if ( rectifier_error )
|
||||||
|
{
|
||||||
|
//d[3] non-zero
|
||||||
|
|
||||||
|
std::cout << "\tRectification of \"" << task_name << "\" failed with exit code " << rectifier_error << "." << std::endl;
|
||||||
|
// d[2] check if REQUIRED
|
||||||
|
if ( this->definition.get_required() )
|
||||||
|
{
|
||||||
|
// d[2] yes
|
||||||
|
// halt/exception
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
} else {
|
||||||
|
// d[2] no
|
||||||
|
// next
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// d[3] zero
|
||||||
|
|
||||||
|
// execute target
|
||||||
|
std::cout << "\tRe-Executing target \"" << this->definition.get_target() << "\"." << std::endl;
|
||||||
|
int retry_code = Sproc::execute( target_command );
|
||||||
|
|
||||||
|
// d[4] exit code of target retry
|
||||||
|
if (retry_code == 0) {
|
||||||
|
// d[4] zero
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// d[4] non-zero
|
||||||
|
// d[5] required check
|
||||||
|
if ( this->definition.get_required() )
|
||||||
|
{
|
||||||
|
// d[5] yes
|
||||||
|
throw Task_RequiredButRectifierDoesNotHeal();
|
||||||
|
} else {
|
||||||
|
// d[5] no
|
||||||
|
// next
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no d[1]
|
||||||
|
std::cout << "\tRectification is not enabled for \"" << task_name << "\"." << std::endl;
|
||||||
|
// required d[2]
|
||||||
|
if ( this->definition.get_required() )
|
||||||
|
{
|
||||||
|
// d[2] yes
|
||||||
|
// This is executing.....
|
||||||
|
std::cout << "\tThis task is required to continue the plan." << std::endl;
|
||||||
|
// but these are NOT executing?????
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
throw Task_RequiredButFailedTask();
|
||||||
|
} else {
|
||||||
|
// d[2] no
|
||||||
|
std::cout << "\tThis task is not required to continue the plan." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -52,13 +52,13 @@ int Unit::load_root(Json::Value loader_root)
|
||||||
{ this->rectifier = loader_root.get("rectifier", errmsg).asString(); } else throw Unit_DataStructureException();
|
{ this->rectifier = loader_root.get("rectifier", errmsg).asString(); } else throw Unit_DataStructureException();
|
||||||
|
|
||||||
if ( loader_root.isMember("active") )
|
if ( loader_root.isMember("active") )
|
||||||
{ this->active = loader_root.get("active", errmsg).asString(); } else throw Unit_DataStructureException();
|
{ this->active = loader_root.get("active", errmsg).asBool(); } else throw Unit_DataStructureException();
|
||||||
|
|
||||||
if ( loader_root.isMember("required") )
|
if ( loader_root.isMember("required") )
|
||||||
{ this->required = loader_root.get("required", errmsg).asString(); } else throw Unit_DataStructureException();
|
{ this->required = loader_root.get("required", errmsg).asBool(); } else throw Unit_DataStructureException();
|
||||||
|
|
||||||
if ( loader_root.isMember("rectify") )
|
if ( loader_root.isMember("rectify") )
|
||||||
{ this->rectify = loader_root.get("rectify", errmsg).asString(); } else throw Unit_DataStructureException();
|
{ this->rectify = loader_root.get("rectify", errmsg).asBool(); } else throw Unit_DataStructureException();
|
||||||
|
|
||||||
this->populated = true;
|
this->populated = true;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ std::string Unit::get_rectifier()
|
||||||
/// Unit::get_active - retrieves the armed status of the unit.
|
/// Unit::get_active - retrieves the armed status of the unit.
|
||||||
///
|
///
|
||||||
/// \return the armed status of the unit.
|
/// \return the armed status of the unit.
|
||||||
std::string Unit::get_active()
|
bool Unit::get_active()
|
||||||
{
|
{
|
||||||
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
||||||
return this->active;
|
return this->active;
|
||||||
|
@ -128,7 +128,7 @@ std::string Unit::get_active()
|
||||||
/// Unit::get_required - retrieves the requirement status of the unit.
|
/// Unit::get_required - retrieves the requirement status of the unit.
|
||||||
///
|
///
|
||||||
/// \return the requirement status of the unit.
|
/// \return the requirement status of the unit.
|
||||||
std::string Unit::get_required()
|
bool Unit::get_required()
|
||||||
{
|
{
|
||||||
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
||||||
return this->required;
|
return this->required;
|
||||||
|
@ -137,7 +137,7 @@ std::string Unit::get_required()
|
||||||
/// Unit::get_rectify - retrieves the rectification status of the unit.
|
/// Unit::get_rectify - retrieves the rectification status of the unit.
|
||||||
///
|
///
|
||||||
/// \return the rectification status of the unit.
|
/// \return the rectification status of the unit.
|
||||||
std::string Unit::get_rectify()
|
bool Unit::get_rectify()
|
||||||
{
|
{
|
||||||
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
if ( ! this->populated ) { throw Unit_NotPopulated(); }
|
||||||
return this->rectify;
|
return this->rectify;
|
||||||
|
|
|
@ -28,15 +28,15 @@ private:
|
||||||
// an indicator of whether the test is active or not
|
// an indicator of whether the test is active or not
|
||||||
// this is used as a way to give definers a way to force executors to edit arbitrary fields or prevent
|
// this is used as a way to give definers a way to force executors to edit arbitrary fields or prevent
|
||||||
// execution of potentially dangerous or intrusive tests
|
// execution of potentially dangerous or intrusive tests
|
||||||
std::string active;
|
bool active;
|
||||||
|
|
||||||
// an indicator of whether or not this test is required to pass.
|
// an indicator of whether or not this test is required to pass.
|
||||||
// intended to be used as a flag to halt execution of further tests on failure
|
// intended to be used as a flag to halt execution of further tests on failure
|
||||||
std::string required;
|
bool required;
|
||||||
|
|
||||||
// indicator of whether the rectifier executable should be run on test failures.
|
// indicator of whether the rectifier executable should be run on test failures.
|
||||||
// if rectifier exits on non-zero return code, it should be trigger the behaviour indicated by required
|
// if rectifier exits on non-zero return code, it should be trigger the behaviour indicated by required
|
||||||
std::string rectify;
|
bool rectify;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Unit();
|
Unit();
|
||||||
|
@ -52,9 +52,9 @@ public:
|
||||||
std::string get_target();
|
std::string get_target();
|
||||||
std::string get_output();
|
std::string get_output();
|
||||||
std::string get_rectifier();
|
std::string get_rectifier();
|
||||||
std::string get_active();
|
bool get_active();
|
||||||
std::string get_required();
|
bool get_required();
|
||||||
std::string get_rectify();
|
bool get_rectify();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FTESTS_UNIT_H
|
#endif //FTESTS_UNIT_H
|
||||||
|
|
|
@ -7,34 +7,23 @@
|
||||||
/// \param input - The commandline input to execute.
|
/// \param input - The commandline input to execute.
|
||||||
/// \return - The return code of the execution of input in the calling shell.
|
/// \return - The return code of the execution of input in the calling shell.
|
||||||
int Sproc::execute(std::string input) {
|
int Sproc::execute(std::string input) {
|
||||||
std::cout << std::endl << "made it to subprocess execution but not implemented yet" << std::endl << std::endl;
|
|
||||||
|
|
||||||
int PIPE_READ = 0;
|
int PIPE_READ = 0;
|
||||||
int PIPE_WRITE = 1;
|
int PIPE_WRITE = 1;
|
||||||
|
|
||||||
int stdin_pipe[2];
|
int stdin_pipe[2];
|
||||||
// int aStderrPipe[2];
|
int stderr_pipe[2];
|
||||||
int stdout_pipe[2];
|
int stdout_pipe[2];
|
||||||
int child_pid;
|
int child_pid;
|
||||||
char nChar;
|
char nChar;
|
||||||
int child_exit_code;
|
int child_exit_code;
|
||||||
|
|
||||||
if (pipe(stdin_pipe) < 0)
|
if ( pipe(stdin_pipe) < 0 )
|
||||||
{
|
{
|
||||||
perror("allocating pipe for child input redirect");
|
perror("allocating pipe for child input redirect");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if ( pipe(stdout_pipe) < 0 )
|
||||||
if (pipe(aStderrPipe < 0)) {
|
|
||||||
close(aStderrPipe[PIPE_READ]);
|
|
||||||
close(aStderrPipe[PIPE_WRITE]);
|
|
||||||
perror("allocating pipe for error redirect");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (pipe(stdout_pipe) < 0)
|
|
||||||
{
|
{
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
|
@ -42,6 +31,14 @@ int Sproc::execute(std::string input) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( pipe(stderr_pipe) < 0 ) {
|
||||||
|
close(stderr_pipe[PIPE_READ]);
|
||||||
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
|
perror("allocating pipe for error redirect");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
child_pid = fork();
|
child_pid = fork();
|
||||||
if (0 == child_pid)
|
if (0 == child_pid)
|
||||||
{
|
{
|
||||||
|
@ -58,41 +55,41 @@ int Sproc::execute(std::string input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirect stderr
|
// redirect stderr
|
||||||
if (dup2(stdout_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
|
if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
|
||||||
exit(errno);
|
exit(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// all these are for use by parent only
|
// all these are for use by parent only
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
close(stdout_pipe[PIPE_READ]);
|
close(stdout_pipe[PIPE_READ]);
|
||||||
close(stdout_pipe[PIPE_WRITE]);
|
close(stdout_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
|
close(stderr_pipe[PIPE_READ]);
|
||||||
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
|
|
||||||
// run child process image
|
// run child process image
|
||||||
// replace this with any exec* function find easier to use ("man exec")
|
// replace this with any exec* function find easier to use ("man exec")
|
||||||
child_exit_code = system( input.c_str() );
|
child_exit_code = system( input.c_str() );
|
||||||
|
|
||||||
|
|
||||||
// if we get here at all, an error occurred, but we are in the child
|
// if we get here at all, an error occurred, but we are in the child
|
||||||
// process, so just exit
|
// process, so just exit
|
||||||
exit(child_exit_code);
|
return WEXITSTATUS(child_exit_code);
|
||||||
} else if (child_pid > 0) {
|
} else if (child_pid > 0) {
|
||||||
// parent continues here
|
// parent continues here
|
||||||
|
|
||||||
// close unused file descriptors, these are for child only
|
// close unused file descriptors, these are for child only
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdout_pipe[PIPE_WRITE]);
|
close(stdout_pipe[PIPE_WRITE]);
|
||||||
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
// da fuq?
|
|
||||||
/* // Include error check here
|
|
||||||
if (NULL != szMessage)
|
|
||||||
{
|
|
||||||
write(stdin_pipe[PIPE_WRITE], szMessage, strlen(szMessage));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Just a char by char read here, you can change it accordingly
|
// Just a char by char read here, you can change it accordingly
|
||||||
while (read(stdout_pipe[PIPE_READ], &nChar, 1) == 1)
|
while ( read( stdout_pipe[PIPE_READ], &nChar, 1 ) == 1 )
|
||||||
{
|
{
|
||||||
|
// does this loop also need to involve STDERR? -CP
|
||||||
write(STDOUT_FILENO, &nChar, 1);
|
write(STDOUT_FILENO, &nChar, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,12 +97,18 @@ int Sproc::execute(std::string input) {
|
||||||
// open of course as long as you want to talk to the child
|
// open of course as long as you want to talk to the child
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
close(stdout_pipe[PIPE_READ]);
|
close(stdout_pipe[PIPE_READ]);
|
||||||
|
close(stderr_pipe[PIPE_READ]);
|
||||||
} else {
|
} else {
|
||||||
// failed to create child
|
// failed to create child
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
close(stdout_pipe[PIPE_READ]);
|
close(stdout_pipe[PIPE_READ]);
|
||||||
close(stdout_pipe[PIPE_WRITE]);
|
close(stdout_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
|
close(stderr_pipe[PIPE_READ]);
|
||||||
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
}
|
}
|
||||||
return child_exit_code;
|
|
||||||
|
return WEXITSTATUS(child_exit_code);
|
||||||
}
|
}
|
Loading…
Reference in New Issue