diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2018-07-18 19:50:57 +0200 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2018-07-21 10:05:16 +0000 |
commit | 3f00d0fea4b8db29ef8268f2189704a3ea8e3360 (patch) | |
tree | 03d2d6abb708a8830682250653c43d79d24100cf | |
parent | 99043faef2d12b70dc27e2c816738a9ba2fff659 (diff) |
Fix: events callback aren't correctly registered
They were stored in the mapis sections instead of the events
one.
Clean and handle raw events as well. Before that it could
only process events coming from monitoring api. Now it could
receive the event directly.
Make sure that the event handle is valid before sends the
request response. This prevent to subcribe or push an event
while the event handle hasn't been correctly created. This
could happens if the testVerb hasn't not been called from a
session. In that case, the response will just be that tests
has been launched.
Format.
Change-Id: I0aa522939162684f91dd426cc14919bb0ec3f69e
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
-rw-r--r-- | conf.d/controller/lua.d/aft.lua | 189 | ||||
-rw-r--r-- | src/aft.c | 10 | ||||
-rw-r--r-- | src/mapis.c | 24 |
3 files changed, 165 insertions, 58 deletions
diff --git a/conf.d/controller/lua.d/aft.lua b/conf.d/controller/lua.d/aft.lua index 918deb1..b9061fb 100644 --- a/conf.d/controller/lua.d/aft.lua +++ b/conf.d/controller/lua.d/aft.lua @@ -22,6 +22,14 @@ local lu = require('luaunit') lu.LuaUnit:setOutputType('JUNIT') lu.LuaUnit.fname = "xUnitResults.xml" +local function table_size(t) + local size = 0 + for _,_ in pairs(t) do + size = size + 1 + end + return size +end + _AFT = { exit = {0, code}, context = _ctx, @@ -98,71 +106,151 @@ function _AFT.registerData(dict, 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 +function _AFT.bindingEventHandler(eventObj, uid) + local eventName = nil + local eventListeners = nil + local data = nil + + if uid then + eventName = uid + data = eventObj + elseif eventObj.event.name then + eventName = eventObj.event.name + eventListeners = eventObj.data.result + -- Remove from event to hold the bare event data and be able to assert it + eventObj.data.result = nil + data = eventObj.data end - if log and log.api == api and log.type == eventObj.data.type then + if type(_AFT.monitored_events[eventName]) == 'table' then + if eventListeners then + _AFT.monitored_events[eventName].eventListeners = eventListeners + end + _AFT.incrementCount(_AFT.monitored_events[eventName]) - _AFT.registerData(_AFT.monitored_events[eventName], eventObj.data) + _AFT.registerData(_AFT.monitored_events[eventName], data) end +end +function _evt_catcher_(source, action, eventObj) + local uid = AFB:getuid(source) + if uid == "monitor/trace" then + if eventObj.type == "event" then + _AFT.bindingEventHandler(eventObj) + end + else + _AFT.bindingEventHandler(eventObj, uid) + end end -function _AFT.bindingEventHandler(eventObj) - local eventName = eventObj.event.name - local eventListeners = eventObj.data.result +function _AFT.lockWait(eventName, timeout) + if type(eventName) ~= "string" then + print("Error: wrong argument given to wait an event. 1st argument should be a string") + return 0 + end - -- Remove from event to hold the bare event data and be able to assert it - eventObj.data.result = nil + local count = 0 + if _AFT.monitored_events[eventName].receivedCount and timeout then + count = _AFT.monitored_events[eventName].receivedCount + end - if type(_AFT.monitored_events[eventName]) == 'table' then - _AFT.monitored_events[eventName].eventListeners = eventListeners + while timeout > 0 do + timeout = AFB:lockwait(_AFT.context, timeout) + AFB:lockwait(_AFT.context, 0) --without it _evt_catcher_ cannot received event - _AFT.incrementCount(_AFT.monitored_events[eventName]) - _AFT.registerData(_AFT.monitored_events[eventName], eventObj.data) + if _AFT.monitored_events[eventName].receivedCount == count + 1 then + return 1 + end end + return 0 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) +function _AFT.lockWaitGroup(eventGroup, timeout) + if type(eventGroup) ~= "table" then + print("Error: wrong argument given to wait a group of events. 1st argument should be a table") + return 0 + end + local eventGroupCpy = {table.unpack(eventGroup)} + + while timeout > 0 do + timeout = AFB:lockwait(_AFT.context, timeout) + AFB:lockwait(_AFT.context, 0) --without it _evt_catcher_ cannot received event + + for key,event in pairs(eventGroupCpy) do + if _AFT.monitored_events[event.name].receivedCount == event.receivedCount + 1 then + eventGroupCpy[key] = nil + end + end + if table_size(eventGroupCpy) == 0 then return 1 end end + return 0 end --[[ Assert and test functions about the event part. ]] -function _AFT.lockwait(eventName, timeout) - local count = 0 - if _AFT.monitored_events[eventName].receivedCount then - if timeout then - count = _AFT.monitored_events[eventName].receivedCount - end +function _AFT.assertEvtGrpNotReceived(eventGroup, timeout) + local count = 0 + local eventName = "" + for _,event in pairs(eventGroup) do + eventGroup[key] = {name = event, receivedCount = _AFT.monitored_events[event].receivedCount} end - while timeout > 0 do - timeout = AFB:lockwait(_AFT.context, timeout) - AFB:lockwait(_AFT.context, 0) --without it ev catcher cannot received event - if _AFT.monitored_events[eventName].receivedCount == count + 1 then - return 1 - end - end - return 0 + if timeout then + count = _AFT.lockWaitGroup(eventGroup, timeout) + else + for _,v in pairs(eventGroup) do + count = count + v.count + end + end + + for _,event in pairs(eventGroup) do + eventName = eventName .. " " .. event.name + end + _AFT.assertIsTrue(count == 0, "One of the following events has been received: '".. eventName .."' but it shouldn't") + + for _,event in pairs(eventGroup) do + if _AFT.monitored_events[event.name].cb then + local data_n = table_size(_AFT.monitored_events[event.name].data) + _AFT.monitored_events[event.name].cb(v.name, _AFT.monitored_events[event.name].data[data_n]) + end + end +end + +function _AFT.assertEvtGrpReceived(eventGroup, timeout) + local count = 0 + local eventName = "" + for key,event in pairs(eventGroup) do + eventGroup[key] = {name = event, receivedCount = _AFT.monitored_events[event].receivedCount} + end + + if timeout then + count = _AFT.lockWaitGroup(eventGroup, timeout) + else + for _,v in pairs(eventGroup) do + count = count + v.receivedCount + end + end + + for _,event in pairs(eventGroup) do + eventName = eventName .. " " .. event.name + end + _AFT.assertIsTrue(count >= table_size(eventGroup), "None or one of the following events: '".. eventName .."' has not been received") + + for _,event in pairs(eventGroup) do + if _AFT.monitored_events[event.name].cb then + local data_n = table_size(_AFT.monitored_events[event.name].data) + _AFT.monitored_events[event.name].cb(v.name, _AFT.monitored_events[event.name].data[data_n]) + end + end end function _AFT.assertEvtNotReceived(eventName, timeout) - local count = _AFT.lockwait(eventName, timeout) + local count = _AFT.monitored_events[eventName].receivedCount + if timeout then + count = _AFT.lockWait(eventName, timeout) + end _AFT.assertIsTrue(count == 0, "Event '".. eventName .."' received but it shouldn't") @@ -173,7 +261,10 @@ function _AFT.assertEvtNotReceived(eventName, timeout) end function _AFT.assertEvtReceived(eventName, timeout) - local count = _AFT.lockwait(eventName, timeout) + local count = _AFT.monitored_events[eventName].receivedCount + if timeout then + count = _AFT.lockWait(eventName, timeout) + end _AFT.assertIsTrue(count > 0, "No event '".. eventName .."' received") @@ -460,8 +551,10 @@ local function call_tests() 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 type(evtHandle) == "userdata" then + AFB:subscribe(_AFT.context,evtHandle) + AFB:evtpush(_AFT.context,evtHandle,{info = success.." "..failures}) + end end function _launch_test(context, args) @@ -470,7 +563,15 @@ function _launch_test(context, args) -- Prepare the tests execution configuring the monitoring and loading -- lua test files to execute in the Framework. AFB:servsync(_AFT.context, "monitor", "set", { verbosity = "debug" }) - AFB:servsync(_AFT.context, "monitor", "trace", { add = { api = args.trace, request = "vverbose", event = "push_after" }}) + if type(args.trace) == "string" then + AFB:servsync(_AFT.context, "monitor", "trace", { add = { api = args.trace, request = "vverbose", event = "push_after" }}) + elseif type(args.trace) == "table" then + for _,v in pairs(args.trace) do + if type(v) == "string" then + AFB:servsync(_AFT.context, "monitor", "trace", { add = { api = v, request = "vverbose", event = "push_after" }}) + end + end + end if args.files and type(args.files) == 'table' then for _,f in pairs(args.files) do dofile('var/'..f) @@ -62,7 +62,7 @@ static AFB_ApiVerbs CtrlApiVerbs[] = { static int CtrlLoadStaticVerbs(afb_dynapi *apiHandle, AFB_ApiVerbs *verbs) { int errcount = 0; - for (int idx = 0; verbs[idx].verb; idx++) { + for(int idx = 0; verbs[idx].verb; idx++) { errcount += afb_dynapi_add_verb( apiHandle, CtrlApiVerbs[idx].verb, NULL, CtrlApiVerbs[idx].callback, (void *)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); @@ -91,7 +91,7 @@ static int CtrlLoadOneApi(void *cbdata, AFB_ApiT apiHandle) { // add static controls verbs int err = CtrlLoadStaticVerbs(apiHandle, CtrlApiVerbs); - if (err) { + if(err) { AFB_ApiError(apiHandle, "CtrlLoadSection fail to register static V2 verbs"); return ERROR; } @@ -132,21 +132,21 @@ int afbBindingEntry(afb_dynapi *apiHandle) { } configPath = CtlConfigSearch(apiHandle, dirList, prefix); - if (!configPath) { + if(!configPath) { AFB_ApiError(apiHandle, "CtlPreInit: No %s* config found in %s ", GetBinderName(), dirList); return ERROR; } // load config file and create API ctrlConfig = CtlLoadMetaDataUsingPrefix(apiHandle, configPath, prefix); - if (!ctrlConfig) { + if(!ctrlConfig) { AFB_ApiError(apiHandle, "CtrlBindingDyn No valid control config file in:\n-- %s", configPath); return ERROR; } - if (!ctrlConfig->api) { + if(!ctrlConfig->api) { AFB_ApiError(apiHandle, "CtrlBindingDyn API Missing from metadata in:\n-- %s", configPath); diff --git a/src/mapis.c b/src/mapis.c index 145c01f..64543e5 100644 --- a/src/mapis.c +++ b/src/mapis.c @@ -16,8 +16,9 @@ * limitations under the License. */ +#include <string.h> #include <mapis.h> -#include <ctl-plugin.h> +#include <ctl-config.h> struct mapisHandleT { AFB_ApiT mainApiHandle; @@ -27,11 +28,11 @@ struct mapisHandleT { json_object *eventsJ; }; -static int LoadOneMapi(void *data, AFB_ApiT apiHandle) -{ - int savedCount = 0, count = 0; +static int LoadOneMapi(void *data, AFB_ApiT apiHandle) { + int savedCount = 0, count = 0, idx = 0; CtlActionT *savedActions = NULL, *newActions = NULL; struct mapisHandleT *mapisHandle = (struct mapisHandleT*)data; + CtlConfigT *ctrlConfig = afb_dynapi_get_userdata(mapisHandle->mainApiHandle); if(PluginConfig(apiHandle, mapisHandle->section, mapisHandle->mapiJ)) { AFB_ApiError(apiHandle, "Problem loading the plugin as an API for %s, see log message above", json_object_get_string(mapisHandle->mapiJ)); @@ -45,7 +46,12 @@ static int LoadOneMapi(void *data, AFB_ApiT apiHandle) } // Add actions to the section to be able to respond to defined events. - savedActions = mapisHandle->section->actions; + for(idx = 0; ctrlConfig->sections[idx].key != NULL; ++idx) { + if(! strcasecmp(ctrlConfig->sections[idx].key, "events")) { + savedActions = ctrlConfig->sections[idx].actions; + break; + } + } newActions = ActionConfig(apiHandle, mapisHandle->eventsJ, 0); if(savedActions) { @@ -71,10 +77,10 @@ static int LoadOneMapi(void *data, AFB_ApiT apiHandle) while(newActions[savedCount].uid != NULL && count <= total) { mergedActions[count] = newActions[savedCount]; count++; - savedActions++; + savedCount++; } - mapisHandle->section->actions = mergedActions; + ctrlConfig->sections[idx].actions = mergedActions; // declare an event event manager for this API; afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent); @@ -96,8 +102,8 @@ static void OneMapiConfig(void *data, json_object *mapiJ) { "lua", NULL, "verbs", &mapisHandle->verbsJ, "events", &mapisHandle->eventsJ)) { - AFB_ApiError(mapisHandle->mainApiHandle, "Wrong mapis specification, missing uid|[info]|[spath]|libs|[lua]|verbs|[events] for %s", json_object_get_string(mapiJ)); - return; + AFB_ApiError(mapisHandle->mainApiHandle, "Wrong mapis specification, missing uid|[info]|[spath]|libs|[lua]|verbs|[events] for %s", json_object_get_string(mapiJ)); + return; } json_object_get(mapisHandle->verbsJ); |