dependency management implemented -- this should be polished later to say the task name in the exception message. last feature to implement is logging.

master
Phanes 2017-12-03 14:10:09 -05:00
parent c92be3f4be
commit 5f85185e8d
7 changed files with 109 additions and 43 deletions

View File

@ -1,4 +1,5 @@
{ {
"units_path": "/home/phanes/development/internal/Examplar/conf/units/all_test.units", "units_path": "/home/phanes/development/internal/Examplar/conf/units/all_test.units",
"plan_path": "/home/phanes/development/internal/Examplar/conf/plans/test.plan" "plan_path": "/home/phanes/development/internal/Examplar/conf/plans/test.plan",
"config_version": "1"
} }

View File

@ -2,6 +2,6 @@
"plan": [ "plan": [
{ "name": "independent test 1", "dependencies": [ null ] }, { "name": "independent test 1", "dependencies": [ null ] },
{ "name": "independent test 2", "dependencies": [ null ] }, { "name": "independent test 2", "dependencies": [ null ] },
{ "name": "dependent test", "dependencies": [ "independent test 1", null, null ] } { "name": "dependent test", "dependencies": [ "independent test 1" ] }
] ]
} }

View File

@ -5,13 +5,13 @@
"target": "/usr/bin/false", "target": "/usr/bin/false",
"rectifier": "/usr/bin/true", "rectifier": "/usr/bin/true",
"active": true, "active": true,
"required": true, "required": false,
"rectify": true "rectify": true
}, },
{ {
"name": "independent test 2", "name": "independent test 2",
"target": "/usr/bin/false", "target": "/usr/bin/true",
"rectifier": "/usr/bin/false", "rectifier": "/usr/bin/true",
"active": true, "active": true,
"required": false, "required": false,
"rectify": false "rectify": false
@ -26,7 +26,7 @@
}, },
{ {
"name": "dependent test", "name": "dependent test",
"target": "ssh root@phanes.silogroup.org", "target": "/usr/bin/true",
"rectifier": "/usr/bin/false", "rectifier": "/usr/bin/false",
"active": true, "active": true,
"required": false, "required": false,

View File

@ -11,6 +11,14 @@ class Plan_InvalidTaskName: public std::runtime_error { public:
Plan_InvalidTaskName(): std::runtime_error("Plan: Attempted to access a Task using an invalid name.") {} Plan_InvalidTaskName(): std::runtime_error("Plan: Attempted to access a Task using an invalid name.") {}
}; };
/// Plan_Task_Missing_Dependency - Exception thrown when a Plan tries to access a contained Task's value by name not present
/// in the Unit.
class Plan_Task_Missing_Dependency: public std::runtime_error { public:
Plan_Task_Missing_Dependency(): std::runtime_error("Plan: Attempted to execute a task that had unmet dependencies.") {}
};
/// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference /// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference
/// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those /// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those
/// definitions to execute, and if Units together form a Suite, Tasks together form a Plan. /// definitions to execute, and if Units together form a Suite, Tasks together form a Plan.
@ -53,7 +61,7 @@ void Plan::load_plan_file(std::string filename, bool verbose)
/// \param result - The variable receiving the value. /// \param result - The variable receiving the value.
/// \param index - The numerical index in the Task vector to retrieve a value for. /// \param index - The numerical index in the Task vector to retrieve a value for.
/// \param verbose - Whether to print verbose output to STDOUT. /// \param verbose - Whether to print verbose output to STDOUT.
void Plan::get_task(Task & result, int index, bool verbose) void Plan::get_task(Task & result, int index )
{ {
if ( index <= this->tasks.size() ) if ( index <= this->tasks.size() )
{ {
@ -63,30 +71,6 @@ void Plan::get_task(Task & result, int index, bool verbose)
} }
} }
/// Plan::get_task - Retrieves a task by name.
///
/// \param result - The variable receiving the value.
/// \param provided_name - The name to find a task by.
/// \param verbose - Whether to print verbose output to STDOUT.
void Plan::get_task(Task & result, std::string provided_name, bool verbose)
{
bool foundMatch = false;
for ( int i = 0; i < this->tasks.size(); i++ )
{
if ( this->tasks[i].get_name() == provided_name )
{
result = this->tasks[i];
foundMatch = true;
break;
}
}
if (! foundMatch )
{
std::cerr << "Task name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
throw Plan_InvalidTaskName();
}
}
/// Plan::load_definitions - Load the units corresponding to each task in plan from the given Suite. /// Plan::load_definitions - Load the units corresponding to each task in plan from the given Suite.
/// ///
@ -108,6 +92,63 @@ void Plan::load_definitions( Suite unit_definitions, bool verbose )
} }
} }
/// Plan::get_task - Retrieves a task by name.
///
/// \param result - The variable receiving the value.
/// \param provided_name - The name to find a task by.
/// \param verbose - Whether to print verbose output to STDOUT.
void Plan::get_task(Task & result, std::string provided_name )
{
bool foundMatch = false;
for ( int i = 0; i < this->tasks.size(); i++ )
{
if ( this->tasks[i].get_name() == provided_name )
{
result = this->tasks[i];
foundMatch = true;
break;
}
}
if (! foundMatch )
{
std::cerr << "Task name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
throw Plan_InvalidTaskName();
}
}
// TODO dependency check goes here
// This should check to see if there are unmet dependencies.
// done -- add a "completed" attribute to Task
// Iterate through Task::dependencies, a vector attached to tasks[i] containing task names
// use Plan::get_task( name ) method to retrieve that task
// check if it is in a ready state
// return ready/not ready
bool Plan::all_dependencies_complete(std::string name)
{
// get the task by name
Task named_task;
this->get_task( named_task, name );
// get the dependencies of that task
std::vector<std::string> deps = named_task.get_dependencies();
// create an empty task to assign values to during iteration
Task tmpTask;
// iterate through its dependencies
for ( int i = 0; i < deps.size(); i++ )
{
this->get_task( tmpTask, deps[i]);
if (! tmpTask.is_complete() )
{
// error message?
return false;
}
}
return true;
}
/// Plan::execute() - Iterates through all tasks in a plan and executes them. /// Plan::execute() - Iterates through all tasks in a plan and executes them.
/// ///
/// \param verbose /// \param verbose
@ -116,15 +157,17 @@ void Plan::execute( bool verbose )
// for each task in this plan // for each task in this plan
for ( int i = 0; i < this->tasks.size(); i++ ) for ( int i = 0; i < this->tasks.size(); i++ )
{ {
if ( verbose ) { if (this->all_dependencies_complete(this->tasks[i].get_name()) )
std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl; {
// std::cout << "Executing task \"" << this->tasks[0].get_name() << "\"." << std::endl; if ( verbose )
{
std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl;
}
this->tasks[i].execute( verbose );
} else {
throw Plan_Task_Missing_Dependency();
// not all deps met for this task
} }
this->tasks[i].execute( verbose );
// this->tasks[0].execute( verbose );
// for testing a logic issue in Task.execute(), remove when done
// throw Plan_InvalidTaskIndex();
} }
} }

