architecture changes according to overall picture. request-handler unit tests started

This commit is contained in:
Dominic Bosch 2014-02-20 17:22:56 +01:00
parent 108432762e
commit 724af9bb82
13 changed files with 246 additions and 140 deletions

View file

@ -34,6 +34,7 @@ Initializes the HTTP listener and its request handler.
###
exports = module.exports = ( args ) =>
@log = args.logger
@shutDownSystem = args[ 'shutdown-function' ]
requestHandler args
initRouting args[ 'http-port' ]
module.exports
@ -101,17 +102,6 @@ initRouting = ( port ) =>
@shutDownSystem()
###
Adds the shutdown handler to the admin commands.
@param {function} fshutDown
@public addShutdownHandler( *fShutDown* )
###
exports.addShutdownHandler = ( fShutDown ) =>
@shutDownSystem = fShutDown
requestHandler.addShutdownHandler fShutDown
# ###
# Shuts down the http listener.
# There's no way to gracefully stop express from running, thus we

View file

@ -26,9 +26,12 @@ Returns a bunyan logger according to the given arguments.
###
exports.getLogger = ( args ) =>
emptylog =
trace: () ->
debug: () ->
info: () ->
warn: () ->
error: () ->
fatal: () ->
# `args` holds the configuration settings for the logging, see either CLI arguments
# in [webapi-eca](webapi-eca.html) or the configuration parameters in [config](config.html).
args = args ? {}

View file

@ -14,9 +14,6 @@ Request Handler
# - [Persistence](persistence.html)
db = require './persistence'
# - [Module Manager](module-manager.html)
mm = require './module-manager'
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html),
# [path](http://nodejs.org/api/path.html) and
# [querystring](http://nodejs.org/api/querystring.html)
@ -30,36 +27,19 @@ mustache = require 'mustache'
crypto = require 'crypto-js'
# Prepare the user command handlers which are invoked via HTTP requests.
objUserCmds =
'store_action': mm.storeActionModule
'get_actionmodules': mm.getAllActionModules
'store_event': mm.storeEventModule
'get_eventmodules': mm.getAllEventModules
'store_rule': mm.storeRule
objAdminCmds = {}
exports = module.exports = ( args ) ->
exports = module.exports = ( args ) =>
log = args.logger
@userRequestHandler = args[ 'request-service' ]
@objAdminCmds =
shutdown: ( args, answerHandler ) ->
answerHandler.answerSuccess 'Shutting down... BYE!'
setTimeout args[ 'shutdown-function' ], 500
db args
mm args
mm.addDBLink db
users = JSON.parse fs.readFileSync path.resolve __dirname, '..', 'config', 'users.json'
db.storeUser user for user in users
module.exports
###
This allows the parent to add the shutdown handler.
The shutdown function will be called if the admin command shutdown is issued.
@public addShutdownHandler( *fShutdown* )
@param {function} fShutdown
###
exports.addShutdownHandler = ( fShutdown ) =>
objAdminCmds.shutdown = ( args, answerHandler ) ->
answerHandler.answerSuccess 'Shutting down... BYE!'
setTimeout fShutdown, 500
###
Handles possible events that were posted to this server and pushes them into the
@ -260,10 +240,13 @@ exports.handleUserCommand = ( req, resp ) ->
req.on 'end', ->
obj = qs.parse body
console.log obj
if typeof objUserCmds[obj.command] is 'function'
objUserCmds[obj.command] req.session.user, obj, answerHandler req, resp
else
resp.send 404, 'Command unknown!'
@userRequestHandler req.session.user, obj, ( err, obj) ->
console.log 'user request handler sent answer!'
console.log obj
if !err
resp.send 'yay!'
else
resp.send 404, 'Command unknown!'
###
Handles the admin command requests.

View file

