logging reflow

master
Master 2020-06-20 20:09:32 -04:00
parent 11829aca39
commit 839c3d398a
22 changed files with 370 additions and 332 deletions

View File

@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 3.5)
project(examplar)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1z -O0 -DDEBUG=1")
set(SOURCE_FILES examplar.cpp src/loaders/loaders.cpp src/loaders/loaders.h src/json/jsoncpp.cpp src/loaders/JSON_Loader.cpp src/loaders/JSON_Loader.h src/loaders/helpers.cpp src/loaders/helpers.h src/loaders/Suite.cpp src/loaders/Suite.h src/loaders/Plan.cpp src/loaders/Plan.h src/loaders/Conf.cpp src/loaders/Conf.h src/loaders/Unit.cpp src/loaders/Unit.h src/loaders/Task.cpp src/loaders/Task.h src/sproc/Sproc.cpp src/sproc/Sproc.h)
set(SOURCE_FILES examplar.cpp src/loaders/abstract/loaders.cpp src/loaders/abstract/loaders.h src/json/jsoncpp.cpp src/loaders/low_level/JSON_Loader.cpp src/loaders/low_level/JSON_Loader.h src/loaders/misc/helpers.cpp src/loaders/misc/helpers.h src/loaders/abstract/Suite.cpp src/loaders/abstract/Suite.h src/loaders/abstract/Plan.cpp src/loaders/abstract/Plan.h src/loaders/abstract/Conf.cpp src/loaders/abstract/Conf.h src/loaders/abstract/Unit.cpp src/loaders/abstract/Unit.h src/loaders/abstract/Task.cpp src/loaders/abstract/Task.h src/Sproc/Sproc.cpp src/Sproc/Sproc.h src/Logger/Logger.cpp src/Logger/Logger.h)
add_executable(examplar ${SOURCE_FILES})

View File

@ -19,28 +19,22 @@
*/
#include <iostream>
#include "src/json/json.h"
#include "src/loaders/loaders.h"
#include <unistd.h>
#include <getopt.h>
#include <syslog.h>
#include "src/loaders/helpers.h"
/*
* TODO Commandline switches
*/
#include "src/json/json.h"
#include "src/loaders/abstract/loaders.h"
#include "src/Logger/Logger.h"
#include "src/loaders/misc/helpers.h"
void print_usage()
{
printf("examplar [ -h | --help ] [ -v | --verbose ] [ -e | --execution-context EXECUTION_CONTEXT ][ -c | --config CONFIG_PATH ]\n\n");
}
int main( int argc, char * argv[] )
{
int flags, opt;
int opt;
bool verbose = false;
bool show_help = false;
@ -100,66 +94,67 @@ int main( int argc, char * argv[] )
}
}
if ( show_help == true )
if ( show_help )
{
print_usage();
exit( 0 );
}
setlogmask( LOG_UPTO( LOG_INFO ) );
int L_LEVEL = E_INFO;
if ( verbose )
{
L_LEVEL = E_DEBUG;
} else {
L_LEVEL = E_INFO;
}
openlog( "Examplar", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_PERROR | LOG_LOCAL1 );
Logger slog = Logger( L_LEVEL, "Examplar" );
// A Plan is made up of Tasks, and a Suite is made up of Units.
// A Plan declares what units are executed and a Suite declares the definitions of those units.
Conf configuration = Conf(config_path, verbose );
// if the user set this option as a commandline argument
if ( cli_context_supplied == true )
{
// override the conf file's specified execution context
configuration.set_execution_context( execution_context );
}
Conf configuration = Conf(config_path, L_LEVEL );
// check if context override
if ( configuration.has_context_override() )
{
// if so, set the CWD.
chdir( configuration.get_execution_context().c_str() );
std::ostringstream infostring;
infostring << "Execution context: " << get_working_path() << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
slog.log( E_DEBUG, "Set execution context: " + get_working_path() );
}
// if the user set this option as a commandline argument
if ( cli_context_supplied )
{
// override the conf file's specified execution context
configuration.set_execution_context( execution_context );
slog.log( E_DEBUG, "Set execution context from commandline: " + execution_context );
}
// load the filepaths to definitions of a plan and definitions of units.
std::string definitions_file = configuration.get_units_path();
std::string plan_file = configuration.get_plan_path();
Suite available_definitions;
available_definitions.load_units_file( definitions_file, verbose );
Suite available_definitions = Suite( L_LEVEL );
available_definitions.load_units_file( definitions_file );
Plan plan( &configuration );
plan.load_plan_file( plan_file, verbose );
Plan plan = Plan( &configuration, L_LEVEL );
plan.load_plan_file( plan_file );
plan.load_definitions( available_definitions, verbose );
plan.load_definitions( available_definitions );
std::cout << "Ready to execute all tasks in Plan." << std::endl;
slog.log( E_DEBUG, "Ready to execute all tasks in Plan." );
try
{
plan.execute( verbose );
plan.execute();
}
catch ( std::exception& e)
{
std::cerr << e.what() << std::endl;
syslog( LOG_ERR, e.what() );
closelog();
slog.log( E_FATAL, e.what() );
return 1;
}
closelog();
return 0;
}

51
src/Logger/Logger.cpp Normal file
View File

