diff --git a/coffee/logging.coffee b/coffee/logging.coffee new file mode 100644 index 0000000..19c672e --- /dev/null +++ b/coffee/logging.coffee @@ -0,0 +1,83 @@ + +# Logging +# ======= +# A Helper to handle the logging throughout the application. It uses +# [bunyan](https://github.com/trentm/node-bunyan) which allows for different streams +# to be attached to different log levels. [bunyan](https://github.com/trentm/node-bunyan) +# creates JSON entries for each log action. The bunyan module can then be used as a +# CLI to pretty print these logs, e.g.: + +# `node myapp.js | bunyan` + +# **Requires:** + +# - Node.js Module: [fs](http://nodejs.org/api/fs.html) and [path](http://nodejs.org/api/path.html) +fs = require 'fs' +path = require 'path' + +# - External Module: [bunyan](https://github.com/trentm/node-bunyan) +bunyan = require 'bunyan' + +### +Returns a bunyan logger according to the given arguments. + +@public getLogger( *args* ) +@param {Object} args +### +exports.getLogger = ( args ) => + emptylog = + { + info: () -> + warn: () -> + error: () -> + getLog: () -> + } + # `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 ? {} + if args.nolog + # if the user doesn't want to have a log at all (e.g. during tests), it can be omitted with + # the nolog flag + emptylog + else + try + opt = + name: "webapi-eca" + # if we are in development mode, we also add information about where the call came from + # this should be turned off in productive mode since it slows down the logging. + if args['mode'] is 'development' + opt.src = true + # if there's a custom path defined for the log, we adopt the setting. + if args['file-path'] + @logPath = path.resolve args['file-path'] + else + @logPath = path.resolve __dirname, '..', 'logs', 'server.log' + + # We try to write a temp file in the same folder to check if the log can be written + try + fs.writeFileSync @logPath + '.temp', 'temp' + fs.unlinkSync @logPath + '.temp' + catch e + console.error "Log folder '#{ @logPath }' is not writable" + return emptylog + + # We attach two streams, one for the I/O and one for the log file. + # The log levels are defined per stream according to the CLI args or the configuration. + opt.streams = [ + { + level: args['io-level'] + stream: process.stdout + }, + { + level: args['file-level'] + path: @logPath + } + ] + # Finally we create the bunyan logger and return it + bunyan.createLogger opt + + # If something goes wrong we print the error and return an empty logger. + catch e + console.error e + emptylog + diff --git a/coffee/new-logging.coffee b/coffee/new-logging.coffee deleted file mode 100644 index b4af074..0000000 --- a/coffee/new-logging.coffee +++ /dev/null @@ -1,59 +0,0 @@ - -# Logging -# ======= -# A Helper to handle logging. - -# **Requires:** -# - Node.js Module(s): [path](http://nodejs.org/api/path.html) -path = require 'path' - -# - External Module(s): [bunyan](https://github.com/trentm/node-bunyan) -bunyan = require 'bunyan' - -### -Module call ------------ - -Calling the module as a function will act as a constructor and load the config file. -It is possible to hand an args object with the properties nolog (true if no outputs shall -be generated) and configPath for a custom configuration file path. - -@param {Object} args -### -exports = module.exports = ( args ) => - emptylog = - { - info: () -> - warn: () -> - error: () -> - } - args = args ? {} - if args.nolog - emptylog - else - try - opt = - name: "webapi-eca" - if args['mode'] is 'development' - opt.src = true - if args['file-path'] - @logPath = path.resolve __dirname, '..', 'logs', args['file-path'] - else - @logPath = path.resolve __dirname, '..', 'logs', 'server.log' - opt.streams = [ - { - level: args['io-level'] - stream: process.stdout - }, - { - level: args['file-level'] - type: 'rotating-file' - path: @logPath - period: '1d' - count: 3 - } - ] - bunyan.createLogger opt - catch e - console.error e - emptylog \ No newline at end of file diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 1564e8b..6cfdc63 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -21,9 +21,6 @@ Persistence # **Requires:** -# - [Logging](logging.html) -log = require './logging' - # - External Modules: # [crypto-js](https://github.com/evanvosberg/crypto-js) and # [redis](https://github.com/mranney/node_redis) @@ -39,8 +36,8 @@ a db port and a crypto key. @param {Object} args ### exports = module.exports = ( args ) => - args = args ? {} - log args + @log = args.logger + #TODO remove config, do it through args config = require './config' config args @db?.quit() @@ -48,13 +45,13 @@ exports = module.exports = ( args ) => @crypto_key = config.getCryptoKey() @db = redis.createClient config.getDBPort(), 'localhost', { connect_timeout: 2000 } - @db.on 'error', ( err ) -> + @db.on 'error', ( err ) => err.addInfo = 'message from DB' - log.error 'DB', err - @ep = new IndexedModules( 'event-poller', @db ) - @ai = new IndexedModules( 'action-invoker', @db ) + @log.error 'DB', err + @ep = new IndexedModules( 'event-poller', @db, @log ) + @ai = new IndexedModules( 'action-invoker', @db, @log ) else - log.error 'DB', 'Initialization failed because of missing config file!' + @log.error 'DB', 'Initialization failed because of missing config file!' ### Checks whether the db is connected and passes either an error on failure after @@ -69,7 +66,7 @@ exports.isConnected = ( cb ) => numAttempts = 0 fCheckConnection = => if @db.connected - log.print 'DB', 'Successfully connected to DB!' + @log.info 'DB', 'Successfully connected to DB!' cb() else if numAttempts++ < 10 setTimeout fCheckConnection, 100 @@ -83,13 +80,13 @@ Abstracts logging for simple action replies from the DB. @private replyHandler( *action* ) @param {String} action ### -replyHandler = ( action ) -> - ( err, reply ) -> +replyHandler = ( action ) => + ( err, reply ) => if err err.addInfo = "during '#{ action }'" - log.error 'DB', err + @log.error 'DB', err else - log.print 'DB', "#{ action }: #{ reply }" + @log.info 'DB', "#{ action }: #{ reply }" ### Push an event into the event queue. @@ -99,10 +96,10 @@ Push an event into the event queue. ### exports.pushEvent = ( oEvent ) => if oEvent - log.print 'DB', "Event pushed into the queue: '#{ oEvent.eventid }'" + @log.info 'DB', "Event pushed into the queue: '#{ oEvent.eventid }'" @db.rpush 'event_queue', JSON.stringify( oEvent ) else - log.error 'DB', 'Why would you give me an empty event...' + @log.error 'DB', 'Why would you give me an empty event...' ### @@ -137,7 +134,7 @@ hash = ( plainText ) => ( crypto.SHA3 plainText, { outputLength: 512 } ).toString() catch err err.addInfo = 'during hashing' - log.error 'DB', err + @log.error 'DB', err null @@ -153,7 +150,7 @@ encrypt = ( plainText ) => crypto.AES.encrypt plainText, @crypto_key catch err err.addInfo = 'during encryption' - log.error 'DB', err + @log.error 'DB', err null ### @@ -169,7 +166,7 @@ decrypt = ( crypticText ) => dec.toString(crypto.enc.Utf8) catch err err.addInfo = 'during decryption' - log.error 'DB', err + @log.error 'DB', err null ### @@ -184,13 +181,13 @@ data objects via the provided function and returns the results to cb(err, obj). the retrieved data or an error ### getSetRecords = ( set, fSingle, cb ) => - log.print 'DB', "Fetching set records: '#{ set }'" + @log.info 'DB', "Fetching set records: '#{ set }'" # Fetch all members of the set - @db.smembers set, ( err, arrReply ) -> + @db.smembers set, ( err, arrReply ) => if err # If an error happens we return it to the callback function err.addInfo = "fetching '#{ set }'" - log.error 'DB', err + @log.error 'DB', err cb err else if arrReply.length == 0 # If the set was empty we return null to the callback @@ -206,18 +203,18 @@ getSetRecords = ( set, fSingle, cb ) => if semaphore > 0 cb new Error "Timeout fetching '#{ set }'" , 2000 - fCallback = ( prop ) -> + fCallback = ( prop ) => # The callback function is required to preprocess the result before # handing it to the callback. This especially includes decrementing # the semaphore - ( err, data ) -> + ( err, data ) => --semaphore if err err.addInfo = "fetching single element: '#{ prop }'" - log.error 'DB', err + @log.error 'DB', err else if not data # There was no data behind the key - log.error 'DB', new Error "Empty key in DB: '#{ prop }'" + @log.error 'DB', new Error "Empty key in DB: '#{ prop }'" else # We found a valid record and add it to the reply object objReplies[ prop ] = data @@ -231,53 +228,53 @@ getSetRecords = ( set, fSingle, cb ) => fSingle reply, fCallback( reply ) for reply in arrReply class IndexedModules - constructor: ( @setname, @db ) -> - log.print 'DB', "Instantiated indexed modules for '#{ @setname }'" + constructor: ( @setname, @db, @log ) -> + @log.info 'DB', "Instantiated indexed modules for '#{ @setname }'" storeModule: ( mId, data ) => - log.print 'DB', "storeModule(#{ @setname }): #{ mId }" + @log.info 'DB', "storeModule(#{ @setname }): #{ mId }" @db.sadd "#{ @setname }s", mId, replyHandler "Storing '#{ @setname }' key '#{ mId }'" @db.set "#{ @setname }:#{ mId }", data, replyHandler "Storing '#{ @setname }:#{ mId }'" getModule: ( mId, cb ) => - log.print 'DB', "getModule('#{ @setname }): #{ mId }'" + @log.info 'DB', "getModule('#{ @setname }): #{ mId }'" @db.get "#{ @setname }:#{ mId }", cb getModuleIds: ( cb ) => - log.print 'DB', "getModuleIds(#{ @setname })" + @log.info 'DB', "getModuleIds(#{ @setname })" @db.smembers "#{ @setname }s", cb getModules: ( cb ) => - log.print 'DB', "getModules(#{ @setname })" + @log.info 'DB', "getModules(#{ @setname })" getSetRecords "#{ @setname }s", @getModule, cb deleteModule: ( mId ) => - log.print 'DB', "deleteModule(#{ @setname }): #{ mId }" + @log.info 'DB', "deleteModule(#{ @setname }): #{ mId }" @db.srem "#{ @setname }s", mId, replyHandler "Deleting '#{ @setname }' key '#{ mId }'" @db.del "#{ @setname }:#{ mId }", replyHandler "Deleting '#{ @setname }:#{ mId }'" storeParameters: ( mId, userId, data ) => - log.print 'DB', "storeParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @log.info 'DB', "storeParameters(#{ @setname }): '#{ mId }:#{ userId }'" @db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }", replyHandler "Storing '#{ @setname }' module parameters key '#{ mId }'" @db.set "#{ @setname }-params:#{ mId }:#{ userId }", encrypt(data), replyHandler "Storing '#{ @setname }' module parameters '#{ mId }:#{ userId }'" getParameters: ( mId, userId, cb ) => - log.print 'DB', "getParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @log.info 'DB', "getParameters(#{ @setname }): '#{ mId }:#{ userId }'" @db.get "#{ @setname }-params:#{ mId }:#{ userId }", ( err, data ) -> cb err, decrypt data getParametersIds: ( cb ) => - log.print 'DB', "getParametersIds(#{ @setname })" + @log.info 'DB', "getParametersIds(#{ @setname })" @db.smembers "#{ @setname }-params", cb deleteParameters: ( mId, userId ) => - log.print 'DB', "deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @log.info 'DB', "deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'" @db.srem "#{ @setname }-params", "#{ mId }:#{ userId }", replyHandler "Deleting '#{ @setname }-params' key '#{ mId }:#{ userId }'" @db.del "#{ @setname }-params:#{ mId }:#{ userId }", @@ -482,7 +479,7 @@ Query the DB for a rule and pass it to cb(err, obj). @param {function} cb ### exports.getRule = ( ruleId, cb ) => - log.print 'DB', "getRule: '#{ ruleId }'" + @log.info 'DB', "getRule: '#{ ruleId }'" @db.get "rule:#{ ruleId }", cb ### @@ -491,8 +488,8 @@ Fetch all rules and pass them to cb(err, obj). @public getRules( *cb* ) @param {function} cb ### -exports.getRules = ( cb ) -> - log.print 'DB', 'Fetching all Rules' +exports.getRules = ( cb ) => + @log.info 'DB', 'Fetching all Rules' getSetRecords 'rules', exports.getRule, cb ### @@ -502,7 +499,7 @@ Fetch all rule IDs and hand it to cb(err, obj). @param {function} cb ### exports.getRuleIds = ( cb ) => - log.print 'DB', 'Fetching all Rule IDs' + @log.info 'DB', 'Fetching all Rule IDs' @db.smembers 'rules', cb ### @@ -513,7 +510,7 @@ Store a string representation of a rule in the DB. @param {String} data ### exports.storeRule = ( ruleId, data ) => - log.print 'DB', "storeRule: '#{ ruleId }'" + @log.info 'DB', "storeRule: '#{ ruleId }'" @db.sadd 'rules', "#{ ruleId }", replyHandler "storing rule key '#{ ruleId }'" @db.set "rule:#{ ruleId }", data, @@ -527,7 +524,7 @@ Delete a string representation of a rule. @param {String} userId ### exports.deleteRule = ( ruleId ) => - log.print 'DB', "deleteRule: '#{ ruleId }'" + @log.info 'DB', "deleteRule: '#{ ruleId }'" @db.srem "rules", ruleId, replyHandler "Deleting rule key '#{ ruleId }'" @db.del "rule:#{ ruleId }", replyHandler "Deleting rule '#{ ruleId }'" @@ -555,7 +552,7 @@ Associate a rule to a user. @param {String} userId ### exports.linkRule = ( ruleId, userId ) => - log.print 'DB', "linkRule: '#{ ruleId }' for user '#{ userId }'" + @log.info 'DB', "linkRule: '#{ ruleId }' for user '#{ userId }'" @db.sadd "rule:#{ ruleId }:users", userId, replyHandler "storing user '#{ userId }' for rule key '#{ ruleId }'" @db.sadd "user:#{ userId }:rules", ruleId, @@ -569,7 +566,7 @@ Get rules linked to a user and hand it to cb(err, obj). @param {function} cb ### exports.getUserLinkedRules = ( userId, cb ) => - log.print 'DB', "getUserLinkedRules: for user '#{ userId }'" + @log.info 'DB', "getUserLinkedRules: for user '#{ userId }'" @db.smembers "user:#{ userId }:rules", cb ### @@ -580,7 +577,7 @@ Get users linked to a rule and hand it to cb(err, obj). @param {function} cb ### exports.getRuleLinkedUsers = ( ruleId, cb ) => - log.print 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'" + @log.info 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'" @db.smembers "rule:#{ ruleId }:users", cb ### @@ -591,7 +588,7 @@ Delete an association of a rule to a user. @param {String} userId ### exports.unlinkRule = ( ruleId, userId ) => - log.print 'DB', "unlinkRule: '#{ ruleId }:#{ userId }'" + @log.info 'DB', "unlinkRule: '#{ ruleId }:#{ userId }'" @db.srem "rule:#{ ruleId }:users", userId, replyHandler "removing user '#{ userId }' for rule key '#{ ruleId }'" @db.srem "user:#{ userId }:rules", ruleId, @@ -605,7 +602,7 @@ Activate a rule. @param {String} userId ### exports.activateRule = ( ruleId, userId ) => - log.print 'DB', "activateRule: '#{ ruleId }' for '#{ userId }'" + @log.info 'DB', "activateRule: '#{ ruleId }' for '#{ userId }'" @db.sadd "rule:#{ ruleId }:active-users", userId, replyHandler "storing activated user '#{ userId }' in rule '#{ ruleId }'" @db.sadd "user:#{ userId }:active-rules", ruleId, @@ -619,7 +616,7 @@ Get rules activated for a user and hand it to cb(err, obj). @param {function} cb ### exports.getUserActivatedRules = ( userId, cb ) => - log.print 'DB', "getUserActivatedRules: for user '#{ userId }'" + @log.info 'DB', "getUserActivatedRules: for user '#{ userId }'" @db.smembers "user:#{ userId }:active-rules", cb ### @@ -630,7 +627,7 @@ Get users activated for a rule and hand it to cb(err, obj). @param {function} cb ### exports.getRuleActivatedUsers = ( ruleId, cb ) => - log.print 'DB', "getRuleActivatedUsers: for rule '#{ ruleId }'" + @log.info 'DB', "getRuleActivatedUsers: for rule '#{ ruleId }'" @db.smembers "rule:#{ ruleId }:active-users", cb ### @@ -641,7 +638,7 @@ Deactivate a rule. @param {String} userId ### exports.deactivateRule = ( ruleId, userId ) => - log.print 'DB', "deactivateRule: '#{ ruleId }' for '#{ userId }'" + @log.info 'DB', "deactivateRule: '#{ ruleId }' for '#{ userId }'" @db.srem "rule:#{ ruleId }:active-users", userId, replyHandler "removing activated user '#{ userId }' in rule '#{ ruleId }'" @db.srem "user:#{ userId }:active-rules", ruleId, @@ -654,7 +651,7 @@ Fetch all active ruleIds and pass them to cb(err, obj). @param {function} cb ### exports.getAllActivatedRuleIdsPerUser = ( cb ) => - log.print 'DB', "Fetching all active rules" + @log.info 'DB', "Fetching all active rules" @db.smembers 'users', ( err, obj ) => result = {} if obj.length is 0 @@ -684,7 +681,7 @@ The password should be hashed before it is passed to this function. exports.storeUser = ( objUser ) => #TODO Only store user if not already existing, or at least only then add a private key #for his encryption. we would want to have one private key per user, right? - log.print 'DB', "storeUser: '#{ objUser.username }'" + @log.info 'DB', "storeUser: '#{ objUser.username }'" if objUser and objUser.username and objUser.password @db.sadd 'users', objUser.username, replyHandler "storing user key '#{ objUser.username }'" @@ -692,7 +689,7 @@ exports.storeUser = ( objUser ) => @db.hmset "user:#{ objUser.username }", objUser, replyHandler "storing user properties '#{ objUser.username }'" else - log.error 'DB', new Error 'username or password was missing' + @log.error 'DB', new Error 'username or password was missing' ### Fetch all user IDs and pass them to cb(err, obj). @@ -701,7 +698,7 @@ Fetch all user IDs and pass them to cb(err, obj). @param {function} cb ### exports.getUserIds = ( cb ) => - log.print 'DB', "getUserIds" + @log.info 'DB', "getUserIds" @db.smembers "users", cb ### @@ -712,7 +709,7 @@ Fetch a user by id and pass it to cb(err, obj). @param {function} cb ### exports.getUser = ( userId, cb ) => - log.print 'DB', "getUser: '#{ userId }'" + @log.info 'DB', "getUser: '#{ userId }'" @db.hgetall "user:#{ userId }", cb ### @@ -722,7 +719,7 @@ Deletes a user and all his associated linked and active rules. @param {String} userId ### exports.deleteUser = ( userId ) => - log.print 'DB', "deleteUser: '#{ userId }'" + @log.info 'DB', "deleteUser: '#{ userId }'" @db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'" @db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'" @@ -766,14 +763,14 @@ because we only store hashes of passwords for security6 reasons. ### #TODO verify and test whole function exports.loginUser = ( userId, password, cb ) => - log.print 'DB', "User '#{ userId }' tries to log in" - fCheck = ( pw ) -> - ( err, obj ) -> + @log.info 'DB', "User '#{ userId }' tries to log in" + fCheck = ( pw ) => + ( err, obj ) => if err cb err, null else if obj and obj.password if pw == obj.password - log.print 'DB', "User '#{ obj.username }' logged in!" + @log.info 'DB', "User '#{ obj.username }' logged in!" cb null, obj else cb (new Error 'Wrong credentials!'), null @@ -796,7 +793,7 @@ Associate a role with a user. @param {String} role ### exports.storeUserRole = ( userId, role ) => - log.print 'DB', "storeUserRole: '#{ userId }:#{ role }'" + @log.info 'DB', "storeUserRole: '#{ userId }:#{ role }'" @db.sadd 'roles', role, replyHandler "adding role '#{ role }' to role index set" @db.sadd "user:#{ userId }:roles", role, replyHandler "adding role '#{ role }' to user '#{ userId }'" @@ -811,7 +808,7 @@ Fetch all roles of a user and pass them to cb(err, obj). @param {function} cb ### exports.getUserRoles = ( userId, cb ) => - log.print 'DB', "getUserRoles: '#{ userId }'" + @log.info 'DB', "getUserRoles: '#{ userId }'" @db.smembers "user:#{ userId }:roles", cb ### @@ -822,7 +819,7 @@ Fetch all users of a role and pass them to cb(err, obj). @param {function} cb ### exports.getRoleUsers = ( role, cb ) => - log.print 'DB', "getRoleUsers: '#{ role }'" + @log.info 'DB', "getRoleUsers: '#{ role }'" @db.smembers "role:#{ role }:users", cb ### @@ -833,7 +830,7 @@ Remove a role from a user. @param {String} userId ### exports.removeUserRole = ( userId, role ) => - log.print 'DB', "removeRoleFromUser: role '#{ role }', user '#{ userId }'" + @log.info 'DB', "removeRoleFromUser: role '#{ role }', user '#{ userId }'" @db.srem "user:#{ userId }:roles", role, replyHandler "Removing role '#{ role }' from user '#{ userId }'" @db.srem "role:#{ role }:users", userId, @@ -845,4 +842,4 @@ Shuts down the db link. @public shutDown() ### -exports.shutDown = () => @db.quit() +exports.shutDown = () => @db?.quit() diff --git a/coffee/sandbox.coffee b/coffee/sandbox.coffee new file mode 100644 index 0000000..7d77c21 --- /dev/null +++ b/coffee/sandbox.coffee @@ -0,0 +1,16 @@ +bunyan = require 'bunyan' +opt = + name: "webapi-eca" +opt.streams = [ + { + level: 'info' + stream: process.stdout + }, + { + level: 'info' + path: 'logs/server.log' + } + ] +# Finally we create the bunyan logger +logger = bunyan.createLogger opt +logger.info 'weeee' \ No newline at end of file diff --git a/coffee/webapi-eca.coffee b/coffee/webapi-eca.coffee index 553e298..7e0befc 100644 --- a/coffee/webapi-eca.coffee +++ b/coffee/webapi-eca.coffee @@ -1,19 +1,19 @@ ### -Server -============ +WebAPI-ECA Engine +================= ->This is the main module that is used to run the whole server: +>This is the main module that is used to run the whole application: > -> node server [opt] +> node webapi-eca [opt] > -> See below in the optimist CLI preparation for allowed optional parameters +> See below in the optimist CLI preparation for allowed optional parameters `[opt]`. ### # **Requires:** # - [Logging](logging.html) -logger = require './new-logging' +logger = require './logging' # - [Configuration](config.html) conf = require './config' @@ -40,37 +40,48 @@ optimist = require 'optimist' procCmds = {} ### -Let's prepare the optimist CLI +Let's prepare the optimist CLI optional arguments `[opt]`: ### usage = 'This runs your webapi-based ECA engine' opt = +# `-h`, `--help`: Display the help 'h': alias : 'help', describe: 'Display this' +# `-c`, `--config-path`: Specify a path to a custom configuration file, other than "config/config.json" 'c': alias : 'config-path', describe: 'Specify a path to a custom configuration file, other than "config/config.json"' +# `-w`, `--http-port`: Specify a HTTP port for the web server 'w': alias : 'http-port', describe: 'Specify a HTTP port for the web server' +# `-d`, `--db-port`: Specify a port for the redis DB 'd': alias : 'db-port', describe: 'Specify a port for the redis DB' +# `-m`, `--log-mode`: Specify a log mode: [development|productive] 'm': alias : 'log-mode', describe: 'Specify a log mode: [development|productive]' +# `-i`, `--log-io-level`: Specify the log level for the I/O 'i': alias : 'log-io-level', describe: 'Specify the log level for the I/O' +# `-f`, `--log-file-level`: Specify the log level for the log file 'f': alias : 'log-file-level', describe: 'Specify the log level for the log file' +# `-p`, `--log-file-path`: Specify the path to the log file within the "logs" folder 'p': alias : 'log-file-path', describe: 'Specify the path to the log file within the "logs" folder' +# `-n`, `--nolog`: Set this if no output shall be generated 'n': alias : 'nolog', describe: 'Set this if no output shall be generated' + +# now fetch the CLI arguments and exit if the help has been called. argv = optimist.usage( usage ).options( opt ).argv if argv.help console.log optimist.help() diff --git a/documentation/techdoc/techdoc.tex b/documentation/techdoc/techdoc.tex index 012e83e..7b54ac6 100644 --- a/documentation/techdoc/techdoc.tex +++ b/documentation/techdoc/techdoc.tex @@ -1,4 +1,7 @@ \documentclass{article} +\usepackage{cite} +\usepackage{courier} +\usepackage[toc,page]{appendix} \newcommand*{\createTitlePage}{\begingroup \centering @@ -23,29 +26,6 @@ \clearpage\createTitlePage \thispagestyle{empty} -% \title{\huge WebAPI-ECA Engine\vspace*{15 mm}} -% \subtitle{Master Thesis Report} -% %\date{} -% %\author{Dominic Bosch \\ Departement Mathematics and Computer Science \\ University of Basel} -% \author{ -% Technical Documentation\\ -% \date{\today} -% \vspace*{50 mm}\\ -% \fontsize{10}{9}\selectfont -% Dominic Bosch\\ -% \fontsize{10}{9}\selectfont -% Departement Mathematics and Computer Science\\ -% \fontsize{10}{9}\selectfont -% University of Basel -% } -% \maketitle - -% \renewcommand{\abstractname}{} -% \begin{abstract} -% %\textbf{Abstract.} -% This docuemnt describes the technical features of the WebAPI-ECA engine reference implementation. -% \end{abstract} - \newpage \tableofcontents @@ -56,5 +36,97 @@ \subsection{section} \subsubsection{subsection} t.b.d. +Introduction +%Documentation can be found on localhost:[http_port]/doc/ + +% TODO +% Key files within the application. This may include files created by the development team, databases accessed during the program's operation, and third-party utility programs. +% Functions and subroutines. This includes an explanation of what each function or subroutine does, including its range of input values and output values. +% Program variables and constants, and how they're used in the application. +% The overall program structure. For a disc-based application, this may mean describing the program's individual modules and libraries, while for a Web application, this may mean describing which pages use which files. + +\section{Prerequisites} +Redis or write own DB Interface + +Node.js + +\section{Installation} +Crossplatform + +\section{Configuration} + +\section{Application Architecture} +The application is started through the webapi-eca module, which loads other modules such as the logging module, the configuration file handler, the persistence interface, the listener to HTTP requests and finally the ECA engine. +% TODO Architecture picture goes here! + +\subsection{Modules} +\subsubsection{Webapi-ECA} +starting point +reads cli arguments +Initializes: +config +engine +persistence +http listener +logging +forks the event poller and sends him information about new rules so he can fetch the appropriate event poller modules. + +\subsubsection{Persistence} +The persistence module is an interface to a persistent storage. +It stores the events in a queue, action invoker modules, event poller modules, rules, users and roles. +Event Queue +\texttt{event\_queue} (List): The event queue for all incoming events to be processed by the engine. +Action Invokers +\texttt{action-invokers} (Set of [aiId] keys): A set of all existing action invokers. +\texttt{action-invoker:[aiId]} (String): A stringified action invoker. +\texttt{action-params} (Set of [aiId]:[userId] keys): All existing action invoker parameters associated with a user. +\texttt{action-params:[aiId]:[userId]} (String): A stringified parameter object associated to an action invoker and a user. +Event Pollers +\texttt{event-pollers} (Set of [epId] keys): A set of all existing event pollers. +\texttt{event-poller:[epId]} (String): A stringified event poller. +\texttt{event-params} (Set of [epId]:[userId] keys): All existing event poller parameters associated with a user. +\texttt{event-params:[epId]:[userId]} (String): A stringified parameter object associated to an event poller and a user. +Rules +\texttt{rules} (Set of [ruleId] keys): A set of all existing rules. +\texttt{rule:[ruleId]:users} (Set of [userId] keys): Associated users to a rule. +\texttt{rule:[ruleId]} (String): Stringified rule object. +\texttt{rule:[ruleId]:active-users} (Set of [userId] keys): Users that have this rule activated. +Users +\texttt{users} (Set of [userId] keys): A set of all existing users. +\texttt{user:[userId]} (Hashmap): The flat user object. +\texttt{user:[userId]:rules} (Set of [ruleId] keys): Associated rules to a user. +\texttt{user:[userId]:active-rules} (Set of [ruleId] keys): Active rules. +\texttt{user:[userId]:roles} (Set of [roleId] keys): All roles a certain user is associated with. +Roles +\texttt{roles} (Set of [roleId] keys): A set of all existing roles. +\texttt{role:[roleId]:users} (Set of [userId] keys): All users associated to this role. + +\subsection{Views/Webpages} +user interfaces +login +credentials entered in a login form are encrypted using a random key and only then sent to the server. +we fetch the google crypto-js module in the browser from +% \ + +and the engine fetches the same but modularized code from the npm repository via the package manager. Now we have the same crypto-js code in both modules + +this also allows us to send privately stored modules and rules encrypted to the user, which will then see it decrypted after it arrived at the browser + + + + +\bibliography{user-manual} +\bibliographystyle{beast} + +\newpage +\renewcommand*\appendixpagename{APPENDIX} +\renewcommand*\appendixtocname{APPENDIX} +\begin{appendices} + \section{Things} + \subsection{Important things} + % \subsubsection{ecaserver.js} + Some appendix content + +\end{appendices} \end{document} \ No newline at end of file diff --git a/documentation/user-manual/user-manual.tex b/documentation/user-manual/user-manual.tex index 715191b..f486225 100644 --- a/documentation/user-manual/user-manual.tex +++ b/documentation/user-manual/user-manual.tex @@ -1,4 +1,6 @@ \documentclass{article} +\usepackage{cite} +\usepackage[toc,page]{appendix} \newcommand*{\createTitlePage}{\begingroup \centering @@ -23,28 +25,6 @@ \clearpage\createTitlePage \thispagestyle{empty} -% \title{\huge WebAPI-ECA Engine\vspace*{15 mm}} -% \subtitle{Master Thesis Report} -% %\date{} -% %\author{Dominic Bosch \\ Departement Mathematics and Computer Science \\ University of Basel} -% \author{ -% Technical Documentation\\ -% \date{\today} -% \vspace*{50 mm}\\ -% \fontsize{10}{9}\selectfont -% Dominic Bosch\\ -% \fontsize{10}{9}\selectfont -% Departement Mathematics and Computer Science\\ -% \fontsize{10}{9}\selectfont -% University of Basel -% } -% \maketitle - -% \renewcommand{\abstractname}{} -% \begin{abstract} -% %\textbf{Abstract.} -% This docuemnt describes the technical features of the WebAPI-ECA engine reference implementation. -% \end{abstract} \newpage @@ -57,4 +37,32 @@ \subsubsection{subsection} t.b.d. +\section{Administrator} +Start the server +Event \& Action Module Management +For All: CRUD, The view shows all existing modules per user and allows editing +Rules +For All: CRUD +\section{User} +Event \& Action Module Management +Per User: CRUD \& Credentials +Rule Management\cite{2005-Patranjan-TLE.pdf} +Per User: CRUD + + + +\bibliography{user-manual} +\bibliographystyle{beast} + +\newpage +\renewcommand*\appendixpagename{APPENDIX} +\renewcommand*\appendixtocname{APPENDIX} +\begin{appendices} + \section{Things} + \subsection{Important things} + % \subsubsection{ecaserver.js} + Some appendix content + +\end{appendices} + \end{document} \ No newline at end of file diff --git a/js-coffee/event-poller.js b/js-coffee/event-poller.js index 3027f2d..c059bd7 100644 --- a/js-coffee/event-poller.js +++ b/js-coffee/event-poller.js @@ -2,7 +2,7 @@ 'use strict'; -var logger = require('./new-logging'), +var logger = require('./logging'), listMessageActions = {}, listAdminCommands = {}, listEventModules = {}, diff --git a/js-coffee/logging.js b/js-coffee/logging.js index df44534..4e9fc78 100644 --- a/js-coffee/logging.js +++ b/js-coffee/logging.js @@ -1,107 +1,70 @@ -/* - * Logging - * ======= - * Functions to handle logging and errors. - * - * Valid log types are: - * - * - 0 standard I/O - * - 1 file - * - 2 silent - */ - //TODO dynamic log file names (especially to track unit test logs) -var fs = require('fs'), - wst = require('winston'), - logTypes = [ flushToConsole, flushToFile, null], - logFile = require('path').resolve(__dirname, '..', 'server.log'), - logType = 0; +// Generated by CoffeeScript 1.6.3 +(function() { + var bunyan, fs, path, + _this = this; -exports = module.exports = function(args) { - args = args || {}; - if(args.logType) logType = parseInt(args.logType) || 0; - if(logType == 1) fs.truncateSync(logFile, 0); - if(logType > logTypes.length - 1) logType = 0; - // winston.add(winston.transports.File, { filename: 'somefile.log' }); - // winston.remove(winston.transports.Console); - return module.exports; -}; + fs = require('fs'); -exports.getLogType = function() { return logType; }; + path = require('path'); -function flush(err, msg) { - if(typeof logTypes[logType] === 'function') logTypes[logType](err, msg); -} + bunyan = require('bunyan'); -function flushToConsole(err, msg) { - if(err) console.error("\033[31m" + msg + "\033[0m"); - else console.log(msg); - // if(err) console.error(msg); - // else console.log(msg); -} + /* + Returns a bunyan logger according to the given arguments. + + @public getLogger( *args* ) + @param {Object} args + */ -function flushToFile(err, msg) { - fs.appendFile(logFile, msg + '\n', function (err) {}); -} -// @function print(module, msg) + exports.getLogger = function(args) { + var e, emptylog, opt; + emptylog = { + info: function() {}, + warn: function() {}, + error: function() {}, + getLog: function() {} + }; + args = args != null ? args : {}; + if (args.nolog) { + return emptylog; + } else { + try { + opt = { + name: "webapi-eca" + }; + if (args['mode'] === 'development') { + opt.src = true; + } + if (args['file-path']) { + _this.logPath = path.resolve(args['file-path']); + } else { + _this.logPath = path.resolve(__dirname, '..', 'logs', 'server.log'); + } + try { + fs.writeFileSync(_this.logPath + '.temp', 'temp'); + fs.unlinkSync(_this.logPath + '.temp'); + } catch (_error) { + e = _error; + console.error("Log folder '" + _this.logPath + "' is not writable"); + return emptylog; + } + opt.streams = [ + { + level: args['io-level'], + stream: process.stdout + }, { + level: args['file-level'], + path: _this.logPath + } + ]; + return bunyan.createLogger(opt); + } catch (_error) { + e = _error; + console.error(e); + return emptylog; + } + } + }; -/* - * Prints a log to stdout. - * @param {String} module - * @param {String} msg - */ -exports.print = function(module, msg) { - flush(false, (new Date()).toISOString() + ' | ' + module + ' | ' + msg); -}; - -/** - * Prints a log to stderr. - * @param {String} module - * @param {Error} err - */ -function printError(module, err, isSevere) { - var ts = (new Date()).toISOString() + ' | ', ai = ''; - if(!err) { - err = new Error('Unexpected error'); - isSevere = true; - } - if(typeof err === 'string') err = new Error(err); - // if(module) flush(true, ts + module + ' | ERROR AND BAD HANDLING: ' + err + '\n' + e.stack); - // else flush(true, ts + '!N/A! | ERROR, BAD HANDLING AND NO MODULE NAME: ' + err + '\n' + e.stack); - // } else if(err) { - if(err.addInfo) ai = ' (' + err.addInfo + ')'; - if(!err.message) err.message = 'UNKNOWN REASON!\n' + err.stack; - if(module) { - var msg = ts + module + ' | ERROR'+ai+': ' + err.message; - if(isSevere) msg += '\n' + err.stack; - flush(true, msg); - } else flush(true, ts + '!N/A! | ERROR AND NO MODULE NAME'+ai+': ' + err.message + '\n' + err.stack); - // } else { - // var e = new Error('Unexpected error'); - // flush(true, e.message + ': \n' + e.stack); - // } -}; - -/** - * Prints a message to stderr. - * @param {String} module - * @param {Error} err - */ -exports.error = function(module, err) { - printError(module, err, false); -}; - -/** - * Prints a message with error stack to stderr - * @param {String} module - * @param {Error} err - */ -exports.severe = function(module, err) { - printError(module, err, true); -}; - -exports.obj = function (varname, obj) { - var arrS = (new Error).stack.split('\n'); - console.log('Dumping object "' + varname + '"' + arrS[2]); - console.log(obj); -}; +}).call(this); diff --git a/js-coffee/new-logging.js b/js-coffee/new-logging.js deleted file mode 100644 index 7585b5a..0000000 --- a/js-coffee/new-logging.js +++ /dev/null @@ -1,66 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var bunyan, exports, path, - _this = this; - - path = require('path'); - - bunyan = require('bunyan'); - - /* - Module call - ----------- - - Calling the module as a function will act as a constructor and load the config file. - It is possible to hand an args object with the properties nolog (true if no outputs shall - be generated) and configPath for a custom configuration file path. - - @param {Object} args - */ - - - exports = module.exports = function(args) { - var e, emptylog, opt; - emptylog = { - info: function() {}, - warn: function() {}, - error: function() {} - }; - args = args != null ? args : {}; - if (args.nolog) { - return emptylog; - } else { - try { - opt = { - name: "webapi-eca" - }; - if (args['mode'] === 'development') { - opt.src = true; - } - if (args['file-path']) { - _this.logPath = path.resolve(__dirname, '..', 'logs', args['file-path']); - } else { - _this.logPath = path.resolve(__dirname, '..', 'logs', 'server.log'); - } - opt.streams = [ - { - level: args['io-level'], - stream: process.stdout - }, { - level: args['file-level'], - type: 'rotating-file', - path: _this.logPath, - period: '1d', - count: 3 - } - ]; - return bunyan.createLogger(opt); - } catch (_error) { - e = _error; - console.error(e); - return emptylog; - } - } - }; - -}).call(this); diff --git a/js-coffee/persistence.js b/js-coffee/persistence.js index fd35317..edda71d 100644 --- a/js-coffee/persistence.js +++ b/js-coffee/persistence.js @@ -21,12 +21,10 @@ Persistence (function() { - var IndexedModules, crypto, decrypt, encrypt, exports, getSetRecords, hash, log, redis, replyHandler, + var IndexedModules, crypto, decrypt, encrypt, exports, getSetRecords, hash, redis, replyHandler, _this = this, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - log = require('./logging'); - crypto = require('crypto-js'); redis = require('redis'); @@ -43,8 +41,7 @@ Persistence exports = module.exports = function(args) { var config, _ref; - args = args != null ? args : {}; - log(args); + _this.log = args.logger; config = require('./config'); config(args); if ((_ref = _this.db) != null) { @@ -57,12 +54,12 @@ Persistence }); _this.db.on('error', function(err) { err.addInfo = 'message from DB'; - return log.error('DB', err); + return _this.log.error('DB', err); }); - _this.ep = new IndexedModules('event-poller', _this.db); - return _this.ai = new IndexedModules('action-invoker', _this.db); + _this.ep = new IndexedModules('event-poller', _this.db, _this.log); + return _this.ai = new IndexedModules('action-invoker', _this.db, _this.log); } else { - return log.error('DB', 'Initialization failed because of missing config file!'); + return _this.log.error('DB', 'Initialization failed because of missing config file!'); } }; @@ -83,7 +80,7 @@ Persistence numAttempts = 0; fCheckConnection = function() { if (_this.db.connected) { - log.print('DB', 'Successfully connected to DB!'); + _this.log.info('DB', 'Successfully connected to DB!'); return cb(); } else if (numAttempts++ < 10) { return setTimeout(fCheckConnection, 100); @@ -107,9 +104,9 @@ Persistence return function(err, reply) { if (err) { err.addInfo = "during '" + action + "'"; - return log.error('DB', err); + return _this.log.error('DB', err); } else { - return log.print('DB', "" + action + ": " + reply); + return _this.log.info('DB', "" + action + ": " + reply); } }; }; @@ -124,10 +121,10 @@ Persistence exports.pushEvent = function(oEvent) { if (oEvent) { - log.print('DB', "Event pushed into the queue: '" + oEvent.eventid + "'"); + _this.log.info('DB', "Event pushed into the queue: '" + oEvent.eventid + "'"); return _this.db.rpush('event_queue', JSON.stringify(oEvent)); } else { - return log.error('DB', 'Why would you give me an empty event...'); + return _this.log.error('DB', 'Why would you give me an empty event...'); } }; @@ -180,7 +177,7 @@ Persistence } catch (_error) { err = _error; err.addInfo = 'during hashing'; - log.error('DB', err); + _this.log.error('DB', err); return null; } }; @@ -203,7 +200,7 @@ Persistence } catch (_error) { err = _error; err.addInfo = 'during encryption'; - log.error('DB', err); + _this.log.error('DB', err); return null; } }; @@ -227,7 +224,7 @@ Persistence } catch (_error) { err = _error; err.addInfo = 'during decryption'; - log.error('DB', err); + _this.log.error('DB', err); return null; } }; @@ -246,12 +243,12 @@ Persistence getSetRecords = function(set, fSingle, cb) { - log.print('DB', "Fetching set records: '" + set + "'"); + _this.log.info('DB', "Fetching set records: '" + set + "'"); return _this.db.smembers(set, function(err, arrReply) { var fCallback, objReplies, reply, semaphore, _i, _len, _results; if (err) { err.addInfo = "fetching '" + set + "'"; - log.error('DB', err); + _this.log.error('DB', err); return cb(err); } else if (arrReply.length === 0) { return cb(); @@ -268,9 +265,9 @@ Persistence --semaphore; if (err) { err.addInfo = "fetching single element: '" + prop + "'"; - log.error('DB', err); + _this.log.error('DB', err); } else if (!data) { - log.error('DB', new Error("Empty key in DB: '" + prop + "'")); + _this.log.error('DB', new Error("Empty key in DB: '" + prop + "'")); } else { objReplies[prop] = data; } @@ -290,9 +287,10 @@ Persistence }; IndexedModules = (function() { - function IndexedModules(setname, db) { + function IndexedModules(setname, db, log) { this.setname = setname; this.db = db; + this.log = log; this.deleteParameters = __bind(this.deleteParameters, this); this.getParametersIds = __bind(this.getParametersIds, this); this.getParameters = __bind(this.getParameters, this); @@ -302,56 +300,56 @@ Persistence this.getModuleIds = __bind(this.getModuleIds, this); this.getModule = __bind(this.getModule, this); this.storeModule = __bind(this.storeModule, this); - log.print('DB', "Instantiated indexed modules for '" + this.setname + "'"); + this.log.info('DB', "Instantiated indexed modules for '" + this.setname + "'"); } IndexedModules.prototype.storeModule = function(mId, data) { - log.print('DB', "storeModule(" + this.setname + "): " + mId); + this.log.info('DB', "storeModule(" + this.setname + "): " + mId); this.db.sadd("" + this.setname + "s", mId, replyHandler("Storing '" + this.setname + "' key '" + mId + "'")); return this.db.set("" + this.setname + ":" + mId, data, replyHandler("Storing '" + this.setname + ":" + mId + "'")); }; IndexedModules.prototype.getModule = function(mId, cb) { - log.print('DB', "getModule('" + this.setname + "): " + mId + "'"); + this.log.info('DB', "getModule('" + this.setname + "): " + mId + "'"); return this.db.get("" + this.setname + ":" + mId, cb); }; IndexedModules.prototype.getModuleIds = function(cb) { - log.print('DB', "getModuleIds(" + this.setname + ")"); + this.log.info('DB', "getModuleIds(" + this.setname + ")"); return this.db.smembers("" + this.setname + "s", cb); }; IndexedModules.prototype.getModules = function(cb) { - log.print('DB', "getModules(" + this.setname + ")"); + this.log.info('DB', "getModules(" + this.setname + ")"); return getSetRecords("" + this.setname + "s", this.getModule, cb); }; IndexedModules.prototype.deleteModule = function(mId) { - log.print('DB', "deleteModule(" + this.setname + "): " + mId); + this.log.info('DB', "deleteModule(" + this.setname + "): " + mId); this.db.srem("" + this.setname + "s", mId, replyHandler("Deleting '" + this.setname + "' key '" + mId + "'")); return this.db.del("" + this.setname + ":" + mId, replyHandler("Deleting '" + this.setname + ":" + mId + "'")); }; IndexedModules.prototype.storeParameters = function(mId, userId, data) { - log.print('DB', "storeParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + this.log.info('DB', "storeParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); this.db.sadd("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Storing '" + this.setname + "' module parameters key '" + mId + "'")); return this.db.set("" + this.setname + "-params:" + mId + ":" + userId, encrypt(data), replyHandler("Storing '" + this.setname + "' module parameters '" + mId + ":" + userId + "'")); }; IndexedModules.prototype.getParameters = function(mId, userId, cb) { - log.print('DB', "getParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + this.log.info('DB', "getParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, function(err, data) { return cb(err, decrypt(data)); }); }; IndexedModules.prototype.getParametersIds = function(cb) { - log.print('DB', "getParametersIds(" + this.setname + ")"); + this.log.info('DB', "getParametersIds(" + this.setname + ")"); return this.db.smembers("" + this.setname + "-params", cb); }; IndexedModules.prototype.deleteParameters = function(mId, userId) { - log.print('DB', "deleteParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + this.log.info('DB', "deleteParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); this.db.srem("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params' key '" + mId + ":" + userId + "'")); return this.db.del("" + this.setname + "-params:" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params:" + mId + ":" + userId + "'")); }; @@ -615,7 +613,7 @@ Persistence exports.getRule = function(ruleId, cb) { - log.print('DB', "getRule: '" + ruleId + "'"); + _this.log.info('DB', "getRule: '" + ruleId + "'"); return _this.db.get("rule:" + ruleId, cb); }; @@ -628,7 +626,7 @@ Persistence exports.getRules = function(cb) { - log.print('DB', 'Fetching all Rules'); + _this.log.info('DB', 'Fetching all Rules'); return getSetRecords('rules', exports.getRule, cb); }; @@ -641,7 +639,7 @@ Persistence exports.getRuleIds = function(cb) { - log.print('DB', 'Fetching all Rule IDs'); + _this.log.info('DB', 'Fetching all Rule IDs'); return _this.db.smembers('rules', cb); }; @@ -655,7 +653,7 @@ Persistence exports.storeRule = function(ruleId, data) { - log.print('DB', "storeRule: '" + ruleId + "'"); + _this.log.info('DB', "storeRule: '" + ruleId + "'"); _this.db.sadd('rules', "" + ruleId, replyHandler("storing rule key '" + ruleId + "'")); return _this.db.set("rule:" + ruleId, data, replyHandler("storing rule '" + ruleId + "'")); }; @@ -670,7 +668,7 @@ Persistence exports.deleteRule = function(ruleId) { - log.print('DB', "deleteRule: '" + ruleId + "'"); + _this.log.info('DB', "deleteRule: '" + ruleId + "'"); _this.db.srem("rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "'")); _this.db.del("rule:" + ruleId, replyHandler("Deleting rule '" + ruleId + "'")); _this.db.smembers("rule:" + ruleId + ":users", function(err, obj) { @@ -711,7 +709,7 @@ Persistence exports.linkRule = function(ruleId, userId) { - log.print('DB', "linkRule: '" + ruleId + "' for user '" + userId + "'"); + _this.log.info('DB', "linkRule: '" + ruleId + "' for user '" + userId + "'"); _this.db.sadd("rule:" + ruleId + ":users", userId, replyHandler("storing user '" + userId + "' for rule key '" + ruleId + "'")); return _this.db.sadd("user:" + userId + ":rules", ruleId, replyHandler("storing rule key '" + ruleId + "' for user '" + userId + "'")); }; @@ -726,7 +724,7 @@ Persistence exports.getUserLinkedRules = function(userId, cb) { - log.print('DB', "getUserLinkedRules: for user '" + userId + "'"); + _this.log.info('DB', "getUserLinkedRules: for user '" + userId + "'"); return _this.db.smembers("user:" + userId + ":rules", cb); }; @@ -740,7 +738,7 @@ Persistence exports.getRuleLinkedUsers = function(ruleId, cb) { - log.print('DB', "getRuleLinkedUsers: for rule '" + ruleId + "'"); + _this.log.info('DB', "getRuleLinkedUsers: for rule '" + ruleId + "'"); return _this.db.smembers("rule:" + ruleId + ":users", cb); }; @@ -754,7 +752,7 @@ Persistence exports.unlinkRule = function(ruleId, userId) { - log.print('DB', "unlinkRule: '" + ruleId + ":" + userId + "'"); + _this.log.info('DB', "unlinkRule: '" + ruleId + ":" + userId + "'"); _this.db.srem("rule:" + ruleId + ":users", userId, replyHandler("removing user '" + userId + "' for rule key '" + ruleId + "'")); return _this.db.srem("user:" + userId + ":rules", ruleId, replyHandler("removing rule key '" + ruleId + "' for user '" + userId + "'")); }; @@ -769,7 +767,7 @@ Persistence exports.activateRule = function(ruleId, userId) { - log.print('DB', "activateRule: '" + ruleId + "' for '" + userId + "'"); + _this.log.info('DB', "activateRule: '" + ruleId + "' for '" + userId + "'"); _this.db.sadd("rule:" + ruleId + ":active-users", userId, replyHandler("storing activated user '" + userId + "' in rule '" + ruleId + "'")); return _this.db.sadd("user:" + userId + ":active-rules", ruleId, replyHandler("storing activated rule '" + ruleId + "' in user '" + userId + "'")); }; @@ -784,7 +782,7 @@ Persistence exports.getUserActivatedRules = function(userId, cb) { - log.print('DB', "getUserActivatedRules: for user '" + userId + "'"); + _this.log.info('DB', "getUserActivatedRules: for user '" + userId + "'"); return _this.db.smembers("user:" + userId + ":active-rules", cb); }; @@ -798,7 +796,7 @@ Persistence exports.getRuleActivatedUsers = function(ruleId, cb) { - log.print('DB', "getRuleActivatedUsers: for rule '" + ruleId + "'"); + _this.log.info('DB', "getRuleActivatedUsers: for rule '" + ruleId + "'"); return _this.db.smembers("rule:" + ruleId + ":active-users", cb); }; @@ -812,7 +810,7 @@ Persistence exports.deactivateRule = function(ruleId, userId) { - log.print('DB', "deactivateRule: '" + ruleId + "' for '" + userId + "'"); + _this.log.info('DB', "deactivateRule: '" + ruleId + "' for '" + userId + "'"); _this.db.srem("rule:" + ruleId + ":active-users", userId, replyHandler("removing activated user '" + userId + "' in rule '" + ruleId + "'")); return _this.db.srem("user:" + userId + ":active-rules", ruleId, replyHandler("removing activated rule '" + ruleId + "' in user '" + userId + "'")); }; @@ -826,7 +824,7 @@ Persistence exports.getAllActivatedRuleIdsPerUser = function(cb) { - log.print('DB', "Fetching all active rules"); + _this.log.info('DB', "Fetching all active rules"); return _this.db.smembers('users', function(err, obj) { var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results; result = {}; @@ -869,13 +867,13 @@ Persistence exports.storeUser = function(objUser) { - log.print('DB', "storeUser: '" + objUser.username + "'"); + _this.log.info('DB', "storeUser: '" + objUser.username + "'"); if (objUser && objUser.username && objUser.password) { _this.db.sadd('users', objUser.username, replyHandler("storing user key '" + objUser.username + "'")); objUser.password = objUser.password; return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties '" + objUser.username + "'")); } else { - return log.error('DB', new Error('username or password was missing')); + return _this.log.error('DB', new Error('username or password was missing')); } }; @@ -888,7 +886,7 @@ Persistence exports.getUserIds = function(cb) { - log.print('DB', "getUserIds"); + _this.log.info('DB', "getUserIds"); return _this.db.smembers("users", cb); }; @@ -902,7 +900,7 @@ Persistence exports.getUser = function(userId, cb) { - log.print('DB', "getUser: '" + userId + "'"); + _this.log.info('DB', "getUser: '" + userId + "'"); return _this.db.hgetall("user:" + userId, cb); }; @@ -915,7 +913,7 @@ Persistence exports.deleteUser = function(userId) { - log.print('DB', "deleteUser: '" + userId + "'"); + _this.log.info('DB', "deleteUser: '" + userId + "'"); _this.db.srem("users", userId, replyHandler("Deleting user key '" + userId + "'")); _this.db.del("user:" + userId, replyHandler("Deleting user '" + userId + "'")); _this.db.smembers("user:" + userId + ":rules", function(err, obj) { @@ -974,14 +972,14 @@ Persistence exports.loginUser = function(userId, password, cb) { var fCheck; - log.print('DB', "User '" + userId + "' tries to log in"); + _this.log.info('DB', "User '" + userId + "' tries to log in"); fCheck = function(pw) { return function(err, obj) { if (err) { return cb(err, null); } else if (obj && obj.password) { if (pw === obj.password) { - log.print('DB', "User '" + obj.username + "' logged in!"); + _this.log.info('DB', "User '" + obj.username + "' logged in!"); return cb(null, obj); } else { return cb(new Error('Wrong credentials!'), null); @@ -1009,7 +1007,7 @@ Persistence exports.storeUserRole = function(userId, role) { - log.print('DB', "storeUserRole: '" + userId + ":" + role + "'"); + _this.log.info('DB', "storeUserRole: '" + userId + ":" + role + "'"); _this.db.sadd('roles', role, replyHandler("adding role '" + role + "' to role index set")); _this.db.sadd("user:" + userId + ":roles", role, replyHandler("adding role '" + role + "' to user '" + userId + "'")); return _this.db.sadd("role:" + role + ":users", userId, replyHandler("adding user '" + userId + "' to role '" + role + "'")); @@ -1025,7 +1023,7 @@ Persistence exports.getUserRoles = function(userId, cb) { - log.print('DB', "getUserRoles: '" + userId + "'"); + _this.log.info('DB', "getUserRoles: '" + userId + "'"); return _this.db.smembers("user:" + userId + ":roles", cb); }; @@ -1039,7 +1037,7 @@ Persistence exports.getRoleUsers = function(role, cb) { - log.print('DB', "getRoleUsers: '" + role + "'"); + _this.log.info('DB', "getRoleUsers: '" + role + "'"); return _this.db.smembers("role:" + role + ":users", cb); }; @@ -1053,7 +1051,7 @@ Persistence exports.removeUserRole = function(userId, role) { - log.print('DB', "removeRoleFromUser: role '" + role + "', user '" + userId + "'"); + _this.log.info('DB', "removeRoleFromUser: role '" + role + "', user '" + userId + "'"); _this.db.srem("user:" + userId + ":roles", role, replyHandler("Removing role '" + role + "' from user '" + userId + "'")); return _this.db.srem("role:" + role + ":users", userId, replyHandler("Removing user '" + userId + "' from role '" + role + "'")); }; @@ -1066,7 +1064,8 @@ Persistence exports.shutDown = function() { - return _this.db.quit(); + var _ref; + return (_ref = _this.db) != null ? _ref.quit() : void 0; }; }).call(this); diff --git a/js-coffee/sandbox.js b/js-coffee/sandbox.js new file mode 100644 index 0000000..fcfdd91 --- /dev/null +++ b/js-coffee/sandbox.js @@ -0,0 +1,25 @@ +// Generated by CoffeeScript 1.6.3 +(function() { + var bunyan, logger, opt; + + bunyan = require('bunyan'); + + opt = { + name: "webapi-eca" + }; + + opt.streams = [ + { + level: 'info', + stream: process.stdout + }, { + level: 'info', + path: 'logs/server.log' + } + ]; + + logger = bunyan.createLogger(opt); + + logger.info('weeee'); + +}).call(this); diff --git a/js-coffee/webapi-eca.js b/js-coffee/webapi-eca.js index 32f6c18..edcf809 100644 --- a/js-coffee/webapi-eca.js +++ b/js-coffee/webapi-eca.js @@ -1,21 +1,21 @@ // Generated by CoffeeScript 1.6.3 /* -Server -============ +WebAPI-ECA Engine +================= ->This is the main module that is used to run the whole server: +>This is the main module that is used to run the whole application: > -> node server [opt] +> node webapi-eca [opt] > -> See below in the optimist CLI preparation for allowed optional parameters +> See below in the optimist CLI preparation for allowed optional parameters `[opt]`. */ (function() { var argv, conf, cp, db, engine, fs, http, init, logger, opt, optimist, path, procCmds, shutDown, usage; - logger = require('./new-logging'); + logger = require('./logging'); conf = require('./config'); @@ -36,7 +36,7 @@ Server procCmds = {}; /* - Let's prepare the optimist CLI + Let's prepare the optimist CLI optional arguments `[opt]`: */ diff --git a/run_server.sh b/run_engine.sh similarity index 100% rename from run_server.sh rename to run_engine.sh diff --git a/testing/files/.gitignore b/testing/files/.gitignore new file mode 100644 index 0000000..44f996c --- /dev/null +++ b/testing/files/.gitignore @@ -0,0 +1 @@ +test.log \ No newline at end of file diff --git a/testing/js/test.js b/testing/js/test.js new file mode 100644 index 0000000..28509b5 --- /dev/null +++ b/testing/js/test.js @@ -0,0 +1,93 @@ +// Generated by CoffeeScript 1.6.3 +(function() { + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3378, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:16:04.664Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3401, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:16:54.083Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3419, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:18:01.073Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3426, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:18:37.414Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3468, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:21:37.843Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 3477, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T17:22:08.602Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 6213, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T20:23:53.091Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 6236, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T20:24:45.295Z", + "v": 0 + }); + + ({ + "name": "webapi-eca", + "hostname": "dominic-HPdv6", + "pid": 6260, + "level": 30, + "msg": "TL | custom path test 1", + "time": "2014-02-18T20:25:27.587Z", + "v": 0 + }); + +}).call(this); diff --git a/testing/js/test_config.js b/testing/js/test_config.js index aafa0ae..e7e471f 100644 --- a/testing/js/test_config.js +++ b/testing/js/test_config.js @@ -6,9 +6,14 @@ path = require('path'); exports.setUp = function(cb) { + var log, logger; + logger = require(path.join('..', 'js-coffee', 'logging')); + log = logger.getLogger({ + nolog: true + }); _this.conf = require(path.join('..', 'js-coffee', 'config')); _this.conf({ - logType: 2 + logger: log }); return cb(); }; @@ -20,17 +25,25 @@ }; exports.testParameters = function(test) { - test.expect(4); + var logconf, prop, reqProp, _i, _len; + reqProp = ['mode', 'io-level', 'file-level', 'file-path']; + test.expect(4 + reqProp.length); test.ok(_this.conf.getHttpPort(), 'HTTP port does not exist!'); test.ok(_this.conf.getDBPort(), 'DB port does not exist!'); test.ok(_this.conf.getCryptoKey(), 'Crypto key does not exist!'); - test.ok(_this.conf.getSessionSecret(), 'Session Secret does not exist!'); + logconf = _this.conf.getLogConf(); + test.ok(logconf, 'Log config does not exist!'); + for (_i = 0, _len = reqProp.length; _i < _len; _i++) { + prop = reqProp[_i]; + test.ok(logconf[prop], "Log conf property " + prop + " does not exist!"); + } return test.done(); }; exports.testDifferentConfigFile = function(test) { test.expect(1); _this.conf({ + nolog: true, configPath: path.join('testing', 'files', 'jsonWrongConfig.json') }); test.ok(_this.conf.isReady(), 'Different path not loaded!'); @@ -40,6 +53,7 @@ exports.testNoConfigFile = function(test) { test.expect(1); _this.conf({ + nolog: true, configPath: 'wrongpath.file' }); test.strictEqual(_this.conf.isReady(), false, 'Wrong path still loaded!'); diff --git a/testing/js/test_logging.js b/testing/js/test_logging.js index 9e5d05e..074b9f6 100644 --- a/testing/js/test_logging.js +++ b/testing/js/test_logging.js @@ -1,5 +1,121 @@ // Generated by CoffeeScript 1.6.3 (function() { + var fs, getLog, path, + _this = this; + path = require('path'); + + fs = require('fs'); + + getLog = function(strPath, cb) { + var fWait, + _this = this; + fWait = function() { + var arrStr, fConvertRow, i, row, str, _i, _len; + str = fs.readFileSync(path.resolve(strPath), 'utf-8'); + arrStr = str.split("\n"); + fConvertRow = function(row) { + try { + return JSON.parse(row); + } catch (_error) {} + }; + for (i = _i = 0, _len = arrStr.length; _i < _len; i = ++_i) { + row = arrStr[i]; + arrStr[i] = fConvertRow(row); + } + return cb(arrStr.slice(0, arrStr.length - 1)); + }; + return setTimeout(fWait, 100); + }; + + exports.setUp = function(cb) { + _this.stdPath = path.resolve(__dirname, '..', 'logs', 'server.log'); + try { + fs.unlinkSync(_this.stdPath); + } catch (_error) {} + _this.logger = require(path.join('..', 'js-coffee', 'logging')); + return cb(); + }; + + exports.testCreate = function(test) { + var args, arrLogs, log; + test.expect(2); + arrLogs = ['TL | testInitIO - info', 'TL | testInitIO - warn', 'TL | testInitIO - error']; + args = {}; + args['io-level'] = 'error'; + log = _this.logger.getLogger(args); + log.info(arrLogs[0]); + log.warn(arrLogs[1]); + log.error(arrLogs[2]); + test.ok(fs.existsSync(_this.stdPath), 'Log file does not exist!'); + return getLog(_this.stdPath, function(arr) { + var allCorrect, i, o, _i, _len; + allCorrect = true; + for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) { + o = arr[i]; + if (o.msg === !arrLogs[i]) { + allCorrect = false; + } + } + test.ok(allCorrect, 'Log file does not contain the correct entries!'); + return test.done(); + }); + }; + + exports.testNoLog = function(test) { + var fWait, log; + test.expect(1); + log = _this.logger.getLogger({ + nolog: true + }); + log.info('TL | test 1'); + fWait = function() { + test.ok(!fs.existsSync(_this.stdPath), 'Log file does still exist!'); + return test.done(); + }; + return setTimeout(fWait, 100); + }; + + exports.testCustomPath = function(test) { + var args, fWait, log, strInfo, strPath; + test.expect(2); + strInfo = 'TL | custom path test 1'; + strPath = 'testing/test.log'; + args = {}; + args['file-path'] = strPath; + args['io-level'] = 'error'; + log = _this.logger.getLogger(args); + log.info(strInfo); + fWait = function() { + test.ok(fs.existsSync(strPath), 'Custom log file does not exist!'); + return getLog(strPath, function(arr) { + test.ok(arr[0].msg === strInfo, 'Custom log file not correct!'); + return test.done(); + }); + }; + return setTimeout(fWait, 100); + }; + + exports.testWrongPath = function(test) { + var args, fWait, log, strInfo, strPath; + test.expect(1); + strInfo = 'TL | custom path test 1'; + strPath = 'strange/path/to/test.log'; + args = {}; + args['file-path'] = strPath; + args['io-level'] = 'error'; + console.log('getting logger'); + log = _this.logger.getLogger(args); + console.log('logging'); + log.info(strInfo); + console.log('logged'); + fWait = function() { + console.log('waited'); + test.ok(true, 'Custom log file does not exist!'); + return test.done(); + }; + console.log('timing'); + return setTimeout(fWait, 100); + }; }).call(this); diff --git a/testing/js/test_persistence.js b/testing/js/test_persistence.js index ce82688..19d484c 100644 --- a/testing/js/test_persistence.js +++ b/testing/js/test_persistence.js @@ -1,20 +1,27 @@ // Generated by CoffeeScript 1.6.3 (function() { - var _this = this; + var _this = this, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; exports.setUp = function(cb) { + var logger; _this.path = require('path'); - _this.db = require(path.join('..', 'js-coffee', 'persistence')); - console.log('setup'); - console.log(_this.db); + logger = require(_this.path.join('..', 'js-coffee', 'logging')); + _this.log = logger.getLogger({ + nolog: true + }); + _this.db = require(_this.path.join('..', 'js-coffee', 'persistence')); _this.db({ - logType: 2 + logger: _this.log }); return cb(); }; exports.tearDown = function(cb) { - _this.db.shutDown(); + var _ref; + if ((_ref = _this.db) != null) { + _ref.shutDown(); + } return cb(); }; @@ -24,19 +31,8 @@ exports.Availability = { - setUp: function(cb) { - _this.path = require('path'); - _this.db = require(path.join('..', 'js-coffee', 'persistence')); - console.log('setup'); - console.log(_this.db); - _this.db({ - logType: 2 - }); - return cb(); - }, testRequire: function(test) { test.expect(1); - console.log('setup'); test.ok(_this.db, 'DB interface loaded'); return test.done(); }, @@ -50,6 +46,7 @@ testNoConfig: function(test) { test.expect(1); _this.db({ + logger: _this.log, configPath: 'nonexistingconf.file' }); return _this.db.isConnected(function(err) { @@ -60,6 +57,7 @@ testWrongConfig: function(test) { test.expect(1); _this.db({ + logger: _this.log, configPath: _this.path.join('testing', 'jsonWrongConfig.json') }); return _this.db.isConnected(function(err) { @@ -84,4 +82,721 @@ } }; + /* + # Test EVENT QUEUE + */ + + + exports.EventQueue = { + setUp: function(cb) { + _this.evt1 = { + eventid: '1', + event: 'mail' + }; + _this.evt2 = { + eventid: '2', + event: 'mail' + }; + _this.db.purgeEventQueue(); + return cb(); + }, + testEmptyPopping: function(test) { + test.expect(2); + return _this.db.popEvent(function(err, obj) { + test.ifError(err, 'Error during pop after purging!'); + test.strictEqual(obj, null, 'There was an event in the queue!?'); + return test.done(); + }); + }, + testEmptyPushing: function(test) { + test.expect(2); + _this.db.pushEvent(null); + return _this.db.popEvent(function(err, obj) { + test.ifError(err, 'Error during non-empty pushing!'); + test.strictEqual(obj, null, 'There was an event in the queue!?'); + return test.done(); + }); + }, + testNonEmptyPopping: function(test) { + test.expect(3); + _this.db.pushEvent(_this.evt1); + return _this.db.popEvent(function(err, obj) { + test.ifError(err, 'Error during non-empty popping!'); + test.notStrictEqual(obj, null, 'There was no event in the queue!'); + test.deepEqual(_this.evt1, obj, 'Wrong event in queue!'); + return test.done(); + }); + }, + testMultiplePushAndPops: function(test) { + var forkEnds, semaphore; + test.expect(6); + semaphore = 2; + forkEnds = function() { + if (--semaphore === 0) { + return test.done(); + } + }; + _this.db.pushEvent(_this.evt1); + _this.db.pushEvent(_this.evt2); + _this.db.popEvent(function(err, obj) { + test.ifError(err, 'Error during multiple push and pop!'); + test.notStrictEqual(obj, null, 'There was no event in the queue!'); + test.deepEqual(_this.evt1, obj, 'Wrong event in queue!'); + return forkEnds(); + }); + return _this.db.popEvent(function(err, obj) { + test.ifError(err, 'Error during multiple push and pop!'); + test.notStrictEqual(obj, null, 'There was no event in the queue!'); + test.deepEqual(_this.evt2, obj, 'Wrong event in queue!'); + return forkEnds(); + }); + } + }; + + /* + # Test ACTION INVOKER + */ + + + exports.ActionInvoker = { + testCreateAndRead: function(test) { + var action, id; + test.expect(3); + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + _this.db.storeActionInvoker(id, action); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) >= 0, 'Expected key not in action-invokers set'); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, action, 'Retrieved Action Invoker is not what we expected'); + return _this.db.getActionInvokers(function(err, obj) { + test.deepEqual(action, obj[id], 'Action Invoker ist not in result set'); + _this.db.deleteActionInvoker(id); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + var action, actionNew, id; + test.expect(2); + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + actionNew = 'unit-test action invoker new content'; + _this.db.storeActionInvoker(id, action); + _this.db.storeActionInvoker(id, actionNew); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, actionNew, 'Retrieved Action Invoker is not what we expected'); + return _this.db.getActionInvokers(function(err, obj) { + test.deepEqual(actionNew, obj[id], 'Action Invoker ist not in result set'); + _this.db.deleteActionInvoker(id); + return test.done(); + }); + }); + }, + testDelete: function(test) { + var action, id; + test.expect(2); + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + _this.db.storeActionInvoker(id, action); + _this.db.deleteActionInvoker(id); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, null, 'Action Invoker still exists'); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) < 0, 'Action Invoker key still exists in set'); + return test.done(); + }); + }); + }, + testFetchSeveral: function(test) { + var action1, action1name, action2, action2name, fCheckInvoker, semaphore; + test.expect(3); + semaphore = 2; + action1name = 'test-action-invoker_1'; + action2name = 'test-action-invoker_2'; + action1 = 'unit-test action invoker 1 content'; + action2 = 'unit-test action invoker 2 content'; + fCheckInvoker = function(modname, mod) { + var forkEnds, myTest; + myTest = test; + forkEnds = function() { + if (--semaphore === 0) { + return myTest.done(); + } + }; + return function(err, obj) { + myTest.strictEqual(mod, obj, "Invoker " + modname + " does not equal the expected one"); + _this.db.deleteActionInvoker(modname); + return forkEnds(); + }; + }; + _this.db.storeActionInvoker(action1name, action1); + _this.db.storeActionInvoker(action2name, action2); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, action1name) >= 0 && __indexOf.call(obj, action2name) >= 0, 'Not all action invoker Ids in set'); + _this.db.getActionInvoker(action1name, fCheckInvoker(action1name, action1)); + return _this.db.getActionInvoker(action2name, fCheckInvoker(action2name, action2)); + }); + } + }; + + /* + # Test ACTION INVOKER PARAMS + */ + + + exports.ActionInvokerParams = { + testCreateAndRead: function(test) { + var actionId, params, userId; + test.expect(2); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeActionParams(actionId, userId, params); + return _this.db.getActionParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = actionId + ':' + userId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in action-params set'); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, params, 'Retrieved action params is not what we expected'); + _this.db.deleteActionParams(actionId, userId); + return test.done(); + }); + }); + }, + testUpdate: function(test) { + var actionId, params, paramsNew, userId; + test.expect(1); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + paramsNew = 'shouldn\'t this be a new object?'; + _this.db.storeActionParams(actionId, userId, params); + _this.db.storeActionParams(actionId, userId, paramsNew); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, paramsNew, 'Retrieved action params is not what we expected'); + _this.db.deleteActionParams(actionId, userId); + return test.done(); + }); + }, + testDelete: function(test) { + var actionId, params, userId; + test.expect(2); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeActionParams(actionId, userId, params); + _this.db.deleteActionParams(actionId, userId); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, null, 'Action params still exists'); + return _this.db.getActionParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = actionId + ':' + userId, __indexOf.call(obj, _ref) < 0), 'Action Params key still exists in set'); + return test.done(); + }); + }); + } + }; + + /* + # Test EVENT POLLER + */ + + + exports.EventPoller = { + testCreateAndRead: function(test) { + var event, id; + test.expect(3); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + _this.db.storeEventPoller(id, event); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) >= 0, 'Expected key not in event-pollers set'); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, event, 'Retrieved Event Poller is not what we expected'); + return _this.db.getEventPollers(function(err, obj) { + test.deepEqual(event, obj[id], 'Event Poller ist not in result set'); + _this.db.deleteEventPoller(id); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + var event, eventNew, id; + test.expect(2); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + eventNew = 'unit-test event poller new content'; + _this.db.storeEventPoller(id, event); + _this.db.storeEventPoller(id, eventNew); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, eventNew, 'Retrieved Event Poller is not what we expected'); + return _this.db.getEventPollers(function(err, obj) { + test.deepEqual(eventNew, obj[id], 'Event Poller ist not in result set'); + _this.db.deleteEventPoller(id); + return test.done(); + }); + }); + }, + testDelete: function(test) { + var event, id; + test.expect(2); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + _this.db.storeEventPoller(id, event); + _this.db.deleteEventPoller(id); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, null, 'Event Poller still exists'); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) < 0, 'Event Poller key still exists in set'); + return test.done(); + }); + }); + }, + testFetchSeveral: function(test) { + var event1, event1name, event2, event2name, fCheckPoller, semaphore; + test.expect(3); + semaphore = 2; + event1name = 'test-event-poller_1'; + event2name = 'test-event-poller_2'; + event1 = 'unit-test event poller 1 content'; + event2 = 'unit-test event poller 2 content'; + fCheckPoller = function(modname, mod) { + var forkEnds, myTest; + myTest = test; + forkEnds = function() { + if (--semaphore === 0) { + return myTest.done(); + } + }; + return function(err, obj) { + myTest.strictEqual(mod, obj, "Invoker " + modname + " does not equal the expected one"); + _this.db.deleteEventPoller(modname); + return forkEnds(); + }; + }; + _this.db.storeEventPoller(event1name, event1); + _this.db.storeEventPoller(event2name, event2); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, event1name) >= 0 && __indexOf.call(obj, event2name) >= 0, 'Not all event poller Ids in set'); + _this.db.getEventPoller(event1name, fCheckPoller(event1name, event1)); + return _this.db.getEventPoller(event2name, fCheckPoller(event2name, event2)); + }); + } + }; + + /* + # Test EVENT POLLER PARAMS + */ + + + exports.EventPollerParams = { + testCreateAndRead: function(test) { + var eventId, params, userId; + test.expect(2); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeEventParams(eventId, userId, params); + return _this.db.getEventParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = eventId + ':' + userId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in event-params set'); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, params, 'Retrieved event params is not what we expected'); + _this.db.deleteEventParams(eventId, userId); + return test.done(); + }); + }); + }, + testUpdate: function(test) { + var eventId, params, paramsNew, userId; + test.expect(1); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + paramsNew = 'shouldn\'t this be a new object?'; + _this.db.storeEventParams(eventId, userId, params); + _this.db.storeEventParams(eventId, userId, paramsNew); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, paramsNew, 'Retrieved event params is not what we expected'); + _this.db.deleteEventParams(eventId, userId); + return test.done(); + }); + }, + testDelete: function(test) { + var eventId, params, userId; + test.expect(2); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeEventParams(eventId, userId, params); + _this.db.deleteEventParams(eventId, userId); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, null, 'Event params still exists'); + return _this.db.getEventParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = eventId + ':' + userId, __indexOf.call(obj, _ref) < 0), 'Event Params key still exists in set'); + return test.done(); + }); + }); + } + }; + + /* + # Test RULES + */ + + + exports.Rules = { + setUp: function(cb) { + _this.userId = 'tester-1'; + _this.ruleId = 'test-rule_1'; + _this.rule = { + "id": "rule_id", + "event": "custom", + "condition": { + "property": "yourValue" + }, + "actions": [] + }; + _this.ruleNew = { + "id": "rule_new", + "event": "custom", + "condition": { + "property": "yourValue" + }, + "actions": [] + }; + return cb(); + }, + tearDown: function(cb) { + _this.db.deleteRule(_this.ruleId); + return cb(); + }, + testCreateAndRead: function(test) { + test.expect(3); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + return _this.db.getRuleIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in rule key set'); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.deepEqual(JSON.parse(obj), _this.rule, 'Retrieved rule is not what we expected'); + return _this.db.getRules(function(err, obj) { + test.deepEqual(_this.rule, JSON.parse(obj[_this.ruleId]), 'Rule not in result set'); + _this.db.deleteRule(_this.ruleId); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + test.expect(1); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.ruleNew)); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.deepEqual(JSON.parse(obj), _this.ruleNew, 'Retrieved rule is not what we expected'); + _this.db.deleteRule(_this.ruleId); + return test.done(); + }); + }, + testDelete: function(test) { + test.expect(2); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.deleteRule(_this.ruleId); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.strictEqual(obj, null, 'Rule still exists'); + return _this.db.getRuleIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) < 0), 'Rule key still exists in set'); + return test.done(); + }); + }); + }, + testLink: function(test) { + test.expect(2); + _this.db.linkRule(_this.ruleId, _this.userId); + return _this.db.getRuleLinkedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) >= 0), "Rule not linked to user " + _this.userId); + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) >= 0), "User not linked to rule " + _this.ruleId); + return test.done(); + }); + }); + }, + testUnlink: function(test) { + test.expect(2); + _this.db.linkRule(_this.ruleId, _this.userId); + _this.db.unlinkRule(_this.ruleId, _this.userId); + return _this.db.getRuleLinkedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) < 0), "Rule still linked to user " + _this.userId); + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "User still linked to rule " + _this.ruleId); + return test.done(); + }); + }); + }, + testActivate: function(test) { + var usr; + test.expect(4); + usr = { + username: "tester-1", + password: "tester-1" + }; + _this.db.storeUser(usr); + _this.db.activateRule(_this.ruleId, _this.userId); + return _this.db.getRuleActivatedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) >= 0), "Rule not activated for user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) >= 0), "User not activated for rule " + _this.ruleId); + return _this.db.getAllActivatedRuleIdsPerUser(function(err, obj) { + var _ref2; + test.notStrictEqual(obj[_this.userId], void 0, "User " + _this.userId + " not in activated rules set"); + if (obj[_this.userId]) { + test.ok((_ref2 = _this.ruleId, __indexOf.call(obj[_this.userId], _ref2) >= 0), "Rule " + _this.ruleId + " not in activated rules set"); + } + return test.done(); + }); + }); + }); + }, + testDeactivate: function(test) { + test.expect(3); + _this.db.activateRule(_this.ruleId, _this.userId); + _this.db.deactivateRule(_this.ruleId, _this.userId); + return _this.db.getRuleActivatedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) < 0), "Rule still activated for user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "User still activated for rule " + _this.ruleId); + return _this.db.getAllActivatedRuleIdsPerUser(function(err, obj) { + var _ref2; + if (obj[_this.userId]) { + test.ok((_ref2 = _this.ruleId, __indexOf.call(obj[_this.userId], _ref2) < 0), "Rule " + _this.ruleId + " still in activated rules set"); + } else { + test.ok(true, "We are fine since there are no entries for this user anymore"); + } + return test.done(); + }); + }); + }); + }, + testUnlinkAndDeactivateAfterDeletion: function(test) { + var fWaitForDeletion, fWaitForTest; + test.expect(2); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.linkRule(_this.ruleId, _this.userId); + _this.db.activateRule(_this.ruleId, _this.userId); + fWaitForTest = function() { + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) < 0), "Rule " + _this.ruleId + " still linked to user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "Rule " + _this.ruleId + " still activated for user " + _this.userId); + return test.done(); + }); + }); + }; + fWaitForDeletion = function() { + _this.db.deleteRule(_this.ruleId); + return setTimeout(fWaitForTest, 100); + }; + return setTimeout(fWaitForDeletion, 100); + } + }; + + /* + # Test USER + */ + + + exports.User = { + setUp: function(cb) { + _this.oUser = { + username: "tester-1", + password: "password" + }; + return cb(); + }, + tearDown: function(cb) { + _this.db.deleteUser(_this.oUser.username); + return cb(); + }, + testCreateInvalid: function(test) { + var oUserInvOne, oUserInvTwo; + test.expect(4); + oUserInvOne = { + username: "tester-1-invalid" + }; + oUserInvTwo = { + password: "password" + }; + _this.db.storeUser(oUserInvOne); + _this.db.storeUser(oUserInvTwo); + return _this.db.getUser(oUserInvOne.username, function(err, obj) { + test.strictEqual(obj, null, 'User One was stored!?'); + return _this.db.getUser(oUserInvTwo.username, function(err, obj) { + test.strictEqual(obj, null, 'User Two was stored!?'); + return _this.db.getUserIds(function(err, obj) { + var _ref, _ref1; + test.ok((_ref = oUserInvOne.username, __indexOf.call(obj, _ref) < 0), 'User key was stored!?'); + test.ok((_ref1 = oUserInvTwo.username, __indexOf.call(obj, _ref1) < 0), 'User key was stored!?'); + return test.done(); + }); + }); + }); + }, + testDelete: function(test) { + test.expect(2); + _this.db.storeUser(_this.oUser); + return _this.db.getUser(_this.oUser.username, function(err, obj) { + test.deepEqual(obj, _this.oUser, "User " + _this.oUser.username + " is not what we expect!"); + return _this.db.getUserIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.oUser.username, __indexOf.call(obj, _ref) >= 0), 'User key was not stored!?'); + return test.done(); + }); + }); + }, + testUpdate: function(test) { + var oUserOne; + test.expect(2); + oUserOne = { + username: "tester-1-update", + password: "password" + }; + _this.db.storeUser(oUserOne); + oUserOne.password = "password-update"; + _this.db.storeUser(oUserOne); + return _this.db.getUser(oUserOne.username, function(err, obj) { + test.deepEqual(obj, oUserOne, "User " + _this.oUser.username + " is not what we expect!"); + return _this.db.getUserIds(function(err, obj) { + var _ref; + test.ok((_ref = oUserOne.username, __indexOf.call(obj, _ref) >= 0), 'User key was not stored!?'); + _this.db.deleteUser(oUserOne.username); + return test.done(); + }); + }); + }, + testDelete: function(test) { + var fWaitForDeletion; + test.expect(2); + fWaitForDeletion = function() { + return _this.db.getUserIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.oUser.username, __indexOf.call(obj, _ref) < 0), 'User key still in set!'); + return _this.db.getUser(_this.oUser.username, function(err, obj) { + test.strictEqual(obj, null, 'User key still exists!'); + return test.done(); + }); + }); + }; + _this.db.storeUser(_this.oUser); + _this.db.deleteUser(_this.oUser.username); + return setTimeout(fWaitForDeletion, 100); + }, + testDeleteLinks: function(test) { + var fWaitForDeletion, fWaitForPersistence; + test.expect(4); + fWaitForPersistence = function() { + _this.db.deleteUser(_this.oUser.username); + return setTimeout(fWaitForDeletion, 200); + }; + fWaitForDeletion = function() { + return _this.db.getRoleUsers('tester', function(err, obj) { + var _ref; + test.ok((_ref = _this.oUser.username, __indexOf.call(obj, _ref) < 0), 'User key still in role tester!'); + return _this.db.getUserRoles(_this.oUser.username, function(err, obj) { + test.ok(obj.length === 0, 'User still associated to roles!'); + return _this.db.getUserLinkedRules(_this.oUser.username, function(err, obj) { + test.ok(obj.length === 0, 'User still associated to rules!'); + return _this.db.getUserActivatedRules(_this.oUser.username, function(err, obj) { + test.ok(obj.length === 0, 'User still associated to activated rules!'); + return test.done(); + }); + }); + }); + }); + }; + _this.db.storeUser(_this.oUser); + _this.db.linkRule('rule-1', _this.oUser.username); + _this.db.linkRule('rule-2', _this.oUser.username); + _this.db.linkRule('rule-3', _this.oUser.username); + _this.db.activateRule('rule-1', _this.oUser.username); + _this.db.storeUserRole(_this.oUser.username, 'tester'); + return setTimeout(fWaitForPersistence, 100); + }, + testLogin: function(test) { + test.expect(3); + _this.db.storeUser(_this.oUser); + return _this.db.loginUser(_this.oUser.username, _this.oUser.password, function(err, obj) { + test.deepEqual(obj, _this.oUser, 'User not logged in!'); + return _this.db.loginUser('dummyname', _this.oUser.password, function(err, obj) { + test.strictEqual(obj, null, 'User logged in?!'); + return _this.db.loginUser(_this.oUser.username, 'wrongpass', function(err, obj) { + test.strictEqual(obj, null, 'User logged in?!'); + return test.done(); + }); + }); + }); + } + }; + + /* + # Test ROLES + */ + + + exports.Roles = { + setUp: function(cb) { + _this.db({ + logger: _this.log + }); + _this.oUser = { + username: "tester-1", + password: "password" + }; + return cb(); + }, + tearDown: function(cb) { + _this.db.deleteUser(_this.oUser.username); + return cb(); + }, + testStore: function(test) { + test.expect(2); + _this.db.storeUser(_this.oUser); + _this.db.storeUserRole(_this.oUser.username, 'tester'); + return _this.db.getUserRoles(_this.oUser.username, function(err, obj) { + test.ok(__indexOf.call(obj, 'tester') >= 0, 'User role tester not stored!'); + return _this.db.getRoleUsers('tester', function(err, obj) { + var _ref; + test.ok((_ref = _this.oUser.username, __indexOf.call(obj, _ref) >= 0), "User " + _this.oUser.username + " not stored in role tester!"); + return test.done(); + }); + }); + }, + testDelete: function(test) { + test.expect(2); + _this.db.storeUser(_this.oUser); + _this.db.storeUserRole(_this.oUser.username, 'tester'); + _this.db.removeUserRole(_this.oUser.username, 'tester'); + return _this.db.getUserRoles(_this.oUser.username, function(err, obj) { + test.ok(__indexOf.call(obj, 'tester') < 0, 'User role tester not stored!'); + return _this.db.getRoleUsers('tester', function(err, obj) { + var _ref; + test.ok((_ref = _this.oUser.username, __indexOf.call(obj, _ref) < 0), "User " + _this.oUser.username + " not stored in role tester!"); + return test.done(); + }); + }); + } + }; + }).call(this); diff --git a/testing/test_config.coffee b/testing/test_config.coffee index 4bebcb2..e1da583 100644 --- a/testing/test_config.coffee +++ b/testing/test_config.coffee @@ -1,9 +1,12 @@ path = require 'path' exports.setUp = ( cb ) => + logger = require path.join '..', 'js-coffee', 'logging' + log = logger.getLogger + nolog: true @conf = require path.join '..', 'js-coffee', 'config' @conf - nolog: true + logger: log cb() exports.testRequire = ( test ) => diff --git a/testing/test_logging.coffee b/testing/test_logging.coffee index d092080..5ed74e6 100644 --- a/testing/test_logging.coffee +++ b/testing/test_logging.coffee @@ -1,68 +1,99 @@ +path = require 'path' +fs = require 'fs' + +getLog = ( strPath, cb ) -> + fWait = => + # cb fs.readFileSync path, 'utf-8' + str = fs.readFileSync path.resolve( strPath ), 'utf-8' + arrStr = str.split "\n" + fConvertRow = ( row ) -> + try + JSON.parse row + arrStr[i] = fConvertRow row for row, i in arrStr + cb arrStr.slice 0, arrStr.length - 1 + setTimeout fWait, 100 exports.setUp = ( cb ) => - @fs = require 'fs' - @path = require 'path' - @stdPath = @path.resolve __dirname, '..', 'logs', 'server.log' + @stdPath = path.resolve __dirname, '..', 'logs', 'server.log' try - @fs.unlinkSync @stdPath - catch e - @log = require @path.join '..', 'js-coffee', 'new-logging' + fs.unlinkSync @stdPath + @logger = require path.join '..', 'js-coffee', 'logging' cb() -exports.tearDown = ( cb ) => - cb() +# exports.tearDown = ( cb ) => +# cb() -exports.testInitIO = ( test ) => - test.expect 1 - conf = - logType: 0 - @log.configure conf - @log.info 'TL', 'testInitIO - info' - @log.warn 'TL', 'testInitIO - warn' - @log.error 'TL', 'testInitIO - error' - test.ok !@fs.existsSync @stdPath - test.done() +exports.testCreate = ( test ) => + test.expect 2 + arrLogs = [ + 'TL | testInitIO - info' + 'TL | testInitIO - warn' + 'TL | testInitIO - error' + ] + args = {} + args[ 'io-level' ] = 'error' + log = @logger.getLogger args + log.info arrLogs[0] + log.warn arrLogs[1] + log.error arrLogs[2] + test.ok fs.existsSync( @stdPath ), 'Log file does not exist!' + getLog @stdPath, ( arr ) -> + allCorrect = true + for o,i in arr + if o.msg is not arrLogs[i] + allCorrect = false + test.ok allCorrect, 'Log file does not contain the correct entries!' + test.done() -exports.testInitFile = ( test ) => +exports.testNoLog = ( test ) => test.expect 1 - conf = - logType: 1 - @log.configure conf - @log.info 'UT', 'test 1' + log = @logger.getLogger + nolog: true + log.info 'TL | test 1' fWait = () => - @log.info 'UT', 'test 2' - test.ok @fs.existsSync @stdPath + test.ok !fs.existsSync( @stdPath ), 'Log file does still exist!' test.done() setTimeout fWait, 100 -# exports.testInitSilent = ( test ) => -# test.expect 1 +exports.testCustomPath = ( test ) => + test.expect 2 -# conf = -# logType: 2 -# @log.configure conf -# @log.info 'test 3' + strInfo = 'TL | custom path test 1' + strPath = 'testing/files/test.log' + args = {} + args[ 'file-path' ] = strPath + args[ 'io-level' ] = 'error' -# test.ok true, 'yay' -# test.done() + log = @logger.getLogger args + log.info strInfo -# exports.testInitPath = ( test ) => -# test.expect 1 + fWait = () => + test.ok fs.existsSync( strPath ), 'Custom log file does not exist!' + getLog strPath, ( arr ) -> + test.ok arr[0].msg is strInfo, 'Custom log file not correct!' + try + fs.unlinkSync strPath + test.done() -# conf = -# logType: 1 -# logPath: 'testing/log-initPath.log' -# @log.configure conf -# @log.info 'test 3' + setTimeout fWait, 100 -# test.ok true, 'yay' -# test.done() +exports.testWrongPath = ( test ) => + test.expect 1 -# exports.testPrint = ( test ) => -# test.expect 1 -# test.ok true, 'yay' -# @log.info 'test 3' -# test.done() \ No newline at end of file + strInfo = 'TL | custom path test 1' + strPath = 'strange/path/to/test.log' + args = {} + args[ 'file-path' ] = strPath + args[ 'io-level' ] = 'error' + log = @logger.getLogger args + log.info strInfo + + fWait = () => + test.ok !fs.existsSync( path.resolve ( strPath ) ), 'Custom log file does exist!?' + test.done() + + setTimeout fWait, 1000 + diff --git a/testing/test_persistence.coffee b/testing/test_persistence.coffee index f54cf42..9cb8ed3 100644 --- a/testing/test_persistence.coffee +++ b/testing/test_persistence.coffee @@ -1,12 +1,16 @@ exports.setUp = ( cb ) => @path = require 'path' + logger = require @path.join '..', 'js-coffee', 'logging' + @log = logger.getLogger + nolog: true @db = require @path.join '..', 'js-coffee', 'persistence' - @db logType: 2 + @db + logger: @log cb() exports.tearDown = ( cb ) => - @db.shutDown() + @db?.shutDown() cb() @@ -31,6 +35,7 @@ exports.Availability = test.expect 1 @db + logger: @log configPath: 'nonexistingconf.file' @db.isConnected ( err ) -> test.ok err, 'Still connected!?' @@ -39,7 +44,9 @@ exports.Availability = testWrongConfig: ( test ) => test.expect 1 - @db { configPath: @path.join 'testing', 'jsonWrongConfig.json' } + @db + logger: @log + configPath: @path.join 'testing', 'jsonWrongConfig.json' @db.isConnected ( err ) -> test.ok err, 'Still connected!?' test.done() @@ -836,7 +843,8 @@ exports.User = ### exports.Roles = setUp: ( cb ) => - @db logType: 1 + @db + logger: @log @oUser = username: "tester-1" password: "password"