Skip to content

Commit

Permalink
Lots of microbrushing
Browse files Browse the repository at this point in the history
  • Loading branch information
etki committed Sep 4, 2017
1 parent 00984ba commit dac9912
Show file tree
Hide file tree
Showing 40 changed files with 770 additions and 109 deletions.
2 changes: 1 addition & 1 deletion examples/webpack/lib/scenario.js
Expand Up @@ -58,7 +58,7 @@ var scenario = {
}
},
onTermination: function () {
this.info('onTermination hook running')
this.info('onTermination hook is running')
}
}

Expand Down
9 changes: 7 additions & 2 deletions lib/API/Barricade.js
Expand Up @@ -3,9 +3,14 @@ var Normalizer = Schema.Normalizer
var Validator = Schema.Validator
var Slf4j = require('@ama-team/voxengine-sdk').Logger.Slf4j
var Printer = require('./Printer').Printer
var InvalidInputError = require('../Error').InvalidInputError

/**
* @param {object} [options]
* This class provide so-called barricade functionality - it validates
* and converts user input and, if input is invalid, prevents following
* actions by raising an exception.
*
* @param {TBarricadeOptions} [options]
*
* @class
*/
Expand All @@ -23,7 +28,7 @@ function Barricade (options) {
logger.info('Running scenario validation')
printer.violations(violations)
if (violations.severity === Validator.Severity.Fatal) {
throw new Error('Scenario validation has failed')
throw new InvalidInputError('Scenario validation has failed')
}
return Normalizer.scenario(input)
}
Expand Down
65 changes: 51 additions & 14 deletions lib/API/Framework.js
Expand Up @@ -5,17 +5,40 @@ var Barricade = require('./Barricade').Barricade
var Run = require('../Execution').Run
var Binder = require('../Adapter/Binder').Binder
var Printer = require('./Printer').Printer
var OperationStatus = require('../Schema').OperationStatus