View File

@ -19,10 +19,10 @@ class Plan: public JSON_Loader
void load_plan_file( std::string filename, bool verbose ); void load_plan_file( std::string filename, bool verbose );
// fetch a task from this->tasks // fetch a task from this->tasks
void get_task( Task & result, std::string provided_name, bool verbose ); void get_task( Task & result, std::string provided_name );
// fetch a task from this->tasks // fetch a task from this->tasks
void get_task( Task & result, int index, bool verbose ); void get_task( Task & result, int index );
// load unit definitions from a provided suite and import them into individual tasks // load unit definitions from a provided suite and import them into individual tasks
void load_definitions( Suite unit_definitions, bool verbose ); void load_definitions( Suite unit_definitions, bool verbose );
@ -32,6 +32,8 @@ class Plan: public JSON_Loader
// execute all tasks in this plan // execute all tasks in this plan
void execute( bool verbose ); void execute( bool verbose );
bool all_dependencies_complete(std::string name);
}; };
#endif //FTESTS_PLAN_H #endif //FTESTS_PLAN_H

View File

@ -91,6 +91,20 @@ bool Task::is_complete()
return this->complete; return this->complete;
} }
/// Task::mark_complete - Marks the task complete..
void Task::mark_complete()
{
this->complete = true;
}
/// Task::get_dependencies - returns a pointer to the dependencies vector.
std::vector<std::string> Task::get_dependencies()
{
return this->dependencies;
}
/// Task::has_definition - Indicator if the task has attached its definition from a Suite. /// Task::has_definition - Indicator if the task has attached its definition from a Suite.
bool Task::has_definition() bool Task::has_definition()
{ {
@ -102,10 +116,10 @@ bool Task::has_definition()
/// \param verbose - Verbosity level - not implemented yet. /// \param verbose - Verbosity level - not implemented yet.
void Task::execute( bool verbose ) void Task::execute( bool verbose )
{ {
// DUFFING // DUFFING - If Examplar is broken it's probably going to be in this block.
// PREWORK // PREWORK
// throw if unit not coupled to all necessary values since Task is stateful (stateful is okay) // throw if unit not coupled to all necessary values since Task is stateful (yes, stateful is okay)
if (! this->has_definition() ) { if (! this->has_definition() ) {
throw Task_NotReady(); throw Task_NotReady();
} }
@ -133,6 +147,7 @@ void Task::execute( bool verbose )
if ( verbose ) { if ( verbose ) {
std::cout << "\tTarget " << task_name << " succeeded." << std::endl; std::cout << "\tTarget " << task_name << " succeeded." << std::endl;
} }
this->mark_complete();
// next // next
} else { } else {
// Non-Zero d[0] from initial target execution, get to d[1] // Non-Zero d[0] from initial target execution, get to d[1]

View File

@ -42,6 +42,11 @@ class Task
// execute this task's definition // execute this task's definition
void execute( bool verbose ); void execute( bool verbose );
void mark_complete();
// returns a pointer to the dependencies vector
std::vector<std::string> get_dependencies();
}; };
#endif //FTESTS_TASK_H #endif //FTESTS_TASK_H