diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2018-07-05 18:42:53 +0200 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2018-07-10 17:12:30 +0200 |
commit | 90e56dd22eba15bf71e3e0042080c2213ae39920 (patch) | |
tree | 889d89bd0f751832eb6e5fc9211d17a5221c74cc /conf.d/controller/lua.d/aft.lua | |
parent | 179196fc65315bf9e8cade8137e9786e2e0b0fed (diff) |
Files reorganization and rename project to AFT
Change-Id: I2e4adc51bdf5fcb9001c68fb4fc71f4987da47e0
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
Diffstat (limited to 'conf.d/controller/lua.d/aft.lua')
-rw-r--r-- | conf.d/controller/lua.d/aft.lua | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/conf.d/controller/lua.d/aft.lua b/conf.d/controller/lua.d/aft.lua new file mode 100644 index 0000000..5032929 --- /dev/null +++ b/conf.d/controller/lua.d/aft.lua @@ -0,0 +1,378 @@ +--[[ + Copyright (C) 2018 "IoT.bzh" + Author Romain Forlot <romain.forlot@iot.bzh> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + NOTE: strict mode: every global variables should be prefixed by '_' +--]] + +local lu = require('luaunit') +lu.LuaUnit:setOutputType('JUNIT') +lu.LuaUnit.fname = "var/jUnitResults.xml" + +-- Use our own print function to redirect it to a file the standard output +_standard_print = print +print = function(...) + io.write(... .. '\n') + _standard_print(...) +end + +_AFT = { + exit = {0, code}, + context = _ctx, + tests_list = {}, + event_history = false, + monitored_events = {}, +} + +function _AFT.enableEventHistory() + _AFT.event_history = true +end + +function _AFT.setJunitFile(filePath) + lu.LuaUnit.fname = filePath +end + +function _AFT.setOutputFile(filePath) + local file = assert(io.open(filePath, "w+")) + io.output(file) +end + +function _AFT.exitAtEnd(code) + _AFT.exit = {1, code} +end + +--[[ + Events listener and assertion functions to test correctness of received + event data. + + Check are in 2 times. First you need to register the event that you want to + monitor then you test that it has been correctly received. + + Notice that there is a difference between log and event. Logs are daemon + messages normally handled by the host log system (journald, syslog...) and + events are generated by the apis to communicate and send informations to the + subscribed listeners. +]] + +function _AFT.addEventToMonitor(eventName, callback) + _AFT.monitored_events[eventName] = { cb = callback, receivedCount = 0 } +end + +function _AFT.incrementCount(dict) + if dict.receivedCount then + dict.receivedCount = dict.receivedCount + 1 + else + dict.receivedCount = 1 + end +end + +function _AFT.registerData(dict, eventData) + if dict.data and type(dict.data) == 'table' then + if _AFT.event_history == true then + table.insert(dict.data, eventData, 1) + else + dict.data[1] = eventData + end + else + dict.data = {} + table.insert(dict.data, eventData) + end +end + +function _AFT.requestDaemonEventHandler(eventObj) + local eventName = eventObj.data.message + local log = _AFT.monitored_events[eventName] + local api = nil + + if eventObj.daemon then + api = eventObj.daemon.api + elseif eventObj.request then + api = eventObj.request.api + end + + if log and log.api == api and log.type == eventObj.data.type then + _AFT.incrementCount(_AFT.monitored_events[eventName]) + _AFT.registerData(_AFT.monitored_events[eventName], eventObj.data) + end + +end + +function _AFT.bindingEventHandler(eventObj) + local eventName = eventObj.event.name + local eventListeners = eventObj.data.result + + -- Remove from event to hold the bare event data and be able to assert it + eventObj.data.result = nil + + if type(_AFT.monitored_events[eventName]) == 'table' then + _AFT.monitored_events[eventName].eventListeners = eventListeners + + _AFT.incrementCount(_AFT.monitored_events[eventName]) + _AFT.registerData(_AFT.monitored_events[eventName], eventObj.data) + end +end + +function _evt_catcher_ (source, action, eventObj) + if eventObj.type == "event" then + _AFT.bindingEventHandler(eventObj) + elseif eventObj.type == "daemon" or eventObj.type == "request" then + _AFT.requestDaemonEventHandler(eventObj) + end +end + +--[[ + Assert and test functions about the event part. +]] + +function _AFT.assertEvtNotReceived(eventName) + local count = 0 + if _AFT.monitored_events[eventName].receivedCount then + count = _AFT.monitored_events[eventName].receivedCount + end + + _AFT.assertIsTrue(count == 0, "Event '".. eventName .."' received but it shouldn't") + + if _AFT.monitored_events[eventName].cb then + local data_n = #_AFT.monitored_events[eventName].data + _AFT.monitored_events[eventName].cb(eventName, _AFT.monitored_events[eventName].data[data_n]) + end +end + +function _AFT.assertEvtReceived(eventName) + local count = 0 + if _AFT.monitored_events[eventName].receivedCount then + count = _AFT.monitored_events[eventName].receivedCount + end + + _AFT.assertIsTrue(count > 0, "No event '".. eventName .."' received") + + if _AFT.monitored_events[eventName].cb then + local data_n = #_AFT.monitored_events[eventName].data + _AFT.monitored_events[eventName].cb(eventName, _AFT.monitored_events[eventName].data[data_n]) + end +end + +function _AFT.testEvtNotReceived(testName, eventName, timeout) + table.insert(_AFT.tests_list, {testName, function() + if timeout then sleep(timeout) end + _AFT.assertEvtNotReceived(eventName) + end}) +end + +function _AFT.testEvtReceived(testName, eventName, timeout) + table.insert(_AFT.tests_list, {testName, function() + if timeout then sleep(timeout) end + _AFT.assertEvtReceived(eventName) + end}) +end + +--[[ + Assert function meant to tests API Verbs calls +]] + +local function assertVerbCallParameters(src, api, verb, args) + _AFT.assertIsUserdata(src, "Source must be an opaque userdata pointer which will be passed to the binder") + _AFT.assertIsString(api, "API and Verb must be string") + _AFT.assertIsString(verb, "API and Verb must be string") + _AFT.assertIsTable(args, "Arguments must use LUA Table (event empty)") +end + +function _AFT.assertVerb(api, verb, args, cb) + assertVerbCallParameters(_AFT.context, api, verb, args) + local err,responseJ = AFB:servsync(_AFT.context, api, verb, args) + _AFT.assertIsFalse(err) + _AFT.assertStrContains(responseJ.request.status, "success", nil, nil, "Call for API/Verb failed.") + + local tcb = type(cb) + if cb then + if tcb == 'function' then + cb(responseJ) + elseif tcb == 'table' then + _AFT.assertEquals(responseJ.response, cb) + elseif tcb == 'string' or tcb == 'number' then + _AFT.assertEquals(responseJ.response, cb) + else + _AFT.assertIsTrue(false, "Wrong parameter passed to assertion. Last parameter should be function, table representing a JSON object or nil") + end + end +end + +function _AFT.assertVerbError(api, verb, args, cb) + assertVerbCallParameters(_AFT.context, api, verb, args) + local err,responseJ = AFB:servsync(_AFT.context, api, verb, args) + _AFT.assertIsTrue(err) + _AFT.assertNotStrContains(responseJ.request.status, "success", nil, nil, "Call for API/Verb succeed but it shouldn't.") + + local tcb = type(cb) + if cb then + if tcb == 'function' then + cb(responseJ) + elseif tcb == 'string' then + _AFT.assertNotEquals(responseJ.request.info, cb) + else + _AFT.assertIsFalse(false, "Wrong parameter passed to assertion. Last parameter should be a string representing the failure informations") + end + end +end + +function _AFT.testVerb(testName, api, verb, args, cb) + table.insert(_AFT.tests_list, {testName, function() + _AFT.assertVerb(api, verb, args, cb) + end}) +end + +function _AFT.testVerbError(testName, api, verb, args, cb) + table.insert(_AFT.tests_list, {testName, function() + _AFT.assertVerbError(api, verb, args, cb) + end}) +end + +function _AFT.testCustom(testName, testFunction) + table.insert(_AFT.tests_list, {testName, function() + testFunction() + end}) +end + +--[[ + Make all assertions accessible using _AFT and declare some convenients + aliases. +]] + +local luaunit_list_of_assert = { + -- official function name from luaunit test framework + + -- general assertions + 'assertEquals', + 'assertItemsEquals', + 'assertNotEquals', + 'assertAlmostEquals', + 'assertNotAlmostEquals', + 'assertEvalToTrue', + 'assertEvalToFalse', + 'assertStrContains', + 'assertStrIContains', + 'assertNotStrContains', + 'assertNotStrIContains', + 'assertStrMatches', + 'assertError', + 'assertErrorMsgEquals', + 'assertErrorMsgContains', + 'assertErrorMsgMatches', + 'assertIs', + 'assertNotIs', + + -- type assertions: assertIsXXX -> assert_is_xxx + 'assertIsNumber', + 'assertIsString', + 'assertIsTable', + 'assertIsBoolean', + 'assertIsNil', + 'assertIsTrue', + 'assertIsFalse', + 'assertIsNaN', + 'assertIsInf', + 'assertIsPlusInf', + 'assertIsMinusInf', + 'assertIsPlusZero', + 'assertIsMinusZero', + 'assertIsFunction', + 'assertIsThread', + 'assertIsUserdata', + + -- type assertions: assertNotIsXXX -> assert_not_is_xxx + 'assertNotIsNumber', + 'assertNotIsString', + 'assertNotIsTable', + 'assertNotIsBoolean', + 'assertNotIsNil', + 'assertNotIsTrue', + 'assertNotIsFalse', + 'assertNotIsNaN', + 'assertNotIsInf', + 'assertNotIsPlusInf', + 'assertNotIsMinusInf', + 'assertNotIsPlusZero', + 'assertNotIsMinusZero', + 'assertNotIsFunction', + 'assertNotIsThread', + 'assertNotIsUserdata', +} + +local luaunit_list_of_functions = { + "setOutputType", +} + +local _AFT_list_of_funcs = { + -- AF Binder generic assertions + { 'addEventToMonitor', 'resetEventReceivedCount' }, + { 'assertVerb', 'assertVerbStatusSuccess' }, + { 'assertVerb', 'assertVerbResponseEquals' }, + { 'assertVerb', 'assertVerbCb' }, + { 'assertVerbError', 'assertVerbStatusError' }, + { 'assertVerbError', 'assertVerbResponseEqualsError' }, + { 'assertVerbError', 'assertVerbCbError' }, + { 'testVerb', 'testVerbStatusSuccess' }, + { 'testVerb', 'testVerbResponseEquals' }, + { 'testVerb', 'testVerbCb' }, + { 'testVerbError', 'testVerbStatusError' }, + { 'testVerbError', 'testVerbResponseEqualsError' }, + { 'testVerbError', 'testVerbCbError' }, +} + +-- Import all luaunit assertion function to _AFT object +for _, v in pairs( luaunit_list_of_assert ) do + local funcname = v + _AFT[funcname] = lu[funcname] +end + +-- Import specific luaunit configuration functions to _AFT object +for _, v in pairs( luaunit_list_of_functions ) do + local funcname = v + _AFT[funcname] = lu.LuaUnit[funcname] +end + +-- Create all aliases in _AFT +for _, v in pairs( _AFT_list_of_funcs ) do + local funcname, alias = v[1], v[2] + _AFT[alias] = _AFT[funcname] +end + +function _launch_test(context, args) + _AFT.context = context + + _AFT.setOutputFile("var/test_results.log") + AFB:servsync(_AFT.context, "monitor", "set", { verbosity = "debug" }) + AFB:servsync(_AFT.context, "monitor", "trace", { add = { api = args.trace, request = "vverbose", event = "push_after" }}) + if args.files and type(args.files) == 'table' then + for _,f in pairs(args.files) do + dofile('var/'..f) + end + elseif type(args.files) == 'string' then + dofile('var/'..args.files) + end + + AFB:success(_AFT.context, { info = "Launching tests"}) + lu.LuaUnit:runSuiteByInstances(_AFT.tests_list) + + local success ="Success : "..tostring(lu.LuaUnit.result.passedCount) + local failures="Failures : "..tostring(lu.LuaUnit.result.testCount-lu.LuaUnit.result.passedCount) + + local evtHandle = AFB:evtmake(_AFT.context, 'results') + AFB:subscribe(_AFT.context,evtHandle) + AFB:evtpush(_AFT.context,evtHandle,{info = success.." "..failures}) + + if _AFT.exit[1] == 1 then os.exit(_AFT.exit[2]) end +end |