@ -0,0 +1,51 @@
//
// Created by bagira on 6/13/20.
//
#include "Logger.h"
Logger::Logger( int LOG_LEVEL, std::string mask )
{
this->LOG_LEVEL = LOG_LEVEL;
this->mask = mask.c_str();
setlogmask( LOG_UPTO( this->LOG_LEVEL ) );
openlog( this->mask, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_PERROR | LOG_LOCAL1 );
}
void Logger::log( int LOG_LEVEL, std::string msg )
{
std::string ERR = "XXXX";
if ( LOG_LEVEL <= this->LOG_LEVEL )
{
switch ( LOG_LEVEL )
{
case E_DEBUG: ERR = "DBUG"; break;
case E_FATAL: ERR = "FATL"; break;
case E_INFO: ERR = "INFO"; break;
case E_WARN: ERR = "WARN"; break;
}
std::string s_msg = "[" + ERR + "] " + msg;
syslog( this->LOG_LEVEL, s_msg.c_str() );
if ( LOG_LEVEL == E_FATAL | LOG_LEVEL == E_WARN )
{
std::cerr << "[" << this->get_8601() << "]\t[" << this->mask << "]\t[" << ERR << "]\t" << msg.c_str() << std::endl;
} else {
std::cout << "[" << this->get_8601() << "]\t[" << this->mask << "]\t[" << ERR << "]\t" << msg.c_str() << std::endl;
}
}
}
std::string Logger::get_8601()
{
auto now = std::chrono::system_clock::now();
auto itt = std::chrono::system_clock::to_time_t(now);
std::ostringstream ss;
// ss << std::put_time(gmtime(&itt), "%FT%TZ");
ss << std::put_time(localtime(&itt), "%Y-%m-%d_%H:%M:%S");
return ss.str();
}

35
src/Logger/Logger.h Normal file
View File

@ -0,0 +1,35 @@
//
// Created by bagira on 6/13/20.
//
#ifndef EXAMPLAR_LOGGER_H
#define EXAMPLAR_LOGGER_H
#include <syslog.h>
#include <string>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>
enum L_LVL {
E_INFO,
E_FATAL,
E_WARN,
E_DEBUG
};
class Logger {
public:
Logger( int LOG_LEVEL, std::string mask );
void log( int LOG_LEVEL, std::string msg );
private:
int LOG_LEVEL;
const char * mask;
std::string get_8601();
};
#endif //EXAMPLAR_LOGGER_H

View File

@ -66,21 +66,23 @@ protected:
/// TODO Expand to detect when a directory path is supplied for units_path or plan_path and import all Tasks and Units.
///
/// \param filename - The filename to load the configuration from.
Conf::Conf( std::string filename, bool verbose ): JSON_Loader()
Conf::Conf( std::string filename, int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::conf" )
{
this->LOG_LEVEL = LOG_LEVEL;
// prepare context spaghetti
this->override_context = false;
try {
// load the conf file.
this->load_json_file( filename, verbose );
this->load_json_file( filename );
}
catch (std::exception) {
throw ConfigLoadException("Could not find '" + filename + "'.");
this->slog.log( E_FATAL, "Unable to locate configuration file: '" + filename + "'." );
throw ConfigLoadException("Config file not found.");
}
if (this->get_serialized(this->config_version, "config_version" ,true) != 0)
if (this->get_serialized(this->config_version, "config_version" ) != 0)
{
throw ConfigLoadException("config_version string is not set in the config file supplied: " + filename);
}
@ -90,38 +92,36 @@ Conf::Conf( std::string filename, bool verbose ): JSON_Loader()
}
// find the path to the plan file
if (this->get_serialized(this->plan_path, "plan_path", true) != 0 )
if (this->get_serialized(this->plan_path, "plan_path" ) != 0 )
{
throw ConfigLoadException("plan_path string is not set in the config file supplied:" + filename);
}
// find the path to the unit definitions file
if (this->get_serialized(this->units_path, "units_path", true) != 0 )
if (this->get_serialized(this->units_path, "units_path" ) != 0 )
{
throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename);
}
if ( this->get_serialized(this->override_execution_context, "execution_context_override", true) != 0 )
if ( this->get_serialized(this->override_execution_context, "execution_context_override" ) != 0 )
{
throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename);
} else {
this->override_context = true;
}
if ( this->get_serialized(this->execution_context, "execution_context", true) != 0 )
if ( this->get_serialized(this->execution_context, "execution_context" ) != 0 )
{
throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename);
} else {
this->execution_context_literal = this->execution_context.asString();
}
if ( this->get_serialized(this->env_vars_file, "env_vars_file", true) != 0 )
if ( this->get_serialized(this->env_vars_file, "env_vars_file" ) != 0 )
{
throw ConfigLoadException("env_vars_file is not set in the config file supplied: " + filename);
}
};
/// Conf::has_context_override - Specifies whether or not the override context function is enabled in the conf file.
@ -137,7 +137,6 @@ std::string Conf::get_execution_context() {
/// Conf::get_plan_path - Retrieves the path to the Plan definition file from the application configuration file.
std::string Conf::get_plan_path() { return this->plan_path.asString(); }
/// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file.
std::string Conf::get_units_path() { return this->units_path.asString(); }

View File

@ -20,8 +20,9 @@
#ifndef FTESTS_CONF_H
#define FTESTS_CONF_H
#include "JSON_Loader.h"
#include "../low_level/JSON_Loader.h"
#include <exception>
#include "../../Logger/Logger.h"
#define STRINGIZE2(s) #s
@ -47,17 +48,20 @@ private:
std::string execution_context_literal;
public:
Conf( std::string filename, bool verbose );
std::string get_plan_path();
std::string get_units_path();
Conf( std::string filename, int LOG_LEVEL );
bool has_context_override();
std::string get_plan_path();
std::string get_units_path();
std::string get_execution_context();
void set_execution_context( std::string );
std::string get_env_vars_file();
private:
int LOG_LEVEL;
Logger slog;
};