@ -21,12 +21,18 @@ conf = require './config'
# - [Persistence](persistence.html)
db = require './persistence'
# - [ECA Components Manager](components-manager.html)
cm = require './components-manager'
# - [Engine](engine.html)
engine = require './engine'
# - [HTTP Listener](http-listener.html)
http = require './http-listener'
# - [Event Poller](event-poller.html) *(will be forked into a child process)*
nameEP = 'event-poller'
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html),
# [path](http://nodejs.org/api/path.html)
# and [child_process](http://nodejs.org/api/child_process.html)
@ -80,12 +86,6 @@ opt =
'n':
alias : 'nolog',
describe: 'Set this if no output shall be generated'
# `-n`, `--nolog`: Set this if no output shall be generated
'u':
alias : 'unit-test-flag',
describe: """Set this if you are running the unit tests. This will cause the
system to not call process.exit() at the end of the shutDown routine
in order to get rid of the express server that would keep running"""
# now fetch the CLI arguments and exit if the help has been called.
argv = optimist.usage( usage ).options( opt ).argv
@ -105,7 +105,6 @@ init = =>
console.error 'FAIL: Config file not ready! Shutting down...'
process.exit()
@isUnitTest = argv.u || false
logconf = conf.getLogConf()
if argv.m
logconf[ 'mode' ] = argv.m
@ -132,6 +131,8 @@ init = =>
@log.info 'RS | Initialzing DB'
db args
# > We only proceed with the initialization if the DB is ready
#TODO eventually we shouldn't let each module load its own persistence
#module, but hand this one through them via the args...
db.isConnected ( err ) =>
if err
@log.error 'RS | No DB connection, shutting down system!'
@ -141,19 +142,9 @@ init = =>
# > Initialize all required modules with the args object.
@log.info 'RS | Initialzing engine'
engine args
@log.info 'RS | Initialzing http listener'
# We give the HTTP listener the ability to shutdown the whole system
http.addShutdownHandler shutDown
http args
# > Distribute handlers between modules to link the application.
@log.info 'RS | Passing handlers to engine'
engine.addPersistence db
@log.info 'RS | Passing handlers to http listener'
#TODO engine pushEvent needs to go into redis queue
#TODO loadAction and addRule will be removed
#mm.addHandlers db, engine.loadActionModule, engine.addRule
@log.info 'RS | Forking child process for the event poller'
# Start the event poller. The module manager will emit events for it
@log.info 'RS | Forking a child process for the event poller'
cliArgs = [
args.logconf['mode']
args.logconf['io-level']
@ -161,8 +152,25 @@ init = =>
args.logconf['file-path']
args.logconf['nolog']
]
poller = cp.fork path.resolve( __dirname, 'event-poller' ), cliArgs
poller = cp.fork path.resolve( __dirname, nameEP ), cliArgs
# after the engine and the event poller have been initialized we can
# initialize the module manager and register event listener functions
# from engine and event poller
@log.info 'RS | Initialzing module manager'
cm args
cm.addListener 'newRule', ( evt ) ->
poller.send evt
cm.addListener 'newRule', ( evt ) ->
engine.internalEvent evt
@log.info 'RS | Initialzing http listener'
# The request handler passes certain requests to the module manager
args[ 'request-service' ] = cm.processRequest
# We give the HTTP listener the ability to shutdown the whole system
args[ 'shutdown-function' ] = shutDown
http args
###
Shuts down the server.
@ -170,6 +178,7 @@ Shuts down the server.
###
shutDown = () =>
@log.warn 'RS | Received shut down command!'
# db?.shutDown()
engine?.shutDown()
# We need to call process.exit() since the express server in the http-listener
# can't be stopped gracefully. Why would you stop this system anyways!??

View file

@ -7,22 +7,35 @@
> then compiled into node modules and rules
*/
'use strict';
// # **Loads Modules:**
// # - [Persistence](persistence.html)
var fs = require('fs'),
path = require('path'),
log,
db, funcLoadAction, funcLoadRule;
db = require('./persistence'),
events = require('events'),
log, ee,
eventHandlers = [],
funcLoadAction, funcLoadRule;
exports = module.exports = function(args) {
args = args || {};
ee = new events.EventEmitter();
log = args.logger;
db(args);
return module.exports;
};
exports.addDBLink = function(db_link) {
db = db_link;
};
exports.addListener = function( evt, eh ) {
ee.addListener( evt, eh );
//TODO as soon as an event handler is added it needs to receive the full list of existing and activated rules
}
exports.processRequest = function( user, obj, cb ) {
console.log('module manager needs to process request: ');
console.log(obj.command);
}
exports.requireFromString = function(src, name, dir) {
if(!dir) dir = __dirname;
@ -174,6 +187,10 @@ exports.storeRule = function (objUser, obj, answHandler) {
}
db.getEventModule(objRule.event.split('->')[0], cbEventModule(lst));
db.storeRule(objRule.id, objUser.username, obj.data);
ee.emit('newRule', objRule);
// for( var i = 0; i < eventHandlers.length; i++ ) {
// eventHandlers[i]( objRule );
// }
} catch(err) {
answHandler.answerError(err.message);
log.error('MM', err);

View file

@ -10,10 +10,14 @@ var path = require('path'),
exports = module.exports = function( args ) {
log = args.logger;
mm = require('./module-manager')(args);
mm = require('./components-manager')(args);
return module.exports;
};
exports.internalEvent = function( evt ) {
console.log('engine got internal event');
console.log(evt);
}
/*
* Initialize the rules engine which initializes the module loader.
* @param {Object} db_link the link to the db, see [db\_interface](db_interface.html)

View file

@ -31,7 +31,7 @@ function init() {
log = logger.getLogger(logconf);
var args = { logger: log };
(ml = require('./module-manager'))(args);
(ml = require('./components-manager'))(args);
(db = require('./persistence'))(args);
initAdminCommands();
initMessageActions();
@ -113,13 +113,15 @@ function initMessageActions() {
if(typeof(func) === 'function') func(args);
};
process.on('message', function(strProps) {
var arrProps = strProps.split('|');
if(arrProps.length < 2) log.error('EP', 'too few parameter in message!');
else {
var func = listMessageActions[arrProps[0]];
if(func) func(arrProps);
}
process.on('message', function( obj ) {
console.log( 'message: ');
console.log (obj);
// var arrProps = obj .split('|');
// if(arrProps.length < 2) log.error('EP', 'too few parameter in message!');
// else {
// var func = listMessageActions[arrProps[0]];
// if(func) func(arrProps);
// }
});
// very important so the process doesnt linger on when the paren process is killed

View file

@ -34,6 +34,7 @@ HTTP Listener
exports = module.exports = function(args) {
_this.log = args.logger;
_this.shutDownSystem = args['shutdown-function'];
requestHandler(args);
initRouting(args['http-port']);
return module.exports;
@ -92,17 +93,4 @@ HTTP Listener
});
};
/*
Adds the shutdown handler to the admin commands.
@param {function} fshutDown
@public addShutdownHandler( *fShutDown* )
*/
exports.addShutdownHandler = function(fShutDown) {
_this.shutDownSystem = fShutDown;
return requestHandler.addShutdownHandler(fShutDown);
};
}).call(this);