/**
* Main library class that provides public API.
*
* @param {TFrameworkOptions} [options]
*
* @class
*/
function Framework (options) {
var self = this
options = options || {}
options.behavior = options.behavior || {terminate: true}
var logger = Slf4j.factory(options.logger, 'ama-team.vsf.framework')
var printer = new Printer(options.logger)

this.run = function (input) {
return self.execute(self.prepare(input))
/**
* Runs provided scenario.
*
* @param {TScenarioInput} scenario
*
* @return {TRunResult}
*/
this.run = function (scenario) {
return self.execute(self.prepare(scenario))
}

/**
* Executes prepared Run
*
* @param {Run} run
*
* @return {TRunResult}
*/
this.execute = function (run) {
printer.scenario(run.getScenario())
run.initialize()
Expand All @@ -24,28 +47,42 @@ function Framework (options) {
.getCompletion()
.then(printer.result, function (reason) {
logger.error('Unexpected error during execution:', reason)
return {
status: OperationStatus.Tripped,
error: reason,
stages: {}
}
})
.then(function (result) {
// TODO: make termination configurable
logger.debug('Shutting down VoxEngine')
VoxEngine.terminate()
if (options.behavior.terminate) {
logger.debug('Shutting down VoxEngine')
VoxEngine.terminate()
}
return result
})
}

/**
* @param {TScenarioInput} input
* Creates run from scenario input.
*
* @param {TScenarioInput} scenario
*
* @return {Run}
*/
this.prepare = function (input) {
var barricade = new Barricade({logger: options.logger, printer: printer})
var scenario = barricade.scenario(input)
var settings = {
state: input.state || {},
arguments: input.arguments || {},
logger: options.logger
this.prepare = function (scenario) {
try {
var barricade = new Barricade({logger: options.logger, printer: printer})
var normalized = barricade.scenario(scenario)
var settings = {
state: scenario.state || {},
arguments: scenario.arguments || {},
logger: options.logger
}
return new Run(normalized, normalized.deserializer, settings)
} catch (e) {
logger.error('Failed to create run, most probably due to invalid scenario')
throw e
}
return new Run(scenario, input.deserializer, settings)
}
}

Expand Down
20 changes: 12 additions & 8 deletions lib/API/Printer.js
Expand Up @@ -22,13 +22,14 @@ function Printer (options) {
* @param {ViolationSet} violations
*/
this.violations = function (violations) {
var list = violations.violations
if (!list.length) {
var groups = violations.violations
if (!Object.keys(groups).length) {
logger.info('No violations have been found')
return
}
logger.info('Found validation violations:')
Object.keys(list).forEach(function (path) {
list[path].forEach(function (v) {
Object.keys(groups).forEach(function (path) {
groups[path].forEach(function (v) {
var severe = v.severity.weight > Validator.Severity.Minor
var method = severe ? 'warn' : 'info'
logger[method]('{}: {} ({})', path, v.message, v.severity.id)
Expand All @@ -43,6 +44,9 @@ function Printer (options) {
var method = result.status.successful ? 'notice' : 'error'
logger[method]('Framework run has finished in {} ms with status {}',
result.duration, result.status.id)
if (result.value) {
logger.info('Result value:', result.value)
}
var stages = result.stages
Object.keys(stages).forEach(function (name) {
var result = stages[name]
Expand All @@ -51,11 +55,11 @@ function Printer (options) {
return
}
if (result.status.successful) {
logger.info('{} stage has successfully finished in {} ms with value {}',
name, result.duration, result.value)
} else {
logger.error('{} stage has finished in {} ms with error:', name,
logger.info('{} stage has successfully finished in {} ms:', name,
result.duration, result.value)
} else {
logger.error('{} stage has failed in {} ms:', name, result.duration,
result.value || result.error)
}
})
if (stages.scenario) {
Expand Down
1 change: 1 addition & 0 deletions lib/Error/index.js
Expand Up @@ -18,6 +18,7 @@ var InternalError = factory('InternalError')
module.exports = {
UserError: UserError,
ScenarioError: factory('ScenarioError', UserError),
InvalidInputError: factory('InvalidInputError', UserError),
/**
* @class InternalError
*/
Expand Down
3 changes: 2 additions & 1 deletion lib/Execution/Context.js
Expand Up @@ -62,7 +62,8 @@ function Context (run, options) {
Object.keys(logger).forEach(function (method) {
if (typeof logger[method] !== 'function') { return }
self[method] = function () {
logger[method].apply(logger, arguments)
var target = self.logger || logger
target[method].apply(target, arguments)
}
})

Expand Down
27 changes: 23 additions & 4 deletions lib/Execution/Run.js
Expand Up @@ -53,20 +53,39 @@ function Run (scenario, deserializer, options) {
initialization
.initialize()
.then(function (value) {
logger.info('Finished initialization stage')
if (value.status.successful) {
logger.info('Finished initialization stage')
} else {
logger.error('Initialization stage has failed:', value.error)
}
stageResults.initialization = value
logger.info('Running execution stage')
return value.status.successful ? execution.run() : null
if (value.status.successful) {
return execution.run()
} else {
var message = 'Execution (scenario) stage is not run due to ' +
'initialization stage fail'
logger.warn(message)
return null
}
})
.then(function (value) {
logger.info('Finished execution stage')
stageResults.scenario = value
if (!value || value.status.successful) {
logger.info('Finished execution stage')
} else {
logger.error('Execution stage has failed:', value.value)
}
logger.info('Running termination stage')
return termination.run(stageResults.initialization, value)
})
.then(function (value) {
logger.info('Finished termination stage')
stageResults.termination = value
if (value.status.successful) {
logger.info('Finished termination stage')
} else {
logger.error('Termination stage has failed:', value.value)
}
})
.then(function () {
logger.info('Finished run')
Expand Down
21 changes: 14 additions & 7 deletions lib/Execution/Stage/InitializationStage.js
@@ -1,6 +1,8 @@
var Future = require('@ama-team/voxengine-sdk').Concurrent.Future
var SDK = require('@ama-team/voxengine-sdk')
var Future = SDK.Concurrent.Future
var Status = require('../../Schema').OperationStatus
var Objects = require('../../Utility').Objects
var Slf4j = SDK.Logger.Slf4j

/**
* This class represents scenario initialization stage (fact gathering). It is
Expand All @@ -9,14 +11,17 @@ var Objects = require('../../Utility').Objects
*
* @param {IExecutor} executor
* @param {TArgumentHandler} deserializer
* @param {object} [options]
* @class
*/
function InitializationStage (executor, deserializer) {
function InitializationStage (executor, deserializer, options) {
options = options || {}
var loggerName = 'ama-team.vsf.execution.stage.initialization-stage'
var logger = Slf4j.factory(options.logger, loggerName)
var completion = new Future()
var result = {
status: null,
error: null,
log: null,
value: null,
startedAt: null,
finishedAt: null,
duration: null
Expand All @@ -31,7 +36,7 @@ function InitializationStage (executor, deserializer) {
* @param {string} value
*/
this.setLog = function (value) {
result.log = value
executor.getContext().log = value
}

/**
Expand All @@ -45,13 +50,15 @@ function InitializationStage (executor, deserializer) {
.runHandler(deserializer, [trigger.arguments, trigger])
.then(function (value) {
ctx.arguments = Objects.merge(ctx.arguments, value, true)
logger.info('Merged context arguments:', ctx.arguments)
logger.debug('Context state:', ctx.state)
result.status = Status.Finished
}, function (e) {
result.error = e
result.value = e
result.status = Status.Failed
})
.then(null, function (e) {
result.error = e
result.value = e
result.status = Status.Tripped
})
.then(function () {
Expand Down
2 changes: 1 addition & 1 deletion lib/Execution/Stage/TerminationStage.js
Expand Up @@ -89,7 +89,7 @@ function TerminationStage (executor, handler, options) {
})
.then(function () {
result.finishedAt = new Date()
result.duration = result.startedAt.getTime() - result.finishedAt.getTime()
result.duration = result.finishedAt.getTime() - result.startedAt.getTime()
return result
})
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Execution/StateMachine.js
Expand Up @@ -188,7 +188,7 @@ function StateMachine (executor, scenario, loggerOpts) {
logger.debug('Transitioned to {}', destination.id)
state = destination
if (state.terminal) {
logger.info('State {} is terminal, halting any further processing',
logger.info('State `{}` is terminal, halting any further processing',
state.id)
terminate(OperationStatus.Finished, value)
return
Expand Down
21 changes: 20 additions & 1 deletion lib/Schema/Normalizer.js
Expand Up @@ -2,6 +2,10 @@ var Objects = require('../Utility').Objects
var Defaults = require('./Defaults')

var Normalizer = {
/**
* @param {TStateTrigger|string} trigger
* @return {TStateTrigger}
*/
stateTrigger: function (trigger) {
if (typeof trigger === 'string') {
trigger = {id: trigger}
Expand Down Expand Up @@ -59,9 +63,10 @@ var Normalizer = {
return state
},
/**
* @param {TStateHandler} handler
* @param {TStateHandler|Function} handler
* @param {string} id
* @param {object<string, (int|null)>} timeouts
*
* @return {TStateHandler}
*/
handler: function (handler, id, timeouts) {
Expand All @@ -74,6 +79,14 @@ var Normalizer = {
}
return handler
},
/**
* @param {TStateHandler|Function} handler
* @param {Function} defaultHandler
* @param {string} id
* @param {object<string, (int|null)>} timeouts
*
* @return {TStateHandler}
*/
singleHandler: function (handler, defaultHandler, id, timeouts) {
if (Objects.isFunction(handler)) {
handler = {handler: handler}
Expand Down Expand Up @@ -114,6 +127,12 @@ var Normalizer = {
scenario.deserializer = Normalizer.deserializer(scenario.deserializer, timeouts)
return scenario
},
/**
* @param {THandler|Function|*} handler
* @param {object.<string, (int|null)>} timeouts
*
* @return {TStateHandler}
*/
deserializer: function (handler, timeouts) {
if (!Objects.isObject(handler)) {
handler = {handler: handler}
Expand Down
3 changes: 3 additions & 0 deletions lib/Schema/Validator.js
Expand Up @@ -129,6 +129,9 @@ var Validator = {
state: function (state, path) {
path = path || '$'
var violations = new ViolationSet()
if (Objects.isFunction(state)) {
return violations
}
if (!Objects.isObject(state)) {
return violations.push(path, 'Is not an object', Severity.Fatal)
}
Expand Down
1 change: 1 addition & 0 deletions lib/Schema/Virtual/Interface/IExecutionContext.js
Expand Up @@ -4,6 +4,7 @@
* @property {object} arguments
* @property {object} state
* @property {object} container
* @property {string} log
* @property {TScenarioTrigger} trigger
*/

Expand Down
5 changes: 5 additions & 0 deletions lib/Schema/Virtual/Type/API/TBarricadeOptions.js
@@ -0,0 +1,5 @@
/**
* @typedef {TComponentOptions} TBarricadeOptions
*
* @property {Printer} printer
*/
5 changes: 5 additions & 0 deletions lib/Schema/Virtual/Type/API/TFrameworkBehaviorOptions.js
@@ -0,0 +1,5 @@
/**
* @typedef {object} TFrameworkBehaviorOptions
*
* @property {boolean} [terminate] Whether to terminate VoxEngine or not
*/

0 comments on commit dac9912

Please sign in to comment.