View File

@ -120,40 +120,39 @@ protected:
/// 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
/// definitions to execute, and if Units together form a Suite, Tasks together form a Plan.
Plan::Plan( Conf * configuration ): JSON_Loader()
Plan::Plan( Conf * configuration, int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::plan" )
{
this->configuration = configuration;
};
this->LOG_LEVEL = LOG_LEVEL;
}
/// Plan::load_plan_file - Uses the json_root buffer on each run to append intact Units as they're deserialized from
/// the provided file.
///
/// \param filename - The filename to load the plan from.
/// \param verbose - Whether to print verbose output to STDOUT.
void Plan::load_plan_file(std::string filename, bool verbose)
void Plan::load_plan_file( std::string filename )
{
// plan always loads from file
this->load_json_file( filename, verbose );
this->load_json_file( filename );
// staging buffer
Json::Value jbuff;
// fill the jbuff staging buffer wih a json::value object in the supplied filename
if ( this->get_serialized( jbuff, "plan", verbose ) == 0 )
if ( this->get_serialized( jbuff, "plan" ) == 0 )
{
this->json_root = jbuff;
}
// iterate through the json::value members that have been loaded. append to this->tasks vector
// buffer for tasks to append:
Task tmp_T;
Task tmp_T = Task( this->LOG_LEVEL );
for ( int index = 0; index < this->json_root.size(); index++ )
{
tmp_T.load_root( this->json_root[ index ], verbose );
tmp_T.load_root( this->json_root[ index ] );
this->tasks.push_back( tmp_T );
if ( verbose ) {
std::cout << "Added task \"" << tmp_T.get_name() << "\" to Plan." << std::endl;
}
this->slog.log( LOG_INFO, "Added task \"" + tmp_T.get_name() + "\" to Plan." );
}
}
@ -177,10 +176,10 @@ void Plan::get_task(Task & result, int index )
///
/// \param unit_definitions - The Suite to load definitions from.
/// \param verbose - Whether to print verbose information to STDOUT.
void Plan::load_definitions( Suite unit_definitions, bool verbose )
void Plan::load_definitions( Suite unit_definitions )
{
// placeholder Unit
Unit tmp_U;
Unit tmp_U = Unit( this->LOG_LEVEL );
// for every task in the plan:
for (int i = 0; i < this->tasks.size(); i++ )
@ -189,7 +188,7 @@ void Plan::load_definitions( Suite unit_definitions, bool verbose )
unit_definitions.get_unit( tmp_U, this->tasks[i].get_name() );
// then have that task attach a copy of tmp_U
this->tasks[i].load_definition( tmp_U, verbose );
this->tasks[i].load_definition( tmp_U );
}
}
@ -213,7 +212,7 @@ void Plan::get_task(Task & result, std::string provided_name )
}
if (! foundMatch )
{
std::cerr << "Task name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
this->slog.log( E_FATAL, "Task name \"" + provided_name + "\" was referenced but not defined!" );
throw Plan_InvalidTaskName();
}
}
@ -226,14 +225,14 @@ void Plan::get_task(Task & result, std::string provided_name )
bool Plan::all_dependencies_complete(std::string name)
{
// get the task by name
Task named_task;
Task named_task = Task( this->LOG_LEVEL );
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;
Task tmpTask = Task( this->LOG_LEVEL );
// iterate through its dependencies
for ( int i = 0; i < deps.size(); i++ )
{
@ -250,26 +249,26 @@ bool Plan::all_dependencies_complete(std::string name)
/// Plan::execute() - Iterates through all tasks in a plan and executes them.
///
/// \param verbose
void Plan::execute( bool verbose )
void Plan::execute()
{
// for each task in this plan
for ( int i = 0; i < this->tasks.size(); i++ )
{
if (this->all_dependencies_complete(this->tasks[i].get_name()) )
{
if ( verbose )
{
std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl;
}
this->slog.log( E_INFO, "Executing task \"" + this->tasks[i].get_name() + "\"." );
try {
this->tasks[i].execute( this->configuration, verbose );
this->tasks[i].execute( this->configuration );
}
catch (std::exception& e) {
throw Plan_Task_GeneralExecutionException( "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() );
this->slog.log( E_FATAL, "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() );
throw Plan_Task_GeneralExecutionException("Could not execute task.");
}
} else {
// not all deps met for this task
throw Plan_Task_Missing_Dependency( "Plan Task \"" + this->tasks[i].get_name() + "\" was specified in the Plan but not executed due to missing dependencies. Please revise your plan." );
this->slog.log( E_FATAL, "Plan Task \"" + this->tasks[i].get_name() + "\" was specified in the Plan but not executed due to missing dependencies. Please revise your plan." );
throw Plan_Task_Missing_Dependency( "Unmet dependency for task." );
}
}
}

View File

@ -22,10 +22,11 @@
#define FTESTS_PLAN_H
#include <string>
#include "../json/json.h"
#include "JSON_Loader.h"
#include "../../json/json.h"
#include "../low_level/JSON_Loader.h"
#include "Task.h"
#include "Conf.h"
#include "../../Logger/Logger.h"
class Plan: public JSON_Loader
{
@ -35,10 +36,10 @@ class Plan: public JSON_Loader
Conf * configuration;
public:
Plan( Conf * configuration );
Plan( Conf * configuration, int LOG_LEVEL );
// append this->tasks from JSON file
void load_plan_file( std::string filename, bool verbose );
void load_plan_file( std::string filename );
// fetch a task from this->tasks
void get_task( Task & result, std::string provided_name );
@ -47,15 +48,19 @@ class Plan: public JSON_Loader
void get_task( Task & result, int index );
// 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 );
// fetch a corresponding Unit to a Task
// void get_definition_from_task(Unit & result, Task input, bool verbose );
// execute all tasks in this plan
void execute( bool verbose );
void execute();
bool all_dependencies_complete(std::string name);
private:
int LOG_LEVEL;
Logger slog;
};
#endif //FTESTS_PLAN_H

View File

@ -79,24 +79,13 @@ protected:
/// human processes to allow modularly developed profiles of test suites. As inferred, Unit is expected to be one of
/// the two types that are only instantiated once per application run, though it is designed to be used more than once
/// if the implementor so desires.
Suite::Suite(): JSON_Loader() {};
bool is_file( std::string path)
Suite::Suite( int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::suite" )
{
struct stat buf;
stat( path.c_str(), &buf );
return S_ISREG(buf.st_mode);
this->LOG_LEVEL;
}
bool is_dir( std::string path )
{
struct stat buf;
stat( path.c_str(), &buf );
return S_ISDIR(buf.st_mode);
}
void get_units_from_dir( std::vector<std::string> * files, std::string path )
void Suite::get_units_from_dir( std::vector<std::string> * files, std::string path )
{
DIR* dirFile = opendir( path.c_str() );
if ( dirFile )
@ -107,11 +96,20 @@ void get_units_from_dir( std::vector<std::string> * files, std::string path )
errno = 0;
while (( hFile = readdir( dirFile )) != NULL )
{
if ( !strcmp( hFile->d_name, "." )) continue;
if ( !strcmp( hFile->d_name, ".." )) continue;
if ( !strcmp( hFile->d_name, "." ))
{
continue;
}
if ( !strcmp( hFile->d_name, ".." ))
{
continue;
}
// hidden files
if ( hFile->d_name[0] == '.' ) continue;
if ( hFile->d_name[0] == '.' )
{
continue;
}
// dirFile.name is the name of the file. Do whatever string comparison
// you want here. Something like:
@ -123,18 +121,17 @@ void get_units_from_dir( std::vector<std::string> * files, std::string path )
}
closedir( dirFile );
} else {
std::cout << "file not found" << std::endl;
this->slog.log( E_DEBUG, "File not found: " + path );
}
}
/// Suite::load_units_file - Uses the json_root buffer on each run to append intact Units as they're
/// deserialized from the provided file.
///
/// \param units_path - The file to pull the JSON-formatted units from.
/// \param verbose - Whether to print verbose output to STDOUT.
void Suite::load_units_file( std::string units_path, bool verbose )
void Suite::load_units_file( std::string units_path )
{
std::vector<std::string> unit_files;
@ -149,28 +146,26 @@ void Suite::load_units_file( std::string units_path, bool verbose )
unit_files.push_back( units_path );
}
std::ostringstream infostring;
infostring << "Unit files found: " << unit_files.size() << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cerr << infostring.str();
this->slog.log( E_INFO, "Unit files found: " + std::to_string( unit_files.size() ) );
for ( int i = 0; i < unit_files.size(); i++ )
{
// will use json_root buffer on each run to append to this->units vector as valid units are found.
this->load_json_file( unit_files[i], verbose );
this->load_json_file( unit_files[i] );
// staging buffer
Json::Value jbuff;
// fill the jbuff staging buffer with a json::value object in the supplied units_path
if ( this->get_serialized( jbuff, "units", verbose ) == 0)
if ( this->get_serialized( jbuff, "units" ) == 0)
{
this->json_root = jbuff;
}
// iterate through the json::value members that have been loaded. append to this->units vector
// buffer for units to append:
Unit tmp_U;
Unit tmp_U = Unit( this->LOG_LEVEL );
for ( int index = 0; index < this->json_root.size(); index++ )
{
// assemble the unit from json_root using the built-in value operator
@ -178,20 +173,13 @@ void Suite::load_units_file( std::string units_path, bool verbose )
if ( tmp_U.get_active() ) {
// append to this->units
this->units.push_back( tmp_U );
if ( verbose ) {
std::ostringstream infostring;
infostring << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Added unit \"" + tmp_U.get_name() + "\" to Suite.");
}
}
}
}
}
/// Suite::get_unit - returns a contained Unit identified by name attribute.
///
/// \param result - the unit type receiving the unit's value
@ -213,11 +201,8 @@ void Suite::get_unit(Unit & result, std::string provided_name)
if (! foundMatch )
{
std::ostringstream infostring;
infostring << "Unit name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
syslog(LOG_ERR, infostring.str().c_str() );
std::cerr << infostring.str();
throw SuiteException( infostring.str() );
this->slog.log( E_FATAL, "Unit name \"" + provided_name + "\" was referenced but not defined!" );
throw SuiteException( "Undefined unit in use." );
}
}

View File

@ -22,9 +22,11 @@
#define FTESTS_UNITS_H
#include <vector>
#include "../json/json.h"
#include "JSON_Loader.h"
#include "../../json/json.h"
#include "../low_level/JSON_Loader.h"
#include "Unit.h"
#include "../../Logger/Logger.h"
#include "../misc/helpers.h"
class Suite: public JSON_Loader
@ -34,14 +36,22 @@ class Suite: public JSON_Loader
std::vector<Unit> units;
public:
// constructor, empty
Suite();
// constructor
Suite( int LOG_LEVEL );
// load a unit definitions file and add valid unit definitions to this->units
void load_units_file( std::string filename, bool verbose );
void load_units_file( std::string filename );
// returns the unit identified by name
void get_unit(Unit & result, std::string provided_name);
private:
void get_units_from_dir( std::vector<std::string> * files, std::string path );
private:
int LOG_LEVEL;
Logger slog;
};
#endif //FTESTS_UNITS_H