View file

@ -20,9 +20,12 @@
exports.getLogger = function(args) {
var e, emptylog, opt;
emptylog = {
trace: function() {},
debug: function() {},
info: function() {},
warn: function() {},
error: function() {}
error: function() {},
fatal: function() {}
};
args = args != null ? args : {};
if (args.nolog) {

View file

@ -11,13 +11,11 @@ Request Handler
(function() {
var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage,
var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, mustache, path, qs, renderPage, sendLoginOrPage,
_this = this;
db = require('./persistence');
mm = require('./module-manager');
fs = require('fs');
path = require('path');
@ -28,22 +26,17 @@ Request Handler
crypto = require('crypto-js');
objUserCmds = {
'store_action': mm.storeActionModule,
'get_actionmodules': mm.getAllActionModules,
'store_event': mm.storeEventModule,
'get_eventmodules': mm.getAllEventModules,
'store_rule': mm.storeRule
};
objAdminCmds = {};
exports = module.exports = function(args) {
var log, user, users, _i, _len;
log = args.logger;
_this.userRequestHandler = args['request-service'];
_this.objAdminCmds = {
shutdown: function(args, answerHandler) {
answerHandler.answerSuccess('Shutting down... BYE!');
return setTimeout(args['shutdown-function'], 500);
}
};
db(args);
mm(args);
mm.addDBLink(db);
users = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'config', 'users.json')));
for (_i = 0, _len = users.length; _i < _len; _i++) {
user = users[_i];
@ -52,22 +45,6 @@ Request Handler
return module.exports;
};
/*
This allows the parent to add the shutdown handler.
The shutdown function will be called if the admin command shutdown is issued.
@public addShutdownHandler( *fShutdown* )
@param {function} fShutdown
*/
exports.addShutdownHandler = function(fShutdown) {
return objAdminCmds.shutdown = function(args, answerHandler) {
answerHandler.answerSuccess('Shutting down... BYE!');
return setTimeout(fShutdown, 500);
};
};
/*
Handles possible events that were posted to this server and pushes them into the
event queue.
@ -315,11 +292,15 @@ Request Handler
var obj;
obj = qs.parse(body);
console.log(obj);
if (typeof objUserCmds[obj.command] === 'function') {
return objUserCmds[obj.command](req.session.user, obj, answerHandler(req, resp));
} else {
return resp.send(404, 'Command unknown!');
}
return this.userRequestHandler(req.session.user, obj, function(err, obj) {
console.log('user request handler sent answer!');
console.log(obj);
if (!err) {
return resp.send('yay!');
} else {
return resp.send(404, 'Command unknown!');
}
});
});
}
};

View file

@ -13,7 +13,7 @@ WebAPI-ECA Engine
(function() {
var argv, conf, cp, db, engine, fs, http, init, logger, opt, optimist, path, procCmds, shutDown, usage,
var argv, cm, conf, cp, db, engine, fs, http, init, logger, nameEP, opt, optimist, path, procCmds, shutDown, usage,
_this = this;
logger = require('./logging');
@ -22,10 +22,14 @@ WebAPI-ECA Engine
db = require('./persistence');
cm = require('./components-manager');
engine = require('./engine');
http = require('./http-listener');
nameEP = 'event-poller';
fs = require('fs');
path = require('path');
@ -79,10 +83,6 @@ WebAPI-ECA Engine
'n': {
alias: 'nolog',
describe: 'Set this if no output shall be generated'
},
'u': {
alias: 'unit-test-flag',
describe: "Set this if you are running the unit tests. This will cause the\nsystem to not call process.exit() at the end of the shutDown routine\nin order to get rid of the express server that would keep running"
}
};
@ -107,7 +107,6 @@ WebAPI-ECA Engine
console.error('FAIL: Config file not ready! Shutting down...');
process.exit();
}
_this.isUnitTest = argv.u || false;
logconf = conf.getLogConf();
if (argv.m) {
logconf['mode'] = argv.m;
@ -145,15 +144,21 @@ WebAPI-ECA Engine
} else {
_this.log.info('RS | Initialzing engine');
engine(args);
_this.log.info('RS | Initialzing http listener');
http.addShutdownHandler(shutDown);
http(args);
_this.log.info('RS | Passing handlers to engine');
engine.addPersistence(db);
_this.log.info('RS | Passing handlers to http listener');
_this.log.info('RS | Forking child process for the event poller');
_this.log.info('RS | Forking a child process for the event poller');
cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']];
return poller = cp.fork(path.resolve(__dirname, 'event-poller'), cliArgs);
poller = cp.fork(path.resolve(__dirname, nameEP), cliArgs);
_this.log.info('RS | Initialzing module manager');
cm(args);
cm.addListener('newRule', function(evt) {
return poller.send(evt);
});
cm.addListener('newRule', function(evt) {
return engine.internalEvent(evt);
});
_this.log.info('RS | Initialzing http listener');
args['request-service'] = cm.processRequest;
args['shutdown-function'] = shutDown;
return http(args);
}
});
};

View file

@ -82,9 +82,12 @@ exports.testCustomPath = ( test ) =>
exports.testWrongPath = ( test ) =>
empty = [
'trace'
'debug'
'info'
'warn'
'error'
'fatal'
]
test.expect empty.length

View file

@ -0,0 +1,118 @@
http = require 'http'
path = require 'path'
events = require 'events'
cp = require 'child_process'
logger = require path.join '..', 'js-coffee', 'logging'
log = logger.getLogger
nolog: true
i = 0
createRequest = ( query, origUrl ) ->
req = new events.EventEmitter()
req.query = query
req.originalUrl = origUrl
req.session = {}
req
createLoggedInRequest = ( query, origUrl ) ->
req = createRequest()
req.session =
user:
name: 'unittester'
req
createAdminRequest = ( query, origUrl ) ->
req = createRequest()
req.session =
user:
name: 'adminunittester'
isAdmin: true
req
postRequestData = ( req, data ) ->
req.emit 'data', data
req.emit 'end'
# cb want's to get a response like { code, msg }
createResponse = ( cb ) ->
resp =
send: ( code, msg ) ->
if msg
code = parseInt code
else
msg = code
code = 200
cb code, msg
exports.setUp = ( cb ) =>
@rh = require path.join '..', 'js-coffee', 'request-handler'
cb()
# test: ( test ) ->
# test.expect 1
# args =
# logger: log
# args[ 'request-service' ] = ( usr, obj, cb ) ->
# console.log 'got a request to answer!'
# args[ 'shutdown-function' ] = () ->
# console.log 'request handler wants us to shutdown!'
# @rh args
# test.ok true, 'yay'
# test.done()
exports.events =
setUp: ( cb ) =>
@db = require path.join '..', 'js-coffee', 'persistence'
args =
logger: log
args[ 'db-port' ] = 6379
@db args
cb()
tearDown: ( cb ) =>
@db.shutDown()
cb()
testEvent: ( test ) =>
test.expect 1
doPolling = true
fPollEventQueue = ( cb ) =>
console.log 'polling'
if doPolling
@db.popEvent cb
setTimeout fPollEventQueue, 5
fPollEventQueue ( err, obj ) ->
console.log 'got something? :'
console.log err
console.log obj
args =
logger: log
args[ 'request-service' ] = ( usr, obj, cb ) ->
test.ok false, 'testEvent should not cause a service request call'
args[ 'shutdown-function' ] = () ->
test.ok false, 'testEvent should not cause a system shutdown'
@rh args
evt = 'event=unittest&eventid=unittest0'
req = createRequest()
console.log req
resp = createResponse ( code, msg ) ->
console.log 'got response: ' + msg
doPolling = false
@rh.handleEvent req, resp
fWait = () ->
postRequestData req, evt
setTimeout fWait, 50
# req.emit 'data', evt
# req.emit 'end'
test.ok true, 'yay'
test.done()