View File

@ -19,10 +19,7 @@
*/
#include "Task.h"
#include <stdio.h>
#include <syslog.h>
#include "../sproc/Sproc.h"
#include "helpers.h"
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
class Task_InvalidDataStructure: public std::runtime_error {
@ -82,20 +79,24 @@ protected:
/// 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.
Task::Task()
Task::Task( int LOG_LEVEL ):
slog( LOG_LEVEL, "examplar::task" ),
definition( LOG_LEVEL )
{
// it hasn't executed yet.
this->complete = false;
// it hasn't been matched with a definition yet.
this->defined = false;
this->LOG_LEVEL = LOG_LEVEL;
}
/// Task::load_root() - loads json values to private members
///
/// \param loader_root - the Json::Value to populate from.
/// \param verbose - Whether to print verbose information to STDOUT.
void Task::load_root(Json::Value loader_root, bool verbose )
void Task::load_root(Json::Value loader_root )
{
if ( loader_root.isMember("name") ) {
this->name = loader_root.get("name", "?").asString();
@ -110,16 +111,10 @@ void Task::load_root(Json::Value loader_root, bool verbose )
// iterate through each member of that obj
for ( int i = 0; i < des_dep_root.size(); i++ ) {
// add each string to dependencies
if ( des_dep_root[i].asString() != "" ) {
if ( des_dep_root[i].asString() != "" )
{
this->dependencies.push_back( des_dep_root[i].asString() );
if ( verbose ) {
std::ostringstream infostring;
infostring << "Added dependency \"" << des_dep_root[i].asString() << "\" to task \""
<< this->get_name() << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
this->slog.log( E_INFO, "Added dependency \"" + des_dep_root[i].asString() + "\" to task \"" + this->get_name() + "\"." );
}
}
}
@ -134,17 +129,10 @@ std::string Task::get_name()
///
/// \param selected_unit - The unit to attach.
/// \param verbose - Whether to print to STDOUT.
void Task::load_definition( Unit selected_unit, bool verbose )
void Task::load_definition( Unit selected_unit )
{
this->definition = selected_unit;
if ( verbose ) {
std::ostringstream infostring;
infostring << "Loaded definition \"" << selected_unit.get_name() << "\" for task \""
<< this->get_name() << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
this->slog.log( E_INFO, "Loaded definition \"" + selected_unit.get_name() + "\" for task \"" + this->get_name() + "\".");
this->defined = true;
}
@ -177,7 +165,7 @@ bool Task::has_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( Conf * configuration, bool verbose )
void Task::execute( Conf * configuration )
{
// DUFFING - If Examplar is broken it's probably going to be in this block.
// Somebody come clean this up, eh?
@ -192,40 +180,26 @@ void Task::execute( Conf * configuration, bool verbose )
// get the name
std::string task_name = this->definition.get_name();
this->slog.log( E_DEBUG, "\tUsing unit: \"" + task_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 )
{
/*
infostring = std::ostringstream();
infostring << "\tUsing unit \"" << task_name << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
*/
// check if context override
if ( configuration->has_context_override() )
{
// if so, set the CWD.
chdir( configuration->get_execution_context().c_str() );
infostring = std::ostringstream();
infostring << "\tExecution context: " << get_working_path() << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Setting execution context: " + get_working_path() );
}
infostring = std::ostringstream();
infostring << "\tExecuting target \"" << target_command << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
// a[0] execute target
// TODO revise variable sourcing strategy
this->slog.log( E_DEBUG, "Loading environment variable file: " + configuration->get_env_vars_file() );
this->slog.log( E_INFO, "Executing target: \"" + target_command + "\"." );
int return_code = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + target_command );
// **********************************************
@ -234,13 +208,8 @@ void Task::execute( Conf * configuration, bool verbose )
if ( return_code == 0 )
{
// d[0].0 ZERO
this->slog.log( E_INFO, "Target \"" + task_name + "\" succeeded. Marking as complete." );
if ( verbose ) {
infostring = std::ostringstream();
infostring << "\tTarget " << task_name << " succeeded. Marking as complete." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
this->mark_complete();
// a[1] NEXT
@ -250,12 +219,7 @@ void Task::execute( Conf * configuration, bool verbose )
if ( return_code != 0 )
{
// d[0].1 NON-ZERO
infostring = std::ostringstream();
infostring << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
syslog(LOG_ERR, infostring.str().c_str() );
std::cerr << infostring.str();
this->slog.log( E_WARN, "Target \"" + task_name + "\" failed with exit code " + std::to_string( return_code ) + "." );
// **********************************************
// d[1] Rectify Check
@ -271,18 +235,13 @@ void Task::execute( Conf * configuration, bool verbose )
{
// d[2].0 FALSE
// a[2] NEXT
infostring = std::ostringstream();
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." );
return;
}
if ( this->definition.get_required() )
{
} else {
// d[2].1 TRUE
// a[3] EXCEPTION
throw TaskException("Task \"" + task_name + "\" is required, and failed, and rectification is not enabled.");
this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, and failed, and rectification is not enabled." );
throw TaskException( "Task failed: " + task_name );
}
// **********************************************
// end - d[2] Required Check
@ -293,18 +252,12 @@ void Task::execute( Conf * configuration, bool verbose )
if ( this->definition.get_rectify() )
{
// d[1].1 TRUE (Rectify Check)
infostring = std::ostringstream();
infostring << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Rectification pattern is enabled for \"" + task_name + "\"." );
// a[4] Execute RECTIFIER
std::string rectifier_command = this->definition.get_rectifier();
infostring = std::ostringstream();
infostring << "\tExecuting rectification: " << rectifier_command << "." << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Executing rectification: " + rectifier_command + "." );
int rectifier_error = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + rectifier_command );
@ -314,12 +267,7 @@ void Task::execute( Conf * configuration, bool verbose )
if ( rectifier_error != 0 )
{
// d[3].1 Non-Zero
infostring = std::ostringstream();
infostring << "\tRectification of \"" << task_name << "\" failed with exit code "
<< rectifier_error << "." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_WARN, "Rectification of \"" + task_name + "\" failed with exit code " + std::to_string( rectifier_error ) + "." );
// **********************************************
// d[4] Required Check
@ -327,10 +275,7 @@ void Task::execute( Conf * configuration, bool verbose )
if ( ! this->definition.get_required() ) {
// d[4].0 FALSE
// a[5] NEXT
infostring = std::ostringstream();
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." );
return;
}
@ -338,7 +283,8 @@ void Task::execute( Conf * configuration, bool verbose )
{
// d[4].1 TRUE
// a[6] EXCEPTION
throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectification failed.");
this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, it failed, and then rectification failed. Lost cause." );
throw TaskException( "Lost cause, task failure." );
}
// **********************************************
// end - d[4] Required Check
@ -349,16 +295,10 @@ void Task::execute( Conf * configuration, bool verbose )
if ( rectifier_error == 0 )
{
// d[3].0 Zero
infostring = std::ostringstream();
infostring << "\tRectification returned successfully." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Rectification returned successfully." );
// a[7] Re-execute Target
infostring = std::ostringstream();
infostring << "\tRe-Executing target \"" << this->definition.get_target() << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Re-Executing target \"" + this->definition.get_target() + "\"." );
int retry_code = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + target_command );
@ -369,20 +309,11 @@ void Task::execute( Conf * configuration, bool verbose )
{
// d[5].0 ZERO
// a[8] NEXT
infostring = std::ostringstream();
infostring << "\tRe-execution was successful." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "Re-execution was successful." );
return;
}
if ( retry_code != 0 )
{
} else {
// d[5].1 NON-ZERO
infostring = std::ostringstream();
infostring << "\tRe-execution failed with exit code " << retry_code << "." << std::endl;
syslog(LOG_ERR, infostring.str().c_str() );
std::cerr << infostring.str();
this->slog.log( E_WARN, "Re-execution failed with exit code " + std::to_string( retry_code ) + "." );
// **********************************************
// d[6] Required Check
@ -391,11 +322,7 @@ void Task::execute( Conf * configuration, bool verbose )
{
// d[6].0 FALSE
// a[9] NEXT
infostring = std::ostringstream();
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." );
return;
}
@ -403,7 +330,8 @@ void Task::execute( Conf * configuration, bool verbose )
{
// d[6].1 TRUE
// a[10] EXCEPTION
throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectifier did not heal the condition causing the target to fail. Cannot proceed with Plan.");
this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, and failed, then rectified but rectifier did not heal the condition causing the target to fail. Cannot proceed with Plan." );
throw TaskException( "Lost cause, task failure." );
}
// **********************************************
// end - d[6] Required Check

View File

@ -22,10 +22,13 @@
#define FTESTS_TASK_H
#include <string>
#include <unistd.h>
#include "../json/json.h"
#include "../../json/json.h"
#include "Unit.h"
#include "Suite.h"
#include "Conf.h"
#include <stdio.h>
#include "../../Sproc/Sproc.h"
#include "../misc/helpers.h"
class Task
{
@ -49,13 +52,13 @@ class Task
public:
// constructor
Task();
Task( int LOG_LEVEL );
// load a json::value into task members (second stage deserialization)
void load_root( Json::Value loader_root, bool verbose );
void load_root( Json::Value loader_root );
// appends definition unit as child member
void load_definition( Unit definition, bool verbose );
void load_definition( Unit definition );
bool is_complete();
bool has_definition();
@ -64,12 +67,16 @@ class Task
std::string get_name();
// execute this task's definition
void execute( Conf * configuration, bool verbose );
void execute( Conf * configuration );
void mark_complete();
// returns a pointer to the dependencies vector
std::vector<std::string> get_dependencies();
private:
Logger slog;
int LOG_LEVEL;
};
#endif //FTESTS_TASK_H

View File

@ -48,7 +48,10 @@ class Unit_DataStructureException: public std::runtime_error { public:
/// required, which is used as a flag to halt or continue if rectifier does not heal the system in such a way that
/// target can run successfully.
/// rectify, which is used as a flag to determine in the rectifier runs.
Unit::Unit() {}
Unit::Unit( int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::unit" )
{
this->LOG_LEVEL;
}
/// Unit::load_root - Takes a JSON::Value and assigns the members to the Unit being populated.
///
@ -92,7 +95,7 @@ int Unit::load_root(Json::Value loader_root)
int Unit::load_string(std::string json_val)
{
// serialize
this->load_json_string( json_val, true );
this->load_json_string( json_val );
// deserialize
this->load_root( this->json_root );

View File

@ -26,8 +26,9 @@
#ifndef FTESTS_UNIT_H
#define FTESTS_UNIT_H
#include <string>
#include "../json/json.h"
#include "JSON_Loader.h"
#include "../../json/json.h"
#include "../low_level/JSON_Loader.h"
#include "../../Logger/Logger.h"
class Unit: JSON_Loader
{
@ -59,7 +60,7 @@ private:
bool rectify;
public:
Unit();
Unit( int LOG_LEVEL );
// loads a serialized jason::value object as a unit
int load_root( Json::Value loader_root );
@ -75,6 +76,10 @@ public:
bool get_active();
bool get_required();
bool get_rectify();
private:
int LOG_LEVEL;
Logger slog;
};
#endif //FTESTS_UNIT_H

View File

@ -20,7 +20,7 @@
#ifndef FTESTS_LOADERS_H
#define FTESTS_LOADERS_H
#include "JSON_Loader.h"
#include "../low_level/JSON_Loader.h"
#include "Suite.h"
#include "Plan.h"
#include "Conf.h"

View File

@ -19,8 +19,6 @@
*/
#include "JSON_Loader.h"
#include "helpers.h"
#include <stdexcept>
/// JSON_Loader_NotReady - Exception thrown when a member function is called before data is populated.
class JSON_Loader_NotReady: public std::runtime_error { public:
@ -40,51 +38,10 @@ class JSON_Loader_InvalidJSON: public std::runtime_error { public:
/// JSON_Loader::JSON_Loader - Constructor for JSON_Loader base class. Simply inits to an unpopulated state.
///
/// The JSON_Loader type is a base type. It is meant to provide the functionalities shared between Suite and Plan.
JSON_Loader::JSON_Loader()
JSON_Loader::JSON_Loader( int LOG_LEVEL ): slog( LOG_LEVEL, "examplar::json_loader" )
{
this->populated = false;
}
/// JSON_Loader::load_json_file - Loads JSON from a filepath into a serialized representation assigned as a local member
/// intended to be used as a buffer for further operations by base methods and derived class methods.
///
/// \param filename -
/// \param verbose
void JSON_Loader::load_json_file( std::string filename, bool verbose )
{
// reads from a file into a Json::Value type.
Json::Reader json_reader;
// the a deserialized json type to contain what's read by the reader
Json::Value json_root;
// first, check if the file exists
if (! exists( filename ) )
{
std::cerr << "File '" << filename << "' does not exist." << std::endl;
throw JSON_Loader_FileNotFound();
}
// create the ifstream file handle
std::ifstream json_file_ifstream( filename, std::ifstream::binary );
// use the reader to parse the ifstream to the local property
bool parsingSuccessful = json_reader.parse( json_file_ifstream, this->json_root );
if (! parsingSuccessful )
{
std::cerr << "Failed to parse '" << filename << "':\n\t" << json_reader.getFormattedErrorMessages();
throw JSON_Loader_InvalidJSON();
} else {
// if in verbose mode, give the user an "it worked" message
if (verbose)
{
std::cout << "Parsed '" << filename << "' with " << this->json_root.size() << " element(s)." << std::endl;
}
}
// Flag as ready for consumption.
this->populated = true;
this->LOG_LEVEL = LOG_LEVEL;
}
/// JSON_Loader::load_json_string - loads json from std::string into a json::value type and sets to protected member
@ -92,7 +49,7 @@ void JSON_Loader::load_json_file( std::string filename, bool verbose )
///
/// \param input - The JSON-formatted string to serialize
/// \param verbose - Whether or not to print verbose information to STDOUT.
void JSON_Loader::load_json_string( std::string input, bool verbose )
void JSON_Loader::load_json_string( std::string input )
{
// reads from a string into a Json::Value type.
Json::Reader json_reader;
@ -108,18 +65,52 @@ void JSON_Loader::load_json_string( std::string input, bool verbose )
if (! parsingSuccessful )
{
std::cerr << "Failed to parse adhoc JSON value." << std::endl << input << std::endl << std::endl << json_reader.getFormattedErrorMessages();
this->slog.log( E_FATAL, "Failed to parse adhoc JSON value: " + json_reader.getFormattedErrorMessages() );
throw JSON_Loader_InvalidJSON();
} else {
this->slog.log( E_DEBUG, "Successfully parsed JSON string with " + std::to_string( this->json_root.size() ) + "elements. Value: '" + input + "'." );
}
// flag as ready for consumption
this->populated = true;
}
/// JSON_Loader::load_json_file - Loads JSON from a filepath into a serialized representation assigned as a local member
/// intended to be used as a buffer for further operations by base methods and derived class methods.
///
/// \param filename -
/// \param verbose
void JSON_Loader::load_json_file( std::string filename )
{
// reads from a file into a Json::Value type.
Json::Reader json_reader;
// the a deserialized json type to contain what's read by the reader
Json::Value json_root;
// first, check if the file exists
if (! exists( filename ) )
{
this->slog.log( E_FATAL, "File '" + filename + "' does not exist." );
throw JSON_Loader_FileNotFound();
}
// create the ifstream file handle
std::ifstream json_file_ifstream( filename, std::ifstream::binary );
// use the reader to parse the ifstream to the local property
bool parsingSuccessful = json_reader.parse( json_file_ifstream, this->json_root );
if (! parsingSuccessful )
{
this->slog.log( E_FATAL, "Failed to parse file '" + filename + "': " + json_reader.getFormattedErrorMessages() );
throw JSON_Loader_InvalidJSON();
} else {
// if in verbose mode, give the user an "it worked" message
if ( verbose )
{
std::cout << "Successfully parsed JSON string with " << this->json_root.size() << " elements. Value:" << std::endl;
std::cout << input << std::endl << std::endl;
this->slog.log( E_DEBUG, "Parsed '" + filename + "' with " + std::to_string( this->json_root.size() ) + " element(s)." );
}
}
// flag as ready for consumption
// Flag as ready for consumption.
this->populated = true;
}
@ -138,7 +129,7 @@ std::string JSON_Loader::as_string()
/// \param key - The JSON key name to assign the value to (the root of the json::value object by name)
/// \param verbose - Whether or not to print verbose output to STDOUT.
/// \return - Boolean indicator of success or failure (0|1)
int JSON_Loader::get_serialized(Json::Value &input, std::string key, bool verbose)
int JSON_Loader::get_serialized(Json::Value &input, std::string key )
{
// throw if the class is not ready to be used.
if ( ! this->populated ) { throw JSON_Loader_NotReady(); }
@ -151,11 +142,10 @@ int JSON_Loader::get_serialized(Json::Value &input, std::string key, bool verbos
}
// key was not found
if ( verbose )
{
// verbose mode tells the user what key we were looking for.
std::cerr << "Failed to find key '" << key << "'." << std::endl;
}
this->slog.log( E_FATAL, "Failed to find key '" + key + "'." );
// exit code for failure
return 1;
}

View File

@ -19,11 +19,13 @@
*/
#ifndef FTESTS_JLOADER_H
#define FTESTS_JLOADER_H
#include "../json/json.h"
#include "../../json/json.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <stdexcept>
#include "../misc/helpers.h"
#include "../../Logger/Logger.h"
class JSON_Loader
{
@ -33,13 +35,13 @@ class JSON_Loader
public:
// constructor
JSON_Loader();
JSON_Loader( int LOG_LEVEL );
// load from json file
void load_json_file( std::string filename, bool verbose );
void load_json_file( std::string filename );
// load from std::string json
void load_json_string( std::string input, bool verbose );
void load_json_string( std::string input );
// return as a JSONCPP serialized object
// deprecated -- these aren't really used.
@ -47,6 +49,10 @@ class JSON_Loader
std::string as_string();
// safely handle deserialized type retrieval (if we want it to be safe)
int get_serialized(Json::Value &input, std::string key, bool verbose);
int get_serialized(Json::Value &input, std::string key );
private:
Logger slog;
int LOG_LEVEL;
};
#endif //FTESTS_JLOADER_H

View File

@ -31,3 +31,17 @@ std::string get_working_path()
char temp[MAXPATHLEN];
return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") );
}
bool is_file( std::string path)
{
struct stat buf;
stat( path.c_str(), &buf );
return S_ISREG(buf.st_mode);
}
bool is_dir( std::string path )
{
struct stat buf;
stat( path.c_str(), &buf );
return S_ISDIR(buf.st_mode);
}

View File

@ -29,5 +29,7 @@
bool exists (const std::string& name);
std::string get_working_path();
bool is_file( std::string );
bool is_dir( std::string );
#endif //FTESTS_HELPERS_H